Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can not run the synopsis example: Missing child element(s). #255

Open
MathMan112 opened this issue Apr 23, 2024 · 2 comments
Open

Can not run the synopsis example: Missing child element(s). #255

MathMan112 opened this issue Apr 23, 2024 · 2 comments

Comments

@MathMan112
Copy link

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

@kislyuk
Copy link
Member

kislyuk commented Apr 24, 2024

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.

@MathMan112
Copy link
Author

MathMan112 commented Apr 26, 2024

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants