-
Notifications
You must be signed in to change notification settings - Fork 1.7k
WIP: Add boolean Certificate.is_issued_by(issuer) #5116
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
Conversation
b738297 to
7290d50
Compare
| '{} verification is not implemented' | ||
| .format(pkey.__class__) | ||
| ) | ||
| except InvalidSignature: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the point of this try-except?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! This slipped through the self-review. I'm removing the redundant code and force-pushing the PR branch (for reference, leaving the original PR in branch is_issued_by-v1 ).
7290d50 to
dd9c4a7
Compare
|
Thanks. One more issue - the method name Especially as the Thus I would prefer I see from other branch that you have So my suggestion: lets have Certificate class only have low-level Alternative: lets not add anything to Cerfificate class, which stays as plain container with no logic and put all implementation details into CertStore class. The question behind this is - can |
Hm, but a certificate issued by a CA must have a valid signature. This is different from any other checks which are subjects to policy (such as presence and value of any X.509v3 extensions or particular algorithms used). I'd say that if we check only for
Thanks for the pointer! Will do this change. |
Let's discuss this question in its own PR 🙂 |
dd9c4a7 to
f1d9666
Compare
|
Branch force-pushed with suggestion by @markokr : along with the initially implemented Previous branch point saved as is_issued_by-v2 for reference. |
f1d9666 to
3e9c02d
Compare
|
An "unintended" force-push: forgot to add the corresponding abstract method of the |
3e9c02d to
085382f
Compare
|
Closing was a mistake, re-opening |
98e72e4 to
1779963
Compare
|
Now we have two PRs adding the same functionality: this one and #5367 . The latter adds one more OpenSSL hook, this PR is Python-only. #5367 follows behavior of
In this PR, we:
I had explained earlier that I think that signature verification is what this method is about. My take is that checks for If deemed reasonable, these checks may be added under parameters with reasonable defaults, such as for example |
| if issuer_candidate.subject != self.issuer: | ||
| raise x509.base.InvalidIssuer( | ||
| expected=self.issuer, received=issuer_candidate.subject) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that the check is sufficient. Other PKIX are typically more rigorous and check KU, SKID, and AKID. NSS seems to be more forgiving than OpenSSL. Ryan mentioned recently that macOS is even more strict and Windows even prioritizes AKID/SKID matching over issuer/subject matching. It's unfortunate that even something 'trivial' like "is cert issued by another cert" is full of landmines...
IMHO you should also check for presence of AKID, SKID, and KU, then verify properties like akid.keyid == issuer.skid, akid.serial == issuer.serial, akid.dirname == issuer.issuer, issuer.ku has cert signing flag, and possibly some proxy cert shenanigans. An AKID/SKID mismatch automatically implies cert mismatch.
If I were you I would just use X509_check_issued() followed by X509_verify(). This gives you OpenSSL semantics, which is what most people expect anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tiran I have given in the comment above reasoning why I think that the mentioned checks are in fact policy checks, and there is more than one way to accept them. Say, CA certificate has no AKID, but the issued one has SKID. Is this OK?
If I were you I would just use
X509_check_issued()followed byX509_verify(). This gives you OpenSSL semantics, which is what most people expect anyway.
This would be definitely the way to go if we were building (yet another) OpenSSL wrapper. But if the project's goal is to be your "cryptographic standard library" (and it allows, at least in theory, for other cryptographic backends), then IMO providing the "correct" APIs is a higher priority than making them mimicking OpenSSL. Of course it's up to project maintainers to decide on what is "correct".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The x509 layer is outside the hazmat area. Any API outside the hazmat layer should be safe, sane, and free of pitfalls. Your implementation of is_issued_by() would be a pitfall for me -- and I know a lot about X.509 and PKIX. Even my proposal X509_check_issued() + X509_verify() has pitfalls because it doesn't validate EKU and BC extensions.
IMHO it would be better to add low-level functions for X.509 trust chain processing to the hazmat layer.
1779963 to
7a7585b
Compare
|
If |
7a7585b to
748983f
Compare
|
I was in the same situation, want to have a "simple" way of checking, "does this certificate" belong to a CA. But X509 validity depends on so many things, like:
So even for my simple use case that I was chasing of only wanting a negative "this cert looks wrong, please provide a valid cert for config", you can end getting it wrong very easily. Even a simple assumption like "if signature matches but signer id is different" fails with things like ":CA1(key1, identifier1) => CA2(key2, identifier2) => CA3(key1,identifier3) => cert(sign by CA identifier3) Why am I showing the cert chain example? Because issued_by is likely used in check validity of a certificate and that is very easy to get wrong because it is even more then only the 'can of worms' issued_by. So getting somthing like this really right, is very hard. |
49ec0b2 to
979423a
Compare
@reaperhulk I agree with your concern. To draw a clearer boundary between policies and technology, I've split pure cryptographic operations into #5950 . Next, we complete this PR with some default policy checks and possibility to add custom ones. Then it would be used for the long-awaited certificate verification in #5093. |
@schwabe I fully agree that the user of the library typically wants just one "Yes/No" answer to their question "Is this a good certificate of my
I do not see an approach which would be simpler than this. If there is such, I'd be happy to know! |
9a1a2fb to
b509804
Compare
b509804 to
efb697a
Compare
7ecbba4 to
26c1cf1
Compare
26c1cf1 to
0e108d0
Compare
c479f16 to
7456d8d
Compare
7456d8d to
f33c93d
Compare
This method is a prerequisite for Certificate.is_issued_by(). It only checks the validity of the cryptographic signature.
Tests missing, documentation incomplete.
1c5b74d to
44e3a30
Compare

Two booleans
leaf_cert.is_issued_by(ca_cert)andca_cert.is_issuer_of(leaf_cert), mirroring each other, are implemented.The functions return True if the "issuer" field of
leaf_certis the same as the "subject" ofca_cert, and the signature onleaf_certvalidates with the public key ofca_cert. If any of these conditions fails, appropriate exception is raised.Corresponding test vectors are added.
This function will be used in #5093.