OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <algorithm> | |
6 | |
7 #include "base/sha1.h" | |
8 #include "crypto/sha2.h" | |
9 #include "net/cert/internal/parse_ocsp.h" | |
10 | |
11 namespace net { | |
12 | |
13 OCSPCertID::OCSPCertID() {} | |
14 OCSPCertID::~OCSPCertID() {} | |
15 | |
16 OCSPSingleResponse::OCSPSingleResponse() {} | |
17 OCSPSingleResponse::~OCSPSingleResponse() {} | |
18 | |
19 OCSPResponseData::OCSPResponseData() {} | |
20 OCSPResponseData::~OCSPResponseData() {} | |
21 | |
22 OCSPResponse::OCSPResponse() {} | |
23 OCSPResponse::~OCSPResponse() {} | |
24 | |
25 der::Input BasicOCSPResponseOid() { | |
26 // From RFC 6960: | |
27 // | |
28 // id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp } | |
29 // id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 } | |
30 // | |
31 // In dotted notation: 1.3.6.1.5.5.7.48.1.1 | |
32 static const uint8_t oid[] = {0x2b, 0x06, 0x01, 0x05, 0x05, | |
33 0x07, 0x30, 0x01, 0x01}; | |
34 return der::Input(oid); | |
35 } | |
36 | |
37 // CertID ::= SEQUENCE { | |
38 // hashAlgorithm AlgorithmIdentifier, | |
39 // issuerNameHash OCTET STRING, -- Hash of issuer's DN | |
40 // issuerKeyHash OCTET STRING, -- Hash of issuer's public key | |
41 // serialNumber CertificateSerialNumber | |
42 // } | |
43 bool ParseOCSPCertID(const der::Input& raw_tlv, OCSPCertID* out) { | |
44 der::Parser outer_parser(raw_tlv); | |
45 der::Parser parser; | |
46 if (!outer_parser.ReadSequence(&parser)) | |
47 return false; | |
48 if (outer_parser.HasMore()) | |
49 return false; | |
50 | |
51 der::Input sigalg_tlv; | |
52 if (!parser.ReadRawTLV(&sigalg_tlv)) | |
53 return false; | |
54 if (!ParseHashAlgorithm(sigalg_tlv, &(out->hash_algorithm))) | |
55 return false; | |
56 if (!parser.ReadTag(der::kOctetString, &(out->issuer_name_hash))) | |
57 return false; | |
58 if (!parser.ReadTag(der::kOctetString, &(out->issuer_key_hash))) | |
59 return false; | |
60 if (!parser.ReadTag(der::kInteger, &(out->serial_number))) | |
61 return false; | |
62 if (!VerifySerialNumber(out->serial_number)) | |
63 return false; | |
64 | |
65 return !parser.HasMore(); | |
66 } | |
67 | |
68 namespace { | |
69 | |
70 // Parses |raw_tlv| to extract an OCSP RevokedInfo (RFC 6960) and stores the | |
71 // result in the OCSPCertStatus |out|. Returns whether the parsing was | |
72 // successful. | |
73 // | |
74 // RevokedInfo ::= SEQUENCE { | |
75 // revocationTime GeneralizedTime, | |
76 // revocationReason [0] EXPLICIT CRLReason OPTIONAL | |
77 // } | |
78 bool ParseRevokedInfo(const der::Input& raw_tlv, OCSPCertStatus* out) { | |
79 der::Parser parser(raw_tlv); | |
80 if (!parser.ReadGeneralizedTime(&(out->revocation_time))) | |
81 return false; | |
82 | |
83 der::Input reason_input; | |
84 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &reason_input, | |
85 &(out->has_reason))) { | |
86 return false; | |
87 } | |
88 if (out->has_reason) { | |
89 der::Parser reason_parser(reason_input); | |
90 der::Input reason_value_input; | |
91 uint8_t reason_value; | |
92 if (!reason_parser.ReadTag(der::kEnumerated, &reason_value_input)) | |
93 return false; | |
94 if (!der::ParseUint8(reason_value_input, &reason_value)) | |
95 return false; | |
96 if (reason_value > | |
97 static_cast<uint8_t>(OCSPCertStatus::RevocationReason::LAST)) { | |
98 return false; | |
99 } | |
100 out->revocation_reason = | |
101 static_cast<OCSPCertStatus::RevocationReason>(reason_value); | |
102 if (out->revocation_reason == OCSPCertStatus::RevocationReason::UNUSED) | |
103 return false; | |
104 if (reason_parser.HasMore()) | |
105 return false; | |
106 } | |
107 return !parser.HasMore(); | |
108 } | |
109 | |
110 // Parses |raw_tlv| to extract an OCSP CertStatus (RFC 6960) and stores the | |
111 // result in the OCSPCertStatus |out|. Returns whether the parsing was | |
112 // successful. | |
113 // | |
114 // CertStatus ::= CHOICE { | |
115 // good [0] IMPLICIT NULL, | |
116 // revoked [1] IMPLICIT RevokedInfo, | |
117 // unknown [2] IMPLICIT UnknownInfo | |
118 // } | |
119 // | |
120 // UnknownInfo ::= NULL | |
121 bool ParseCertStatus(const der::Input& raw_tlv, OCSPCertStatus* out) { | |
122 der::Parser parser(raw_tlv); | |
123 der::Tag status_tag; | |
124 der::Input status; | |
125 if (!parser.ReadTagAndValue(&status_tag, &status)) | |
126 return false; | |
127 | |
128 out->has_reason = false; | |
129 if (status_tag == der::ContextSpecificPrimitive(0)) { | |
130 out->status = OCSPCertStatus::Status::GOOD; | |
131 } else if (status_tag == der::ContextSpecificConstructed(1)) { | |
132 out->status = OCSPCertStatus::Status::REVOKED; | |
133 if (!ParseRevokedInfo(status, out)) | |
134 return false; | |
135 } else if (status_tag == der::ContextSpecificPrimitive(2)) { | |
136 out->status = OCSPCertStatus::Status::UNKNOWN; | |
137 } else { | |
138 return false; | |
139 } | |
140 | |
141 return !parser.HasMore(); | |
142 } | |
143 | |
144 } // namespace | |
145 | |
146 // SingleResponse ::= SEQUENCE { | |
147 // certID CertID, | |
148 // certStatus CertStatus, | |
149 // thisUpdate GeneralizedTime, | |
150 // nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, | |
151 // singleExtensions [1] EXPLICIT Extensions OPTIONAL | |
152 // } | |
153 bool ParseOCSPSingleResponse(const der::Input& raw_tlv, | |
154 OCSPSingleResponse* out) { | |
155 der::Parser outer_parser(raw_tlv); | |
156 der::Parser parser; | |
157 if (!outer_parser.ReadSequence(&parser)) | |
158 return false; | |
159 if (outer_parser.HasMore()) | |
160 return false; | |
161 | |
162 if (!parser.ReadRawTLV(&(out->cert_id_tlv))) | |
163 return false; | |
164 der::Input status_tlv; | |
165 if (!parser.ReadRawTLV(&status_tlv)) | |
166 return false; | |
167 if (!ParseCertStatus(status_tlv, &(out->cert_status))) | |
168 return false; | |
169 if (!parser.ReadGeneralizedTime(&(out->this_update))) | |
170 return false; | |
171 | |
172 der::Input next_update_input; | |
173 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0), | |
174 &next_update_input, &(out->has_next_update))) { | |
175 return false; | |
176 } | |
177 if (out->has_next_update) { | |
178 der::Parser next_update_parser(next_update_input); | |
179 if (!next_update_parser.ReadGeneralizedTime(&(out->next_update))) | |
180 return false; | |
181 if (next_update_parser.HasMore()) | |
182 return false; | |
183 } | |
184 | |
185 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(1), | |
186 &(out->extensions), &(out->has_extensions))) { | |
187 return false; | |
188 } | |
189 | |
190 return !parser.HasMore(); | |
191 } | |
192 | |
193 namespace { | |
194 | |
195 // Parses |raw_tlv| to extract a ResponderID (RFC 6960) and stores the | |
196 // result in the ResponderID |out|. Returns whether the parsing was successful. | |
197 // | |
198 // ResponderID ::= CHOICE { | |
199 // byName [1] Name, | |
200 // byKey [2] KeyHash | |
201 // } | |
202 bool ParseResponderID(const der::Input& raw_tlv, | |
203 OCSPResponseData::ResponderID* out) { | |
204 der::Parser parser(raw_tlv); | |
205 der::Tag id_tag; | |
206 der::Input id_input; | |
207 if (!parser.ReadTagAndValue(&id_tag, &id_input)) | |
208 return false; | |
209 | |
210 if (id_tag == der::ContextSpecificConstructed(1)) { | |
211 out->type = OCSPResponseData::ResponderType::NAME; | |
212 out->name = id_input; | |
213 } else if (id_tag == der::ContextSpecificConstructed(2)) { | |
214 der::Parser key_parser(id_input); | |
215 der::Input responder_key; | |
216 if (!key_parser.ReadTag(der::kOctetString, &responder_key)) | |
217 return false; | |
218 if (key_parser.HasMore()) | |
219 return false; | |
220 | |
221 SHA1HashValue key_hash; | |
222 if (responder_key.Length() != sizeof(key_hash.data)) | |
223 return false; | |
224 memcpy(key_hash.data, responder_key.UnsafeData(), sizeof(key_hash.data)); | |
225 out->type = OCSPResponseData::ResponderType::KEY_HASH; | |
226 out->key_hash = HashValue(key_hash); | |
227 } else { | |
228 return false; | |
229 } | |
230 return !parser.HasMore(); | |
231 } | |
232 | |
233 } // namespace | |
234 | |
235 // ResponseData ::= SEQUENCE { | |
236 // version [0] EXPLICIT Version DEFAULT v1, | |
237 // responderID ResponderID, | |
238 // producedAt GeneralizedTime, | |
239 // responses SEQUENCE OF SingleResponse, | |
240 // responseExtensions [1] EXPLICIT Extensions OPTIONAL | |
241 // } | |
242 bool ParseOCSPResponseData(const der::Input& raw_tlv, OCSPResponseData* out) { | |
243 der::Parser outer_parser(raw_tlv); | |
244 der::Parser parser; | |
245 if (!outer_parser.ReadSequence(&parser)) | |
246 return false; | |
247 if (outer_parser.HasMore()) | |
248 return false; | |
249 | |
250 der::Input version_input; | |
251 bool version_present; | |
252 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0), | |
253 &version_input, &version_present)) { | |
254 return false; | |
255 } | |
256 | |
257 // For compatibilty, we ignore the restriction from X.690 Section 11.5 that | |
258 // DEFAULT values should be omitted for values equal to the default value. | |
259 // TODO: Add warning about non-strict parsing. | |
260 if (version_present) { | |
261 der::Parser version_parser(version_input); | |
262 if (!version_parser.ReadUint8(&(out->version))) | |
263 return false; | |
264 if (version_parser.HasMore()) | |
265 return false; | |
266 } else { | |
267 out->version = 0; | |
268 } | |
269 | |
270 if (out->version != 0) | |
271 return false; | |
272 | |
273 der::Input responder_input; | |
274 if (!parser.ReadRawTLV(&responder_input)) | |
275 return false; | |
276 if (!ParseResponderID(responder_input, &(out->responder_id))) | |
277 return false; | |
278 if (!parser.ReadGeneralizedTime(&(out->produced_at))) | |
279 return false; | |
280 | |
281 der::Parser responses_parser; | |
282 if (!parser.ReadSequence(&responses_parser)) | |
283 return false; | |
284 out->responses.clear(); | |
285 while (responses_parser.HasMore()) { | |
286 der::Input single_response; | |
287 if (!responses_parser.ReadRawTLV(&single_response)) | |
288 return false; | |
289 out->responses.push_back(single_response); | |
290 } | |
291 | |
292 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(1), | |
293 &(out->extensions), &(out->has_extensions))) { | |
294 return false; | |
295 } | |
296 | |
297 return !parser.HasMore(); | |
298 } | |
299 | |
300 namespace { | |
301 | |
302 // Parses |raw_tlv| to extract a BasicOCSPResponse (RFC 6960) and stores the | |
303 // result in the OCSPResponse |out|. Returns whether the parsing was | |
304 // successful. | |
305 // | |
306 // BasicOCSPResponse ::= SEQUENCE { | |
307 // tbsResponseData ResponseData, | |
308 // signatureAlgorithm AlgorithmIdentifier, | |
309 // signature BIT STRING, | |
310 // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL | |
311 // } | |
312 bool ParseBasicOCSPResponse(const der::Input& raw_tlv, OCSPResponse* out) { | |
313 der::Parser outer_parser(raw_tlv); | |
314 der::Parser parser; | |
315 if (!outer_parser.ReadSequence(&parser)) | |
316 return false; | |
317 if (outer_parser.HasMore()) | |
318 return false; | |
319 | |
320 if (!parser.ReadRawTLV(&(out->data))) | |
321 return false; | |
322 der::Input sigalg_tlv; | |
323 if (!parser.ReadRawTLV(&sigalg_tlv)) | |
324 return false; | |
325 out->signature_algorithm = SignatureAlgorithm::CreateFromDer(sigalg_tlv); | |
326 if (!out->signature_algorithm) | |
327 return false; | |
328 if (!parser.ReadBitString(&(out->signature))) | |
329 return false; | |
330 der::Input certs_input; | |
331 if (!parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &certs_input, | |
332 &(out->has_certs))) { | |
333 return false; | |
334 } | |
335 | |
336 out->certs.clear(); | |
337 if (out->has_certs) { | |
338 der::Parser certs_seq_parser(certs_input); | |
339 der::Parser certs_parser; | |
340 if (!certs_seq_parser.ReadSequence(&certs_parser)) | |
341 return false; | |
342 if (certs_seq_parser.HasMore()) | |
343 return false; | |
344 while (certs_parser.HasMore()) { | |
345 der::Input cert_tlv; | |
346 if (!certs_parser.ReadRawTLV(&cert_tlv)) | |
347 return false; | |
348 out->certs.push_back(cert_tlv); | |
349 } | |
350 } | |
351 | |
352 return !parser.HasMore(); | |
353 } | |
354 | |
355 } // namespace | |
356 | |
357 // OCSPResponse ::= SEQUENCE { | |
358 // responseStatus OCSPResponseStatus, | |
359 // responseBytes [0] EXPLICIT ResponseBytes OPTIONAL | |
360 // } | |
361 // | |
362 // ResponseBytes ::= SEQUENCE { | |
363 // responseType OBJECT IDENTIFIER, | |
364 // response OCTET STRING | |
365 // } | |
366 bool ParseOCSPResponse(const der::Input& raw_tlv, OCSPResponse* out) { | |
367 der::Parser outer_parser(raw_tlv); | |
368 der::Parser parser; | |
369 if (!outer_parser.ReadSequence(&parser)) | |
370 return false; | |
371 if (outer_parser.HasMore()) | |
372 return false; | |
373 | |
374 der::Input response_status_input; | |
375 uint8_t response_status; | |
376 if (!parser.ReadTag(der::kEnumerated, &response_status_input)) | |
377 return false; | |
378 if (!der::ParseUint8(response_status_input, &response_status)) | |
379 return false; | |
380 if (response_status > | |
381 static_cast<uint8_t>(OCSPResponse::ResponseStatus::LAST)) { | |
382 return false; | |
383 } | |
384 out->status = static_cast<OCSPResponse::ResponseStatus>(response_status); | |
385 if (out->status == OCSPResponse::ResponseStatus::UNUSED) | |
386 return false; | |
387 | |
388 if (out->status == OCSPResponse::ResponseStatus::SUCCESSFUL) { | |
389 der::Parser outer_bytes_parser; | |
390 der::Parser bytes_parser; | |
391 if (!parser.ReadConstructed(der::ContextSpecificConstructed(0), | |
392 &outer_bytes_parser)) { | |
393 return false; | |
394 } | |
395 if (!outer_bytes_parser.ReadSequence(&bytes_parser)) | |
396 return false; | |
397 if (outer_bytes_parser.HasMore()) | |
398 return false; | |
399 | |
400 der::Input type_oid; | |
401 if (!bytes_parser.ReadTag(der::kOid, &type_oid)) | |
402 return false; | |
403 if (type_oid != BasicOCSPResponseOid()) | |
404 return false; | |
405 | |
406 // As per RFC 6960 Section 4.2.1, the value of |response| SHALL be the DER | |
407 // encoding of BasicOCSPResponse. | |
408 der::Input response; | |
409 if (!bytes_parser.ReadTag(der::kOctetString, &response)) | |
410 return false; | |
411 if (!ParseBasicOCSPResponse(response, out)) | |
412 return false; | |
413 if (bytes_parser.HasMore()) | |
414 return false; | |
415 } | |
416 | |
417 return !parser.HasMore(); | |
418 } | |
419 | |
420 namespace { | |
421 | |
422 // Checks that the |type| hash of |value| is equal to |hash| | |
423 bool VerifyHash(HashValueTag type, | |
424 const der::Input& hash, | |
425 const der::Input& value) { | |
426 HashValue target(type); | |
427 if (target.size() != hash.Length()) | |
428 return false; | |
429 memcpy(target.data(), hash.UnsafeData(), target.size()); | |
430 | |
431 HashValue value_hash(type); | |
432 if (type == HASH_VALUE_SHA1) { | |
433 base::SHA1HashBytes(value.UnsafeData(), value.Length(), value_hash.data()); | |
434 } else if (type == HASH_VALUE_SHA256) { | |
435 std::string hash_string = crypto::SHA256HashString(value.AsString()); | |
436 memcpy(value_hash.data(), hash_string.data(), value_hash.size()); | |
437 } else { | |
438 return false; | |
439 } | |
440 | |
441 return target.Equals(value_hash); | |
442 } | |
443 | |
444 // Checks that the input |id_tlv| parses to a valid CertID and matches the | |
445 // issuer |issuer| name and key, as well as the serial number |serial_number|. | |
446 bool CheckCertID(const der::Input& id_tlv, | |
447 const ParsedTbsCertificate& certificate, | |
448 const ParsedTbsCertificate& issuer, | |
449 const der::Input& serial_number) { | |
450 OCSPCertID id; | |
451 if (!ParseOCSPCertID(id_tlv, &id)) | |
452 return false; | |
453 | |
454 HashValueTag type = HASH_VALUE_SHA1; | |
455 switch (id.hash_algorithm) { | |
456 case DigestAlgorithm::Sha1: | |
457 type = HASH_VALUE_SHA1; | |
458 break; | |
459 case DigestAlgorithm::Sha256: | |
460 type = HASH_VALUE_SHA256; | |
461 break; | |
462 case DigestAlgorithm::Sha384: | |
463 case DigestAlgorithm::Sha512: | |
464 NOTIMPLEMENTED(); | |
465 return false; | |
466 } | |
467 | |
468 if (!VerifyHash(type, id.issuer_name_hash, certificate.issuer_tlv)) | |
469 return false; | |
470 | |
471 // SubjectPublicKeyInfo ::= SEQUENCE { | |
472 // algorithm AlgorithmIdentifier, | |
473 // subjectPublicKey BIT STRING | |
474 // } | |
475 der::Parser outer_parser(issuer.spki_tlv); | |
476 der::Parser spki_parser; | |
477 der::BitString key_bits; | |
478 if (!outer_parser.ReadSequence(&spki_parser)) | |
479 return false; | |
480 if (outer_parser.HasMore()) | |
481 return false; | |
482 if (!spki_parser.SkipTag(der::kSequence)) | |
483 return false; | |
484 if (!spki_parser.ReadBitString(&key_bits)) | |
485 return false; | |
486 der::Input key_tlv = key_bits.bytes(); | |
487 if (!VerifyHash(type, id.issuer_key_hash, key_tlv)) | |
488 return false; | |
489 | |
490 return id.serial_number == serial_number; | |
491 } | |
492 | |
493 } // namespace | |
494 | |
495 bool GetOCSPCertStatus(const OCSPResponseData& response_data, | |
496 const ParsedCertificate& issuer, | |
497 const ParsedCertificate& cert, | |
498 OCSPCertStatus* out) { | |
499 out->status = OCSPCertStatus::Status::GOOD; | |
500 | |
501 ParsedTbsCertificate tbs_cert; | |
502 if (!ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs_cert)) | |
503 return false; | |
504 ParsedTbsCertificate issuer_tbs_cert; | |
505 if (!ParseTbsCertificate(issuer.tbs_certificate_tlv, &issuer_tbs_cert)) | |
506 return false; | |
507 | |
508 bool found = false; | |
509 for (const auto& response : response_data.responses) { | |
510 OCSPSingleResponse single_response; | |
511 if (!ParseOCSPSingleResponse(response, &single_response)) | |
512 return false; | |
513 if (CheckCertID(single_response.cert_id_tlv, tbs_cert, issuer_tbs_cert, | |
514 tbs_cert.serial_number)) { | |
515 OCSPCertStatus new_status = single_response.cert_status; | |
516 found = true; | |
517 // In the case that we receive multiple responses, we keep only the | |
518 // strictest status (REVOKED > UNKNOWN > GOOD). | |
519 if (out->status == OCSPCertStatus::Status::GOOD || | |
520 new_status.status == OCSPCertStatus::Status::REVOKED) { | |
521 *out = new_status; | |
522 } | |
523 } | |
524 } | |
525 | |
526 if (!found) | |
527 out->status = OCSPCertStatus::Status::UNKNOWN; | |
528 | |
529 return found; | |
530 } | |
531 | |
532 } // namespace net | |
OLD | NEW |