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

Feature Suggestion - OpenSSL formatting compatibility #12156

Open
jvanasco opened this issue Dec 17, 2024 · 4 comments
Open

Feature Suggestion - OpenSSL formatting compatibility #12156

jvanasco opened this issue Dec 17, 2024 · 4 comments
Labels
Stale waiting-on-reporter Issue is waiting on a reply from the reporter. It will be automatically cloesd if there is no reply.

Comments

@jvanasco
Copy link

I'm working on porting some internal stuff from pyOpenSSL to Cryptography, and helping some others with PRs on related efforts. Perhaps I am missing something obvious...

I've run into a slight "annoyance" with the x509.Certificate issuer and subject. I'll use the ISRG X1 Cross-Signed Root as an example ( https://letsencrypt.org/certs/isrg-root-x1-cross-signed.pem ) This is no longer used, but it shows my test case.

The relevant output of openssl x509 -in cert.pem -text -noout:

Issuer: O = Digital Signature Trust Co., CN = DST Root CA X3
Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1

And using the legacy project:

from OpenSSL import crypto
cert_legacy = crypto.load_certificate(crypto.FILETYPE_PEM, cert_pem.encode())
_issuer = cert_legacy.get_issuer().get_components()
print(_issuer)
_subject = cert_legacy.get_subject().get_components()
print(_subject)

The output is:

[(b'O', b'Digital Signature Trust Co.'), (b'CN', b'DST Root CA X3')]
[(b'C', b'US'), (b'O', b'Internet Security Research Group'), (b'CN', b'ISRG Root X1')]

Loading the same cert into cryptography:

cert = cryptography.x509.load_pem_x509_certificate(cert_pem.encode())
print(cert.issuer)
print(cert.subject)

We see:

<Name(O=Digital Signature Trust Co.,CN=DST Root CA X3)>
<Name(C=US,O=Internet Security Research Group,CN=ISRG Root X1)>

All looks well. Accessing the existing string convenience methods though:

print(cert.issuer.rfc4514_string())
print(cert.subject.rfc4514_string())

We get:

CN=DST Root CA X3,O=Digital Signature Trust Co.
CN=ISRG Root X1,O=Internet Security Research Group,C=US

The order of fields is reversed.

We can, of course, generate the expected output easily as strings:

",".join([attr.rfc4514_string() for attr in cert.issuer])
",".join([attr.rfc4514_string() for attr in cert.subject])

And as tuples, like get_components would return:

[(attr.rfc4514_attribute_name, attr.value) for attr in cert.issuer]
[(attr.rfc4514_attribute_name, attr.value) for attr in cert.subject]

This just seems like a bit of extra work to me, and there should be some convenience methods for better compatibility here.

While this doesn't make much of a difference in library code, this is causing a bit of extra work on porting stuff over - especially with unit tests.

It would be nice if there were a openssl_compat_string( function, and perhaps openssl_compat_components(; IMHO that would make switching a bit easier for others.

Possibly Related Tickets:

@alex
Copy link
Member

alex commented Dec 17, 2024

This is probably an unsatisfying answer, but pyOpenSSL (and by extension, whatever OpenSSL API we're using) is simply wrong here (or at least, not attempting to do teh right thing), as https://datatracker.ietf.org/doc/html/rfc4514#section-2.1 describes, teh elements must be reversed.

I don't think there's a lot of value in providing an API to match pyOpenSSL's (wrong) behavior here -- given that users can write a function to handle it when their application requires.

@alex alex added the waiting-on-reporter Issue is waiting on a reply from the reporter. It will be automatically cloesd if there is no reply. label Dec 17, 2024
@reaperhulk
Copy link
Member

rfc4514_string reverses the order of encoding deliberately (see: RFC 4514 Section 2.1).

Is there a use case you have for some other string repr? Generally we assume users will either perform operations using the Name object or will fetch the components they need. String representations like OpenSSL's textual output are ambiguous in ways that can be dangerous if people assume they're canonical and can be parsed rather than viewed as strictly presentational, so replicating their choices isn't a design goal.

@jvanasco
Copy link
Author

This is probably an unsatisfying answer... given that users can write a function to handle it when their application requires.

Not unsatisfying at all - I've already written the functions to handle it. I just hoped to make migration easier for others.

Is there a use case you have for some other string repr?

The only use-case is Unit Tests when porting from pyOpenSSL to Cryptography. No library code that I've encountered in my projects, or others, is materially affected - it's just the test suites that have been a pain.

OpenSSL has historically not been consistent at all with presentation; AFAIK the order of elements has been consistent but whitespace varies across versions. Because of that, I've typically used the get_components() functions, which returns tuples.

Again, no big deal. The difference doesn't really affect library code AFAIK. The only time I - and most others that I've seen - seem to utilize this representation is with Unit Tests and Logging.

Copy link

This issue has been waiting for a reporter response for 3 days. It will be auto-closed if no activity occurs in the next 5 days.

@github-actions github-actions bot added the Stale label Dec 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Stale waiting-on-reporter Issue is waiting on a reply from the reporter. It will be automatically cloesd if there is no reply.
Development

No branches or pull requests

3 participants