signxml
signxml copied to clipboard
Can not run the synopsis example: Missing child element(s).
An error appears when attempting to generate the keys according to the documentation.
Can't open "D:\bld\openssl_split_1710792702164\_h_env\Library/openssl.cnf" for reading, No such file or directory
300B0000:error:80000003:system library:BIO_new_file:No such process:crypto\bio\bss_file.c:67:calling fopen(D:\bld\openssl_split_1710792702164\_h_env\Library/openssl.cnf, r)
300B0000:error:10000080:BIO routines:BIO_new_file:no such file:crypto\bio\bss_file.c:75:
However, this is not the preferred method to create the keys as I am using the cryptography library for the task. In the following I run the standard code from cryptography library to generate the key and certificate, then attempting to sign them according to the synopsis example.
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from lxml import etree
from signxml import XMLSigner, XMLVerifier
# Generate our key
key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
# Write our key to disk for safe keeping
with open("privkey.pem", "wb") as f:
f.write(key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
))
# Generate a CSR
csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
# Provide various details about who we are.
x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "California"),
x509.NameAttribute(NameOID.LOCALITY_NAME, "San Francisco"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "My Company"),
x509.NameAttribute(NameOID.COMMON_NAME, "mysite.com"),
])).add_extension(
x509.SubjectAlternativeName([
# Describe what sites we want this certificate for.
x509.DNSName("mysite.com"),
x509.DNSName("www.mysite.com"),
x509.DNSName("subdomain.mysite.com"),
]),
critical=True,
# Sign the CSR with our private key.
).sign(key, hashes.SHA256())
# Write our CSR out to disk.
with open("cert.pem", "wb") as f:
f.write(csr.public_bytes(serialization.Encoding.PEM))
data_to_sign = "<Test/>"
cert = open("cert.pem").read()
key = open("privkey.pem").read()
cert = cert[36:len(cert)-35]
root = etree.fromstring(data_to_sign)
signed_root = XMLSigner().sign(root, key=key, cert=cert)
verified_data = XMLVerifier().verify(signed_root).signed_xml
I receive the following error.
DocumentInvalid: Element '{http://www.w3.org/2000/09/xmldsig#}X509Data':
Missing child element(s). Expected is one of (
{http://www.w3.org/2000/09/xmldsig#}X509IssuerSerial,
{http://www.w3.org/2000/09/xmldsig#}X509SKI,
{http://www.w3.org/2000/09/xmldsig#}X509SubjectName,
{http://www.w3.org/2000/09/xmldsig#}X509Certificate,
{http://www.w3.org/2000/09/xmldsig#}X509CRL,
##other{http://www.w3.org/2000/09/xmldsig#}* )., line 1
It looks like you are not running the synopsis but something else that you wrote. The specific reason this is failing is that you're passing a CSR stripped of its PEM header instead of a certificate. Pass a full PEM certificate, including the header.
You have however uncovered a corner case where SignXML produces an invalid signature when an invalid certificate is passed along with a valid key. I've added an error message for this case; it will be released with the next release.
It looks like you are not running the synopsis but something else that you wrote. The specific reason this is failing is that you're passing a CSR stripped of its PEM header instead of a certificate. Pass a full PEM certificate, including the header.
You have however uncovered a corner case where SignXML produces an invalid signature when an invalid certificate is passed along with a valid key. I've added an error message for this case; it will be released with the next release.
The error still appears when running the synopsis example without modifying the headers of the CSR, if the part -----BEGIN CERTIFICATE-----
is the header.
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from lxml import etree
from signxml import XMLSigner, XMLVerifier
# Generate our key
key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
# Write our key to disk for safe keeping
with open("privkey.pem", "wb") as f:
f.write(key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
))
# Generate a CSR
csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
# Provide various details about who we are.
x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "California"),
x509.NameAttribute(NameOID.LOCALITY_NAME, "San Francisco"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "My Company"),
x509.NameAttribute(NameOID.COMMON_NAME, "mysite.com"),
])).add_extension(
x509.SubjectAlternativeName([
# Describe what sites we want this certificate for.
x509.DNSName("mysite.com"),
x509.DNSName("www.mysite.com"),
x509.DNSName("subdomain.mysite.com"),
]),
critical=True,
# Sign the CSR with our private key.
).sign(key, hashes.SHA256())
# Write our CSR out to disk.
with open("cert.pem", "wb") as f:
f.write(csr.public_bytes(serialization.Encoding.PEM))
# Synopsis example:
data_to_sign = "<Test/>"
cert = open("cert.pem").read()
key = open("privkey.pem").read()
root = etree.fromstring(data_to_sign)
signed_root = XMLSigner().sign(root, key=key, cert=cert)
verified_data = XMLVerifier().verify(signed_root).signed_xml
Relating to child elements, I would like the certificate to be the last child element of the root instead of being the first, some formats require this. Is this possible?
You are still passing a CSR as the cert
keyword argument, not a certificate. A CSR is not a certificate. The signer ends up ignoring it.
Regarding your other question, I'm not sure what you mean exactly but if you're trying to control the position of nodes like X509Data within the Signature parent node, no, that's not directly supported (but you can subclass and override this behavior).
I'm going to close this issue since the error message legibility issue is fixed in the development branch and nothing else indicates a bug within SignXML.