A x509 certificate, and in particular the latest version 3, is the standard for authentication in Public Key Infrastructures (PKIs). Think about Google proving that it's Google before you can communicate with it.
This x509 standard is a tad complicated. Trying to parse such a format usually end up in the creation of a lot of different vulnerabilities. I won't talk about that here. I will talk about their other complicated side: using them correctly!
Here's a list of pitfalls in the creation of such certificates, but also in the validation and use of them when encountering them in the wild wild web (or in your favorite infrastructure).
explanation: keyUsage
is a field inside a x509 v3 certificate that limits the power of the public key inside the certificate. Can you only use it to sign? Or can it be used as part of a key Exchange as well (ECDH)? etc... For example on the web, the keyCertSign
bit must be set for CA certificates.
relevant RFC: Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile
relevant ASN.1:
KeyUsage ::= BIT STRING {
digitalSignature (0),
nonRepudiation (1),
keyEncipherment (2),
dataEncipherment (3),
keyAgreement (4),
keyCertSign (5),
cRLSign (6),
encipherOnly (7),
decipherOnly (8) }
seen in attacks:
best practice: Specify the KeyUsage
at creation, verify the keyUsage
when encountering the certificate. keyCertSign
should be used if the certificate is a CA, keyAgreement
should be used if a key exchange can be done with the public key of the certificate.
see more: Extended Key Usage
explanation: a certificate is only to be valid in a specific interval of time. This interval is specified by the notBefore
and notAfter
fields.
relevant RFC: Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile
relevant ASN.1:
Validity ::= SEQUENCE {
notBefore Time,
notAfter Time }
best practice: Reject certificates that have a notBefore
date anterior to the current date, or that have a notAfter
date posterior to the current date. In other words [ not valid | notBefore date | valid | notAfter date | not valid ]
. The timezone should not matter since you should not rotate your certificate at the last minute, but rather days or month before the end of your previous certificate.
explanation: x509 certificate is an evolving standard, exactly like TLS, through extensions. To preserve backward compatibility, not being able to parse an extension is often considered OK, that is unless the extension is considered critical (important).
relevant RFC: https://tools.ietf.org/html/rfc5280#section-4.2
relevant ASN.1:
Extension ::= SEQUENCE {
extnID OBJECT IDENTIFIER,
critical BOOLEAN DEFAULT FALSE,
extnValue OCTET STRING
-- contains the DER encoding of an ASN.1 value
-- corresponding to the extension type identified
-- by extnID
}
best practice: at creation mark every important extensions as critical
. At verification make sure to process every critical
extensions. If a critical
extension is not recognized, the certificate MUST
be rejected.
explanation: Knowing who you're talking to is really important. A x509 certificate is tied to a specific domain/organization/email/... if you don't check who it is tied to, you are prone to impersonation attacks. Because of reasons, these things can be seen in different places in the subject
field or in the Subject Alternative Name
(SAN) extension. For TLS, things are standardized differently and it will always need to be checked in the latter field.
This is one of the trickier issues in this list as hostname validation is protocol specific (as you can see TLS does things differently) and left to the application. To quote OpenSSL:
One common mistake made by users of OpenSSL is to assume that OpenSSL will validate the hostname in the server's certificate
relevant RFC:
relevant ASN.1:
TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
seen in attacks:
-
The most dangerous code in the world: validating SSL certificates in non-browser software
-
Often, implementations will just check if the
subject Name
contains the stringmywebsite.com
, or will use a vulnerable regex that either acceptmywebsite.com.evil.com
or evil subdomains. Check moxie's presentation (null bytes) to hear more about hostname validation failures.
best practice: During creation, check for the subject
as well as the subject alternative name
fields. During verification, check that the leaf certificate matches the domain/person you are talking to. If TLS is the protocol being used, check that in the subject alternative name
field, only one level of wildcard is allowed and it must be on the leftmost position (*.domain.com
is allowed, sub.*.domain.com
is forbidden). Consult RFC 6125 for more information.
see more:
explanation: the BasicConstraints
extension dictates if a certificate is a CA (can sign others) or not. If it is, it also says how many CAs can follow it before a leaf certificate.
relevant RFC: https://tools.ietf.org/html/rfc5280#section-4.2.1.9
relevant ASN.1:
id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 }
BasicConstraints ::= SEQUENCE {
cA BOOLEAN DEFAULT FALSE,
pathLenConstraint INTEGER (0..MAX) OPTIONAL }
seen in attacks: Moxie - New Tricks For Defeating SSL In Practice (2009). Basically all older browsers would just assume a missing basic constraint field meant that the certificate was a CA. And of course CA would just sign certificates without caring about this field.
best practice: set this field to the relevant value when creating a certificate. When validating a certificate chain, make sure that the pathLen
is valid and the cA
field is set to TRUE
for each non-leaf certificate.
explanation: the NameConstraints
extension contains a set of limitations for CA certificates, on what kind of certificates can follow them in the chain. For examples name constraints can limit the TLDs or the IPs that intermediate CAs will be able to sign certificates for.
relevant RFC: https://tools.ietf.org/html/rfc5280#section-4.2.1.10
relevant ASN.1:
id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
NameConstraints ::= SEQUENCE {
permittedSubtrees [0] GeneralSubtrees OPTIONAL,
excludedSubtrees [1] GeneralSubtrees OPTIONAL }
GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
GeneralSubtree ::= SEQUENCE {
base GeneralName,
minimum [0] BaseDistance DEFAULT 0,
maximum [1] BaseDistance OPTIONAL }
BaseDistance ::= INTEGER (0..MAX)
seen in attacks:
- The ANSSI's CA was used to MITM arbitrary sites
- Fake Google certificates were signed by Diginotar and India CCA
best practice: when creating a CA certificate, be aware of the constraints chained certificates should have and document it in the NameConstraints
field. When verifying a CA certificate, verify that each certificate in the certificate chain is valid according to the requirements of upper certificates.
see more: https://wiki.mozilla.org/CA:NameConstraints
- Certificate Chain Validation
- Certificate Revocation
- Cryptographic Algorithms
Thanks to Chris Palmer, Vincent Lynch and Jeff Jarmoc