Index: net/cert/internal/parse_certificate.cc |
diff --git a/net/cert/internal/parse_certificate.cc b/net/cert/internal/parse_certificate.cc |
index c8b58c07606cfcdeb0c1240fc358598d87cc972d..e04adb89d48640716b0d7c1002b71bbb0a8fdf9f 100644 |
--- a/net/cert/internal/parse_certificate.cc |
+++ b/net/cert/internal/parse_certificate.cc |
@@ -28,8 +28,87 @@ WARN_UNUSED_RESULT bool ReadSequenceTLV(der::Parser* parser, der::Input* out) { |
return parser->ReadRawTLV(out) && IsSequenceTLV(*out); |
} |
+// Parses a Version according to RFC 5280: |
+// |
+// Version ::= INTEGER { v1(0), v2(1), v3(2) } |
+// |
+// No value other that v1, v2, or v3 is allowed (and if given will fail). RFC |
+// 5280 minimally requires the handling of v3 (and overwhelmingly these are the |
+// certificate versions in use today): |
+// |
+// Implementations SHOULD be prepared to accept any version certificate. |
+// At a minimum, conforming implementations MUST recognize version 3 |
+// certificates. |
+WARN_UNUSED_RESULT bool ParseVersion(const der::Input& in, |
+ CertificateVersion* version) { |
+ der::Parser parser(in); |
+ uint64_t version64; |
+ if (!parser.ReadUint64(&version64)) |
+ return false; |
+ |
+ switch (version64) { |
+ case 0: |
+ *version = CertificateVersion::V1; |
+ break; |
+ case 1: |
+ *version = CertificateVersion::V2; |
+ break; |
+ case 2: |
+ *version = CertificateVersion::V3; |
+ break; |
+ default: |
+ // Don't allow any other version identifier. |
+ return false; |
+ } |
+ |
+ // By definition the input to this function was a single INTEGER, so there |
+ // shouldn't be anything else after it. |
+ return !parser.HasMore(); |
+} |
+ |
+// Returns true if the given serial number (CertificateSerialNumber in RFC 5280) |
+// is valid: |
+// |
+// CertificateSerialNumber ::= INTEGER |
+// |
+// The input to this function is the (unverified) value octets of the INTEGER. |
+// This function will verify that: |
+// |
+// * The octets are a valid DER-encoding of an INTEGER (for instance, minimal |
+// encoding length). |
+// |
+// * No more than 20 octets are used. |
+// |
+// Note that it DOES NOT reject non-positive values (zero or negative). |
+// |
+// For reference, here is what RFC 5280 section 4.1.2.2 says: |
+// |
+// Given the uniqueness requirements above, serial numbers can be |
+// expected to contain long integers. Certificate users MUST be able to |
+// handle serialNumber values up to 20 octets. Conforming CAs MUST NOT |
+// use serialNumber values longer than 20 octets. |
+// |
+// Note: Non-conforming CAs may issue certificates with serial numbers |
+// that are negative or zero. Certificate users SHOULD be prepared to |
+// gracefully handle such certificates. |
+WARN_UNUSED_RESULT bool VerifySerialNumber(const der::Input& value) { |
+ bool unused_negative; |
+ if (!der::IsValidInteger(value, &unused_negative)) |
+ return false; |
+ |
+ // Check if the serial number is too long per RFC 5280. |
+ if (value.Length() > 20) |
+ return false; |
+ |
+ return true; |
+} |
+ |
} // namespace |
+ParsedTbsCertificate::ParsedTbsCertificate() {} |
+ |
+ParsedTbsCertificate::~ParsedTbsCertificate() {} |
+ |
bool ParseCertificate(const der::Input& certificate_tlv, |
ParsedCertificate* out) { |
der::Parser parser(certificate_tlv); |
@@ -63,4 +142,141 @@ bool ParseCertificate(const der::Input& certificate_tlv, |
return true; |
} |
+// From RFC 5280 section 4.1: |
+// |
+// TBSCertificate ::= SEQUENCE { |
+// version [0] EXPLICIT Version DEFAULT v1, |
+// serialNumber CertificateSerialNumber, |
+// signature AlgorithmIdentifier, |
+// issuer Name, |
+// validity Validity, |
+// subject Name, |
+// subjectPublicKeyInfo SubjectPublicKeyInfo, |
+// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, |
+// -- If present, version MUST be v2 or v3 |
+// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, |
+// -- If present, version MUST be v2 or v3 |
+// extensions [3] EXPLICIT Extensions OPTIONAL |
+// -- If present, version MUST be v3 |
+// } |
+bool ParseTbsCertificate(const der::Input& tbs_tlv, ParsedTbsCertificate* out) { |
+ der::Parser parser(tbs_tlv); |
+ |
+ // Certificate ::= SEQUENCE { |
+ der::Parser tbs_parser; |
+ if (!parser.ReadSequence(&tbs_parser)) |
+ return false; |
+ |
+ // version [0] EXPLICIT Version DEFAULT v1, |
+ der::Input version; |
+ bool has_version; |
+ if (!tbs_parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &version, |
+ &has_version)) { |
+ return false; |
+ } |
+ if (has_version) { |
+ if (!ParseVersion(version, &out->version)) |
+ return false; |
+ if (out->version == CertificateVersion::V1) { |
+ // The correct way to specify v1 is to omit the version field since v1 is |
+ // the DEFAULT. |
+ return false; |
+ } |
+ } else { |
+ out->version = CertificateVersion::V1; |
+ } |
+ |
+ // serialNumber CertificateSerialNumber, |
+ if (!tbs_parser.ReadTag(der::kInteger, &out->serial_number)) |
+ return false; |
+ if (!VerifySerialNumber(out->serial_number)) |
+ return false; |
+ |
+ // signature AlgorithmIdentifier, |
+ if (!ReadSequenceTLV(&tbs_parser, &out->signature_algorithm_tlv)) |
+ return false; |
+ |
+ // issuer Name, |
+ if (!ReadSequenceTLV(&tbs_parser, &out->issuer_tlv)) |
+ return false; |
+ |
+ // validity Validity, |
+ if (!ReadSequenceTLV(&tbs_parser, &out->validity_tlv)) |
+ return false; |
+ |
+ // subject Name, |
+ if (!ReadSequenceTLV(&tbs_parser, &out->subject_tlv)) |
+ return false; |
+ |
+ // subjectPublicKeyInfo SubjectPublicKeyInfo, |
+ if (!ReadSequenceTLV(&tbs_parser, &out->spki_tlv)) |
+ return false; |
+ |
+ // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, |
+ // -- If present, version MUST be v2 or v3 |
+ der::Input issuer_unique_id; |
+ if (!tbs_parser.ReadOptionalTag(der::ContextSpecificPrimitive(1), |
+ &issuer_unique_id, |
+ &out->has_issuer_unique_id)) { |
+ return false; |
+ } |
+ if (out->has_issuer_unique_id) { |
+ if (!der::ParseBitString(issuer_unique_id, &out->issuer_unique_id)) |
+ return false; |
+ if (out->version != CertificateVersion::V2 && |
+ out->version != CertificateVersion::V3) { |
+ return false; |
+ } |
+ } |
+ |
+ // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, |
+ // -- If present, version MUST be v2 or v3 |
+ der::Input subject_unique_id; |
+ if (!tbs_parser.ReadOptionalTag(der::ContextSpecificPrimitive(2), |
+ &subject_unique_id, |
+ &out->has_subject_unique_id)) { |
+ return false; |
+ } |
+ if (out->has_subject_unique_id) { |
+ if (!der::ParseBitString(subject_unique_id, &out->subject_unique_id)) |
+ return false; |
+ if (out->version != CertificateVersion::V2 && |
+ out->version != CertificateVersion::V3) { |
+ return false; |
+ } |
+ } |
+ |
+ // extensions [3] EXPLICIT Extensions OPTIONAL |
+ // -- If present, version MUST be v3 |
+ if (!tbs_parser.ReadOptionalTag(der::ContextSpecificConstructed(3), |
+ &out->extensions_tlv, &out->has_extensions)) { |
+ return false; |
+ } |
+ if (out->has_extensions) { |
+ // extensions_tlv must be a single element. Also check that it is a |
+ // SEQUENCE. |
+ if (!IsSequenceTLV(out->extensions_tlv)) |
+ return false; |
+ if (out->version != CertificateVersion::V3) |
+ return false; |
+ } |
+ |
+ // Note that there IS an extension point at the end of TBSCertificate |
+ // (according to RFC 5912), so from that interpretation, unconsumed data would |
+ // be allowed in |tbs_parser|. |
+ // |
+ // However because only v1, v2, and v3 certificates are supported by the |
+ // parsing, there shouldn't be any subsequent data in those versions, so |
+ // reject. |
+ if (tbs_parser.HasMore()) |
+ return false; |
+ |
+ // By definition the input was a single TBSCertificate, so there shouldn't be |
+ // unconsumed data. |
+ if (parser.HasMore()) |
+ return false; |
+ |
+ return true; |
+} |
+ |
} // namespace net |