Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/cert/internal/parse_certificate.h" | 5 #include "net/cert/internal/parse_certificate.h" |
| 6 | 6 |
| 7 #include "net/der/input.h" | 7 #include "net/der/input.h" |
| 8 #include "net/der/parse_values.h" | 8 #include "net/der/parse_values.h" |
| 9 #include "net/der/parser.h" | 9 #include "net/der/parser.h" |
| 10 | 10 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 // Should by a single SEQUENCE by definition of the function. | 21 // Should by a single SEQUENCE by definition of the function. |
| 22 return !parser.HasMore(); | 22 return !parser.HasMore(); |
| 23 } | 23 } |
| 24 | 24 |
| 25 // Reads a SEQUENCE from |parser| and writes the full tag-length-value into | 25 // Reads a SEQUENCE from |parser| and writes the full tag-length-value into |
| 26 // |out|. On failure |parser| may or may not have been advanced. | 26 // |out|. On failure |parser| may or may not have been advanced. |
| 27 WARN_UNUSED_RESULT bool ReadSequenceTLV(der::Parser* parser, der::Input* out) { | 27 WARN_UNUSED_RESULT bool ReadSequenceTLV(der::Parser* parser, der::Input* out) { |
| 28 return parser->ReadRawTLV(out) && IsSequenceTLV(*out); | 28 return parser->ReadRawTLV(out) && IsSequenceTLV(*out); |
| 29 } | 29 } |
| 30 | 30 |
| 31 // Parses a Version according to RFC 5280: | |
| 32 // | |
| 33 // Version ::= INTEGER { v1(0), v2(1), v3(2) } | |
| 34 // | |
| 35 // No value other that v1, v2, or v3 is allowed (and if given will fail). RFC | |
| 36 // 5280 minimally requires the handling of v3 (and overwhelmingly these are the | |
| 37 // certificate versions in use today): | |
| 38 // | |
| 39 // Implementations SHOULD be prepared to accept any version certificate. | |
| 40 // At a minimum, conforming implementations MUST recognize version 3 | |
| 41 // certificates. | |
| 42 WARN_UNUSED_RESULT bool ParseVersion(const der::Input& in, | |
| 43 CertificateVersion* version) { | |
| 44 der::Parser parser(in); | |
| 45 uint64_t version64; | |
| 46 if (!parser.ReadUint64(&version64)) | |
| 47 return false; | |
| 48 | |
| 49 switch (version64) { | |
| 50 case 0: | |
| 51 *version = CertificateVersion::V1; | |
| 52 break; | |
| 53 case 1: | |
| 54 *version = CertificateVersion::V2; | |
| 55 break; | |
| 56 case 2: | |
| 57 *version = CertificateVersion::V3; | |
| 58 break; | |
| 59 default: | |
| 60 // Don't allow any other version identifier. | |
| 61 return false; | |
| 62 } | |
| 63 | |
| 64 // By definition the input to this function was a single INTEGER, so there | |
| 65 // shouldn't be anything else after it. | |
| 66 return !parser.HasMore(); | |
| 67 } | |
| 68 | |
| 69 // Returns true if the given serial number (CertificateSerialNumber in RFC 5280) | |
| 70 // is valid: | |
| 71 // | |
| 72 // CertificateSerialNumber ::= INTEGER | |
| 73 // | |
| 74 // The input to this function is the (unverified) value octets of the INTEGER. | |
| 75 // This function will verify that: | |
| 76 // | |
| 77 // * The octets are a valid DER-encoding of an INTEGER (for instance, minimal | |
| 78 // encoding length). | |
| 79 // | |
| 80 // * No more than 20 octets are used. | |
| 81 // | |
| 82 // Note that it DOES NOT reject non-positive values (zero or negative). | |
| 83 // | |
| 84 // For reference, here is what RFC 5280 section 4.1.2.2 says: | |
|
davidben
2015/08/14 17:51:42
Nit: s/here is what // is marginally less verbose.
| |
| 85 // | |
| 86 // Given the uniqueness requirements above, serial numbers can be | |
| 87 // expected to contain long integers. Certificate users MUST be able to | |
| 88 // handle serialNumber values up to 20 octets. Conforming CAs MUST NOT | |
| 89 // use serialNumber values longer than 20 octets. | |
| 90 // | |
| 91 // Note: Non-conforming CAs may issue certificates with serial numbers | |
| 92 // that are negative or zero. Certificate users SHOULD be prepared to | |
| 93 // gracefully handle such certificates. | |
| 94 WARN_UNUSED_RESULT bool VerifySerialNumber(const der::Input& value) { | |
| 95 der::ByteReader reader(value); | |
| 96 | |
| 97 if (value.Length() == 0) | |
| 98 return false; // Not a valid DER-encoded INTEGER. | |
| 99 | |
| 100 // Check if the serial number is too long per RFC 5280. | |
| 101 if (value.Length() > 20) | |
| 102 return false; | |
| 103 | |
| 104 // Accept any single-byte serial number (including zero and negatives). | |
| 105 if (value.Length() == 1) | |
| 106 return true; | |
| 107 | |
| 108 // INTEGER values in DER should be minimal. They should only contain a leading | |
| 109 // zero if the second octet has its most significant bit set to 1 (since | |
| 110 // without the leading zero the described number would be negative). | |
| 111 uint8_t first_byte; | |
| 112 if (!reader.ReadByte(&first_byte)) | |
| 113 return false; // Unexpected | |
| 114 | |
| 115 if (first_byte == 0) { | |
| 116 uint8_t second_byte; | |
| 117 if (!reader.ReadByte(&second_byte)) | |
| 118 return false; // Unexpected | |
| 119 | |
| 120 if ((second_byte & 0x80) == 0) | |
| 121 return false; // MSB must be 1. | |
| 122 } | |
|
davidben
2015/08/14 17:51:42
If you're allowing negative numbers, probably good
eroman
2015/08/14 18:11:59
Good point, I forgot about that!
This sounds gene
davidben
2015/08/14 18:19:22
SGTM
eroman
2015/08/14 21:26:12
Done. (Part of https://codereview.chromium.org/129
| |
| 123 | |
| 124 return true; | |
| 125 } | |
| 126 | |
| 31 } // namespace | 127 } // namespace |
| 32 | 128 |
| 129 ParsedTbsCertificate::ParsedTbsCertificate() | |
| 130 : version(CertificateVersion::V1), | |
| 131 has_issuer_unique_id(false), | |
| 132 has_subject_unique_id(false), | |
| 133 has_extensions(false) {} | |
| 134 | |
| 135 ParsedTbsCertificate::~ParsedTbsCertificate() {} | |
| 136 | |
| 33 bool ParseCertificate(const der::Input& certificate_tlv, | 137 bool ParseCertificate(const der::Input& certificate_tlv, |
| 34 ParsedCertificate* out) { | 138 ParsedCertificate* out) { |
| 35 der::Parser parser(certificate_tlv); | 139 der::Parser parser(certificate_tlv); |
| 36 | 140 |
| 37 // Certificate ::= SEQUENCE { | 141 // Certificate ::= SEQUENCE { |
| 38 der::Parser certificate_parser; | 142 der::Parser certificate_parser; |
| 39 if (!parser.ReadSequence(&certificate_parser)) | 143 if (!parser.ReadSequence(&certificate_parser)) |
| 40 return false; | 144 return false; |
| 41 | 145 |
| 42 // tbsCertificate TBSCertificate, | 146 // tbsCertificate TBSCertificate, |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 56 return false; | 160 return false; |
| 57 | 161 |
| 58 // By definition the input was a single Certificate, so there shouldn't be | 162 // By definition the input was a single Certificate, so there shouldn't be |
| 59 // unconsumed data. | 163 // unconsumed data. |
| 60 if (parser.HasMore()) | 164 if (parser.HasMore()) |
| 61 return false; | 165 return false; |
| 62 | 166 |
| 63 return true; | 167 return true; |
| 64 } | 168 } |
| 65 | 169 |
| 170 // From RFC 5280 section 4.1: | |
| 171 // | |
| 172 // TBSCertificate ::= SEQUENCE { | |
| 173 // version [0] EXPLICIT Version DEFAULT v1, | |
| 174 // serialNumber CertificateSerialNumber, | |
| 175 // signature AlgorithmIdentifier, | |
| 176 // issuer Name, | |
| 177 // validity Validity, | |
| 178 // subject Name, | |
| 179 // subjectPublicKeyInfo SubjectPublicKeyInfo, | |
| 180 // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, | |
| 181 // -- If present, version MUST be v2 or v3 | |
| 182 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, | |
| 183 // -- If present, version MUST be v2 or v3 | |
| 184 // extensions [3] EXPLICIT Extensions OPTIONAL | |
| 185 // -- If present, version MUST be v3 | |
| 186 // } | |
| 187 bool ParseTbsCertificate(const der::Input& tbs_tlv, ParsedTbsCertificate* out) { | |
| 188 der::Parser parser(tbs_tlv); | |
| 189 | |
| 190 // Certificate ::= SEQUENCE { | |
| 191 der::Parser tbs_parser; | |
| 192 if (!parser.ReadSequence(&tbs_parser)) | |
| 193 return false; | |
| 194 | |
| 195 // version [0] EXPLICIT Version DEFAULT v1, | |
| 196 der::Input version; | |
| 197 bool has_version; | |
| 198 if (!tbs_parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &version, | |
| 199 &has_version)) { | |
| 200 return false; | |
| 201 } | |
| 202 if (has_version) { | |
| 203 if (!ParseVersion(version, &out->version)) | |
| 204 return false; | |
| 205 if (out->version == CertificateVersion::V1) { | |
| 206 // The correct way to specify v1 is to omit the version field since v1 is | |
| 207 // the DEFAULT. | |
| 208 return false; | |
| 209 } | |
| 210 } else { | |
| 211 out->version = CertificateVersion::V1; | |
| 212 } | |
| 213 | |
| 214 // serialNumber CertificateSerialNumber, | |
| 215 if (!tbs_parser.ReadTag(der::kInteger, &out->serial_number)) | |
| 216 return false; | |
| 217 if (!VerifySerialNumber(out->serial_number)) | |
| 218 return false; | |
| 219 | |
| 220 // signature AlgorithmIdentifier, | |
| 221 if (!ReadSequenceTLV(&tbs_parser, &out->signature_algorithm_tlv)) | |
| 222 return false; | |
| 223 | |
| 224 // issuer Name, | |
| 225 if (!ReadSequenceTLV(&tbs_parser, &out->issuer_tlv)) | |
| 226 return false; | |
| 227 | |
| 228 // validity Validity, | |
| 229 if (!ReadSequenceTLV(&tbs_parser, &out->validity_tlv)) | |
| 230 return false; | |
| 231 | |
| 232 // subject Name, | |
| 233 if (!ReadSequenceTLV(&tbs_parser, &out->subject_tlv)) | |
| 234 return false; | |
| 235 | |
| 236 // subjectPublicKeyInfo SubjectPublicKeyInfo, | |
| 237 if (!ReadSequenceTLV(&tbs_parser, &out->spki_tlv)) | |
| 238 return false; | |
| 239 | |
| 240 // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, | |
| 241 // -- If present, version MUST be v2 or v3 | |
| 242 der::Input issuer_unique_id; | |
| 243 if (!tbs_parser.ReadOptionalTag(der::ContextSpecificPrimitive(1), | |
| 244 &issuer_unique_id, | |
| 245 &out->has_issuer_unique_id)) { | |
| 246 return false; | |
| 247 } | |
| 248 if (out->has_issuer_unique_id) { | |
| 249 if (!der::ParseBitString(issuer_unique_id, &out->issuer_unique_id)) | |
| 250 return false; | |
| 251 if (out->version != CertificateVersion::V2 && | |
| 252 out->version != CertificateVersion::V3) { | |
| 253 return false; | |
| 254 } | |
| 255 } | |
| 256 | |
| 257 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, | |
| 258 // -- If present, version MUST be v2 or v3 | |
| 259 der::Input subject_unique_id; | |
| 260 if (!tbs_parser.ReadOptionalTag(der::ContextSpecificPrimitive(2), | |
| 261 &subject_unique_id, | |
| 262 &out->has_subject_unique_id)) { | |
| 263 return false; | |
| 264 } | |
| 265 if (out->has_subject_unique_id) { | |
| 266 if (!der::ParseBitString(subject_unique_id, &out->subject_unique_id)) | |
| 267 return false; | |
| 268 if (out->version != CertificateVersion::V2 && | |
| 269 out->version != CertificateVersion::V3) { | |
| 270 return false; | |
| 271 } | |
| 272 } | |
| 273 | |
| 274 // extensions [3] EXPLICIT Extensions OPTIONAL | |
| 275 // -- If present, version MUST be v3 | |
| 276 if (!tbs_parser.ReadOptionalTag(der::ContextSpecificConstructed(3), | |
| 277 &out->extensions_tlv, &out->has_extensions)) { | |
| 278 return false; | |
| 279 } | |
| 280 if (out->has_extensions) { | |
| 281 // ParseTbsCertificate()'s contract guarantees that extensions is a | |
| 282 // SEQUENCE. | |
|
davidben
2015/08/14 17:51:42
Maybe:
// extensions_tlv must be a single eleme
eroman
2015/08/14 21:26:12
Done.
| |
| 283 if (!IsSequenceTLV(out->extensions_tlv)) | |
| 284 return false; | |
| 285 if (out->version != CertificateVersion::V3) | |
| 286 return false; | |
| 287 } | |
| 288 | |
| 289 // Note that there IS an extension point at the end of TBSCertificate | |
| 290 // (according to RFC 5912), so from that interpretation, unconsumed data would | |
| 291 // be allowed in |tbs_parser|. | |
| 292 // | |
| 293 // However because only v1, v2, and v3 certificates are supported by the | |
| 294 // parsing, there shouldn't be any subsequent data in those versions, so | |
| 295 // reject. | |
| 296 if (tbs_parser.HasMore()) | |
| 297 return false; | |
| 298 | |
| 299 // By definition the input was a single TBSCertificate, so there shouldn't be | |
| 300 // unconsumed data. | |
| 301 if (parser.HasMore()) | |
| 302 return false; | |
| 303 | |
| 304 return true; | |
| 305 } | |
| 306 | |
| 66 } // namespace net | 307 } // namespace net |
| OLD | NEW |