-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Add certificate signature verification #2460
Add certificate signature verification #2460
Conversation
So this is definitely still WIP and it shouldn't pass the tests. I'm primarily interested in feedback on the I also still have some tests to finish up, but I wanted to push something out before the weekend. Open questions: does |
Jenkins, ok to test. |
before we go too much farther, we need to think about the full set of options and what not we might care about. |
Agreed. For example, this current code appears to assume validate_certificate_chain will present certs in a prebuilt chain order? I believe we discussed that briefly previously, but if that's the case we need something that can, given a bundle of certs, find a valid chain. A validator is of extremely limited utility if it can't do this resolution. I'd also like the API to have affordances for passing CRL/OCSP as part of the validation process. To avoid making the PR enormous it doesn't have to be implemented now, but nailing down a proposed interface is important. |
@reaperhulk Shuffling a set of certificates to form a valid chain is definitely reasonable. I'll add that in. I'm going to work under the assumption that the certificate set provided to the validator should form one valid chain, not multiple chains. There shouldn't be any extraneous certificates either; all should be a part of the chain. For CRL/OSCP, I'll start thinking about how that'll look. I agree that that should wait for a second round of patches. |
I understand why you'd rather not expose any properties you don't have to. However, I've worked with x509 certificate code at different times over the past 20 years, and I was expecting to find something like signature and tbs_certificate_bytes already there. In the end, I would be fine with something like a Certificate.verifySignature( self, issuerCertificate ) method as long as it did all the right things, looked up the sig algorithm, pulled out the parameters, used the right VerificationContext for the algorithm, etc. I would expect verifySignature to also tell me, if it failed, why it failed. Were the parameters incompatible with the signatureAlgorithm specified in the Certificate? Was the signatureAlgorithm not supported by the backend? I'm guessing these would be exceptions raised by the underlying verification context anyway. Also, I'm writing a certificate path validation library of my own, and I really want to get on with it, so if the two properties work as advertised I'm all for a merge. Just my $.02 :) |
I don't need this functionality at this time, but I believe that if someone wants to write generalized signature verification code that they will also need access to the signatureAlgorithm (ASN.1 type AlgorithmIdentifier) from the outer certificate or the inner tbsCertificate in order to extract the OID of the signature algorithm + hash algorithm (for example sha256WithRSAEncryption), and the algorithm parameters used when the public key was signed. Certificate ::= SEQUENCE { TBSCertificate ::= SEQUENCE { AlgorithmIdentifier ::= SEQUENCE { |
@rowland-smith This information should be available from the |
After looking at the code, as far as I can tell signature_hash_algorithm only returns a cryptography.hazmat.primitives.hashes.Hash object, and that interface doesn't expose either the signature-algorithm itself (like sha254WithRSAEncryption, etc.) nor the parameters, if there were any, used in creating the signature. I was able to access the AlgorithmIdentifier.oid and parameters in SubjectPublicKeyInfo using pyasn1:
|
The public key of the certificate provides the type and the signature hash algorithm provides the hash. For RSA all certificates are signed using PKCS1v1.5 padding and for DSA/ECDSA no padding is required. You can see examples of certificate signature checks (on self-signed certificates) by looking at the test_tbs_certificate_bytes methods in test_x509.py Does this miss anything? If so we definitely need to resolve that :) |
@reaperhulk Yep, that's how I'm doing it here. I just forgot to bring up the key verifier piece when @rowland-smith asked his question. |
Agreed, you can determine the signature algorithm type (RSA/DSA/ECDSA) from the python class of the key. I was thinking about situations where someone wants to be very strict in their validation and must check the OID from the outer Certificate.signatureAlgorithm.type or the TBSCertificate.signature.type. That’s why Certificate.signatureAlgorithm is in the outer body. Also, if actual signature algorithm parameters (Certificate.signatureAlgorithm.parameters | TBSCertificate.signature.parameters) are present they have to currently be extracted from the SubjectPublicKeyInfo (TBSCertificate.signature.parameters) like so: First use ‘cryptography’...spkiEncoding = subjectCertificate.public_key().public_bytes( Encoding.DER, PublicFormat.SubjectPublicKeyInfo ) Then use ‘pyasn1’...subjectPublicKeyInfo = decoder.decode( spkiEncoding, SubjectPublicKeyInfo() )I think in PKIX parameters are very rare, usually absent or ASN.1 NULL, but I think there is at least one valid signature algorithm that uses parameters (RSA PSS)(?). Certificate ::= SEQUENCE { TBSCertificate ::= SEQUENCE {
|
Ok, I'm still working on a bunch of tests but the I added @reaperhulk For CRL/OCSP handling, the Documentation will need to be added for all of this as well. It's on my TODO list. Question: Is there a hash algorithm available that will support elliptic curves? ECDSA is the only signature algorithm supported for OpenSSL but I'm not entirely sure how to use it in the context of signature verification. The OpenSSL backend routine for building x509 certificates requires a |
I’m pretty sure I had ECDSA/sha256 working last week. And I believe that it is commonly used, but I would have to find some references before I could say that was definitive.
|
@rowland-smith I figure there's some way to do it. I tried just passing |
I’ll be glad to try it myself tomorrow. If you figure it out before then let me know. I’ll reply here once I do the test.
|
The test code previously referenced shows how to do a signature verification on a self-signed ECDSA certificate. |
@reaperhulk Well I'm an idiot. Thanks for that! |
Current coverage is
|
Ok, I've redesigned the validation API and am splitting this patch in two. This patch now just contains a The next patch will contain all of the certificate chain code that was in the original patch, represented by a |
Still working on docs. I pulled the CHANGELOG update to make sure everything else is working. @alex @reaperhulk If you have a sec, could you look at the errors Jenkins is throwing? The CentOS test runs break when I check for OpenSSL elliptic curve support (when selectively skipping keys that different OpenSSL versions don't support). What other context/version-specific checks should I do to prevent these errors from triggering? Thanks in advance. |
You'll need to move the EC tests to a separate function and add the EllipticCurveBackend as a required interface. (The failure is occurring because some OpenSSLs don't have EC at all, so you can't check if it supports a specific curve because the functions to check are themselves missing). |
@reaperhulk - thanks for the suggestion. I split them out, so we'll see if that fixes it. |
Take a look in test_ec.py to see what else you need. There's a |
Is this ready for review now? If so, is |
@reaperhulk - Aside from API documentation, this pull request is ready for review. Given that I modeled this after the The A second pull request is incoming that will add a |
@reaperhulk - The subject/issuer name check got pulled out when I split the pull requests. I just added it back in. Now |
Could this be enhanced to also support verification of CRLs? #2489 might help with that. |
Very useful PR, I hope it will be included in next release. But I've faced with problem. I've tried to validate some certificates issued by built-in CAs (Shipped with There are major CAs Maybe script should check |
@reaperhulk I noticed 1.3 was released last week and I am curious why the milestone tag got removed from this. Is there anything you need from me to get this finally reviewed and merged in? |
@PeterHamilton it got removed from the milestone because we didn't have the bandwidth to get it landed in the time frame we wanted for 1.3. Adding to the fourteenth milestone now (sorry about that). |
@reaperhulk Not a problem. I just wanted to make sure I hadn't dropped the ball. It'd been a while since I'd checked on the patch. I'll make sure I'm available for questions or rewrites going forward. What's your timeline for 1.4? |
Hey, can we merge this? |
The lack of action on this PR is embarrassing and I apologize. Unfortunately we're not going to review it for the 1.5 release either, but I will spend some time in the next few days thinking very hard about this one. |
Any new insights, @reaperhulk? 😄 |
Sorry @reaperhulk, I partially checked out on this one as well. If you still think the feature has a place in |
ExtensionOID.KEY_USAGE).value | ||
|
||
if not basic_constraints.ca: | ||
raise InvalidSigningCertificate( |
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 happens if the certificate has no basic constraint or key usage extensions? These v3 extensions are critical but not mandatory extensions. A cert w/o a BC, KU or EKU can be used as CA cert.
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.
While not mandatory in the general case, these extensions are required for conforming CAs. The following quotes are taken from RFC 5280 on X.509 PKI:
https://www.ietf.org/rfc/rfc5280.txt
Regarding the Basic Constraints extension, see Section 4.2.1.9, bottom of page 38:
Conforming CAs MUST include this extension in all CA certificates that contain public keys used to validate digital signatures on certificates and MUST mark the extension as critical in such certificates. This extension MAY appear as a critical or non-critical extension in CA certificates that contain public keys used exclusively for purposes other than validating digital signatures on certificates. Such CA certificates include ones that contain public keys used exclusively for validating digital signatures on CRLs and ones that contain key management public keys used with certificate enrollment protocols. This extension MAY appear as a critical or non-critical extension in end entity certificates.
Regarding the Key Usage extension, see Section 4.2.1.3, top of page 29:
Conforming CAs MUST include this extension in certificates that contain public keys that are used to validate digital signatures on other public key certificates or CRLs. When present, conforming CAs SHOULD mark this extension as critical.
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.
@PeterHamilton , see #2460 (comment)
RFC 5280 is to new for some root CA widely used nowadays. You can't rely on existing of this extensions.
|
||
|
||
def _is_issuing_certificate(issuing_certificate, issued_certificate): | ||
return (issuing_certificate.subject == issued_certificate.issuer) |
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.
This check, in addition to _can_sign_certificates
, should incorporate a check to detect if the issuing_certificate
is name constrained in any way, and if so, validate that the issued_certificate
's subject / subjectAltName(s) match the issuing_certificate
's set of name constraints.
Where are we on this? |
@ofek I'm not actively working on this. I'm fine with anyone picking this up and working on it going forward. |
Is there still any plan to support verification of certificates? This seems like a often-used feature that is currently missing. I'd hate to have to call |
There is a desire for it, but it hasn't reached the top of my todo list and it's definitely something that will require extensive conformance and validation tests. If someone else is interested in tackling it we welcome discussion. Aggregating resources that specify precisely how validation should work as well as test vectors would be helpful for anyone interested in pursuing this. |
This is being actively worked on by @alex but the PR isn't ready yet. I'm going to go ahead and close this, but hopefully we'll have something in time for cryptography 2.1. |
This change adds a CertificateValidator to the x509 API. The validator adds methods to validate a pair of certificates and an entire chain of certificates, given a set of certificate trust anchors is provided. A test suite for the CertificateValidator is included.