# minisignxml
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![CircleCI](https://circleci.com/gh/HENNGE/minisignxml.svg?style=svg)](https://circleci.com/gh/HENNGE/minisignxml)
Python library to sign and verify XML documents.
This library, *on purpose*, only supports a limited part of the xmldsig specification. It is mainly aimed at allowing SAML documents to be signed and verified.
Supported features:
* Simple API.
* Only support enveloped signatures (`http://www.w3.org/2000/09/xmldsig#enveloped-signature`)
* Require and only support exclusive XML canonincalization without comments (`http://www.w3.org/2001/10/xml-exc-c14n#`)
* Support SHA-256 (default) and SHA-1 (for compatibility, not recommended) for signing and digest (`https://www.w3.org/2000/09/xmldsig#sha1`, `https://www.w3.org/2000/09/xmldsig#rsa-sha1`, `http://www.w3.org/2001/04/xmlenc#sha256`, `http://www.w3.org/2001/04/xmldsig-more#rsa-sha256`)
* Only support X509 certificates and RSA private keys
* Uses `lxml` for XML handling and `cryptography` for cryptography.
* Only supports a single signature, with a single reference in a document.
* Support certificate rollover by providing multiple certificates when verifying a document.
`minisignxml` performs no IO and you have to manage and load the keys/certificates yourself.
## API
### Signing
`minisignxml.sign.sign`
```python
def sign(
*,
element: Element,
private_key: RSAPrivateKey,
certificate: Certificate,
config: SigningConfig = SigningConfig.default(),
index: int = 0,
attribute: str = "ID"
) -> bytes:
```
Signs the given `lxml.etree._Element` with the given `cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey` private key, embedding the `cryptography.x509.Certificate` in the signature. Use `minisignxml.config.SigningConfig` to control the hash algorithms uses (default is SHA-256). The `index` controls at which index the signature element is appended to the element.
If the `element` passed in does not have an attribute matching `attribute`, an exception is raised. It is the callers responsibility to ensure the value of the `attribute` attribute of the `Element` is unique for the whole document.
Returns `bytes` containing the serialized XML including the signature.
#### SigningConfig
`minisignxml.config.SigningConfig` is a `dataclass` with the following fields:
* `signature_method`: A `cryptography.hazmat.primitives.hashes.HashAlgorithm` to use for the signature. Defaults to an instance of `cryptography.hazmat.primitives.hashes.SHA256`.
* `digest_method`: A `cryptography.hazmat.primitives.hashes.HashAlgorithm` to use for the content digest. Defaults to an instance of `cryptography.hazmat.primitives.hashes.SHA256`.
### Verifying
`minisignxml.verify.extract_verified_element`
```python
def extract_verified_element(
*,
xml: bytes,
certificate: Certificate,
config: VerifyConfig=VerifyConfig.default(),
attribute: str = "ID"
) -> Element:
```
Verifies that the XML document given (as bytes) is correctly signed using the private key of the `cryptography.x509.Certificate` provided.
A successful call to `extract_verified_element` does not guarantee the integrity of the whole document passed to it via the `xml` parameter. Only the sub-tree returned from the function has been verified. The caller should use the returned `lxml.etree._Element` for further processing.
Raises an exception (see `minisignxml.errors`, though other exceptions such as `ValueError`, `KeyError` or others may also be raised) if the verification failed. Otherwise returns the signed `lxml.etree._Element` (not necessarily the whole document passed to `extract_verified_element`), with the signature removed.
You can control the allowed signature and digest method by using a custom `VerifyConfig` instance. By default only SHA-256 is allowed.
`minisignxml.verify.extract_verified_element_and_certificate`
```python
def extract_verified_element_and_certificate(
*,
xml: bytes,
certificates: Collection[Certificate],
config: VerifyConfig=VerifyConfig.default(),
attribute: str = "ID"
) -> Tuple[Element, Certificate]:
```
Similar to `extract_verified_element`, but allows specifying multiple certificates to aid certificate rollover.
The certificate that was used to sign the xml will be returned with the verified element.
#### VerifyConfig
`minisignxml.config.SigningConfig` is a `dataclass` with the following fields:
* `allowed_signature_methods`: A container of `cryptography.hazmat.primitives.hashes.HashAlgorithm` types to allow for signing. Defaults to `{cryptography.hazmat.primitives.hashes.SHA256}`.
* `allowed_digest_methods`: A container of `cryptography.hazmat.primitives.hashes.HashAlgorithm` types to allow for the content digest. Defaults to `{cryptography.hazmat.primitives.hashes.SHA256}`.
Raw data
{
"_id": null,
"home_page": "https://github.com/HENNGE/minisignxml",
"name": "minisignxml",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.8",
"maintainer_email": null,
"keywords": null,
"author": "Jonas Obrist",
"author_email": "jonas.obrist@hennge.com",
"download_url": "https://files.pythonhosted.org/packages/88/f1/70fa7a930d4210558b22c6dc01df011895e589f3e7f6716f9689fa06f8ac/minisignxml-24.6.tar.gz",
"platform": null,
"description": "# minisignxml\n\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![CircleCI](https://circleci.com/gh/HENNGE/minisignxml.svg?style=svg)](https://circleci.com/gh/HENNGE/minisignxml)\n\n\nPython library to sign and verify XML documents. \n\nThis library, *on purpose*, only supports a limited part of the xmldsig specification. It is mainly aimed at allowing SAML documents to be signed and verified.\n\nSupported features:\n\n* Simple API.\n* Only support enveloped signatures (`http://www.w3.org/2000/09/xmldsig#enveloped-signature`)\n* Require and only support exclusive XML canonincalization without comments (`http://www.w3.org/2001/10/xml-exc-c14n#`)\n* Support SHA-256 (default) and SHA-1 (for compatibility, not recommended) for signing and digest (`https://www.w3.org/2000/09/xmldsig#sha1`, `https://www.w3.org/2000/09/xmldsig#rsa-sha1`, `http://www.w3.org/2001/04/xmlenc#sha256`, `http://www.w3.org/2001/04/xmldsig-more#rsa-sha256`)\n* Only support X509 certificates and RSA private keys\n* Uses `lxml` for XML handling and `cryptography` for cryptography.\n* Only supports a single signature, with a single reference in a document.\n* Support certificate rollover by providing multiple certificates when verifying a document.\n\n`minisignxml` performs no IO and you have to manage and load the keys/certificates yourself.\n\n## API\n\n### Signing\n\n`minisignxml.sign.sign`\n\n```python\ndef sign(\n *,\n element: Element,\n private_key: RSAPrivateKey,\n certificate: Certificate,\n config: SigningConfig = SigningConfig.default(),\n index: int = 0,\n attribute: str = \"ID\"\n) -> bytes:\n```\n\nSigns the given `lxml.etree._Element` with the given `cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey` private key, embedding the `cryptography.x509.Certificate` in the signature. Use `minisignxml.config.SigningConfig` to control the hash algorithms uses (default is SHA-256). The `index` controls at which index the signature element is appended to the element.\n\nIf the `element` passed in does not have an attribute matching `attribute`, an exception is raised. It is the callers responsibility to ensure the value of the `attribute` attribute of the `Element` is unique for the whole document.\n\nReturns `bytes` containing the serialized XML including the signature. \n\n#### SigningConfig\n\n`minisignxml.config.SigningConfig` is a `dataclass` with the following fields:\n\n* `signature_method`: A `cryptography.hazmat.primitives.hashes.HashAlgorithm` to use for the signature. Defaults to an instance of `cryptography.hazmat.primitives.hashes.SHA256`.\n* `digest_method`: A `cryptography.hazmat.primitives.hashes.HashAlgorithm` to use for the content digest. Defaults to an instance of `cryptography.hazmat.primitives.hashes.SHA256`.\n\n\n### Verifying\n\n`minisignxml.verify.extract_verified_element`\n\n```python\ndef extract_verified_element(\n *, \n xml: bytes, \n certificate: Certificate, \n config: VerifyConfig=VerifyConfig.default(),\n attribute: str = \"ID\"\n) -> Element:\n```\n\nVerifies that the XML document given (as bytes) is correctly signed using the private key of the `cryptography.x509.Certificate` provided. \n\nA successful call to `extract_verified_element` does not guarantee the integrity of the whole document passed to it via the `xml` parameter. Only the sub-tree returned from the function has been verified. The caller should use the returned `lxml.etree._Element` for further processing.\n\nRaises an exception (see `minisignxml.errors`, though other exceptions such as `ValueError`, `KeyError` or others may also be raised) if the verification failed. Otherwise returns the signed `lxml.etree._Element` (not necessarily the whole document passed to `extract_verified_element`), with the signature removed.\n\nYou can control the allowed signature and digest method by using a custom `VerifyConfig` instance. By default only SHA-256 is allowed.\n\n`minisignxml.verify.extract_verified_element_and_certificate`\n\n```python\ndef extract_verified_element_and_certificate(\n *, \n xml: bytes, \n certificates: Collection[Certificate], \n config: VerifyConfig=VerifyConfig.default(),\n attribute: str = \"ID\"\n) -> Tuple[Element, Certificate]:\n```\n\nSimilar to `extract_verified_element`, but allows specifying multiple certificates to aid certificate rollover.\nThe certificate that was used to sign the xml will be returned with the verified element.\n\n#### VerifyConfig\n\n`minisignxml.config.SigningConfig` is a `dataclass` with the following fields:\n\n* `allowed_signature_methods`: A container of `cryptography.hazmat.primitives.hashes.HashAlgorithm` types to allow for signing. Defaults to `{cryptography.hazmat.primitives.hashes.SHA256}`.\n* `allowed_digest_methods`: A container of `cryptography.hazmat.primitives.hashes.HashAlgorithm` types to allow for the content digest. Defaults to `{cryptography.hazmat.primitives.hashes.SHA256}`.\n\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "Minimal XML signature and verification, intended for use with SAML2",
"version": "24.6",
"project_urls": {
"Homepage": "https://github.com/HENNGE/minisignxml",
"Repository": "https://github.com/HENNGE/minisignxml"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "919f4af6969a33cc257ee6124aa13b49355b9b04d192653fe8bbed7e55a03d2a",
"md5": "76348faff2fc5b4d3e3186156b771d2d",
"sha256": "83d61745607f523783ac6c8638e2ec7a9d16f3ed178c1c4b7af9bfd02c51e944"
},
"downloads": -1,
"filename": "minisignxml-24.6-py3-none-any.whl",
"has_sig": false,
"md5_digest": "76348faff2fc5b4d3e3186156b771d2d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.8",
"size": 9464,
"upload_time": "2024-06-10T07:40:08",
"upload_time_iso_8601": "2024-06-10T07:40:08.031157Z",
"url": "https://files.pythonhosted.org/packages/91/9f/4af6969a33cc257ee6124aa13b49355b9b04d192653fe8bbed7e55a03d2a/minisignxml-24.6-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "88f170fa7a930d4210558b22c6dc01df011895e589f3e7f6716f9689fa06f8ac",
"md5": "50bf5eb5f08dbbdda7e67083b956b70c",
"sha256": "7bb2de078793cdf7b7835047b79d215eb2a7e4c948653f6ecee2d95e1674f114"
},
"downloads": -1,
"filename": "minisignxml-24.6.tar.gz",
"has_sig": false,
"md5_digest": "50bf5eb5f08dbbdda7e67083b956b70c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.8",
"size": 7955,
"upload_time": "2024-06-10T07:40:09",
"upload_time_iso_8601": "2024-06-10T07:40:09.763473Z",
"url": "https://files.pythonhosted.org/packages/88/f1/70fa7a930d4210558b22c6dc01df011895e589f3e7f6716f9689fa06f8ac/minisignxml-24.6.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-06-10 07:40:09",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "HENNGE",
"github_project": "minisignxml",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "minisignxml"
}