OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/asn1_util.h" | 5 #include "net/cert/asn1_util.h" |
6 | 6 |
7 namespace net { | 7 namespace net { |
8 | 8 |
9 namespace asn1 { | 9 namespace asn1 { |
10 | 10 |
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
319 return false; | 319 return false; |
320 } | 320 } |
321 } | 321 } |
322 } | 322 } |
323 } | 323 } |
324 | 324 |
325 urls_out->swap(tmp_urls_out); | 325 urls_out->swap(tmp_urls_out); |
326 return true; | 326 return true; |
327 } | 327 } |
328 | 328 |
329 bool ExtractSCTExtensionFromOCSPResponse( | |
330 base::StringPiece ocsp_response, | |
331 const base::StringPiece& cert_serial_number, | |
332 base::StringPiece* sct_list_out) { | |
333 sct_list_out->clear(); | |
334 | |
335 // OCSPResponse ::= SEQUENCE { | |
336 // responseStatus OCSPResponseStatus, | |
337 // responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } | |
338 base::StringPiece ocsp_response_sequence; | |
339 if (!GetElement(&ocsp_response, kSEQUENCE, &ocsp_response_sequence)) | |
340 return false; | |
341 if (!ocsp_response.empty()) | |
342 return false; | |
343 | |
344 // responseStatus | |
345 if (!GetElement(&ocsp_response_sequence, kENUMERATED, NULL)) | |
346 return false; | |
347 | |
348 // responseBytes | |
349 base::StringPiece response_bytes_outer; | |
350 if (!GetElement(&ocsp_response_sequence, | |
351 kOptional | kConstructed | kContextSpecific | 0, | |
352 &response_bytes_outer)) | |
353 return false; | |
wtc
2013/12/03 01:18:06
Nit: add curly braces {} because the conditional e
ekasper
2013/12/03 13:50:51
Done.
| |
354 if (!ocsp_response_sequence.empty()) | |
355 return false; | |
356 | |
357 // ResponseBytes ::= SEQUENCE { | |
358 // responseType OBJECT IDENTIFIER, | |
359 // response OCTET STRING } -- DER encoding of BasicOCSPResponse | |
360 base::StringPiece response_bytes; | |
361 if (!GetElement(&response_bytes_outer, kSEQUENCE, &response_bytes)) | |
362 return false; | |
363 if (!response_bytes_outer.empty()) | |
364 return false; | |
365 | |
366 // responseType | |
367 base::StringPiece response_type; | |
368 if (!GetElement(&response_bytes, kOID, &response_type)) | |
369 return false; | |
370 | |
371 // id-ad-ocsp: 1.3.6.1.5.5.7.48.1.1 | |
372 static const uint8 kBasicOCSPResponseOID[] = {0x2b, 0x06, 0x01, 0x05, 0x05, | |
373 0x07, 0x30, 0x01, 0x01}; | |
wtc
2013/12/03 01:18:06
Nit: add a space after '{' and before '}'.
ekasper
2013/12/03 13:50:51
Done.
| |
374 | |
375 if (response_type.size() != sizeof(kBasicOCSPResponseOID) || | |
376 memcmp(response_type.data(), kBasicOCSPResponseOID, | |
377 response_type.size()) != 0) | |
378 return false; | |
379 | |
380 base::StringPiece wrapped_response; | |
381 if (!GetElement(&response_bytes, kOCTETSTRING, &wrapped_response)) | |
382 return false; | |
383 | |
384 if (!response_bytes.empty()) | |
385 return false; | |
386 | |
387 // BasicOCSPResponse ::= SEQUENCE { | |
388 // tbsResponseData ResponseData, | |
389 // signatureAlgorithm AlgorithmIdentifier, | |
390 // signature BIT STRING, | |
391 // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } | |
392 base::StringPiece basic_ocsp_response; | |
393 if (!GetElement(&wrapped_response, kSEQUENCE, &basic_ocsp_response)) | |
394 return false; | |
395 if (!wrapped_response.empty()) | |
396 return false; | |
397 | |
398 // ResponseData ::= SEQUENCE { | |
399 // version [0] EXPLICIT Version DEFAULT v1, | |
400 // responderID ResponderID, | |
401 // producedAt GeneralizedTime, | |
402 // responses SEQUENCE OF SingleResponse, | |
403 // responseExtensions [1] EXPLICIT Extensions OPTIONAL } | |
404 base::StringPiece tbs_response_data; | |
405 if (!GetElement(&basic_ocsp_response, kSEQUENCE, &tbs_response_data)) | |
406 return false; | |
407 | |
408 // version | |
409 if (!GetElement(&tbs_response_data, | |
410 kOptional | kConstructed | kContextSpecific | 0, NULL)) | |
411 return false; | |
412 | |
413 // ResponderID ::= CHOICE { | |
414 // byName [1] Name, | |
415 // byKey [2] KeyHash } | |
416 if (!GetElement(&tbs_response_data, | |
417 kConstructed | kContextSpecific | 1, NULL) && | |
418 !GetElement(&tbs_response_data, | |
419 kConstructed | kContextSpecific | 2, NULL)) | |
420 return false; | |
421 | |
422 // producedAt | |
423 if (!GetElement(&tbs_response_data, kGENERALIZEDTIME, NULL)) | |
424 return false; | |
425 | |
426 // responses: SEQUENCE OF and SEQUENCE share the same tag. | |
427 base::StringPiece responses; | |
428 if (!GetElement(&tbs_response_data, kSEQUENCE, &responses)) | |
429 return false; | |
430 | |
431 while (responses.size() > 0) { | |
wtc
2013/12/03 01:18:06
Nit: this function is very long. If we want to bre
ekasper
2013/12/03 13:50:51
I've broken it up so that the seeking to the right
| |
432 // SingleResponse ::= SEQUENCE { | |
433 // certID CertID, | |
434 // certStatus CertStatus, | |
435 // thisUpdate GeneralizedTime, | |
436 // nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, | |
437 // singleExtensions [1] EXPLICIT Extensions OPTIONAL } | |
438 base::StringPiece single_response; | |
439 if (!GetElement(&responses, kSEQUENCE, &single_response)) | |
440 return false; | |
441 | |
442 // CertID ::= SEQUENCE { | |
443 // hashAlgorithm AlgorithmIdentifier, | |
444 // issuerNameHash OCTET STRING, -- Hash of Issuer's DN | |
445 // issuerKeyHash OCTET STRING, -- Hash of Issuers public key | |
446 // serialNumber CertificateSerialNumber } | |
447 base::StringPiece cert_id; | |
448 if (!GetElement(&single_response, kSEQUENCE, &cert_id)) | |
449 return false; | |
450 | |
451 // hashAlgorithm | |
452 if (!GetElement(&cert_id, kSEQUENCE, NULL)) | |
453 return false; | |
454 // issuerNameHash | |
455 if (!GetElement(&cert_id, kOCTETSTRING, NULL)) | |
456 return false; | |
457 // issuerKeyHash | |
458 if (!GetElement(&cert_id, kOCTETSTRING, NULL)) | |
459 return false; | |
460 | |
461 base::StringPiece serial_number; | |
462 if (!GetElement(&cert_id, kINTEGER, &serial_number)) | |
463 return false; | |
464 | |
465 if (serial_number != cert_serial_number) { | |
466 // Serial number mismatch - continue. | |
467 continue; | |
468 } | |
469 | |
470 // Serial number match: continue to see if the CT extension is present. | |
471 // CertStatus ::= CHOICE { | |
472 // good [0] IMPLICIT NULL, | |
473 // revoked [1] IMPLICIT RevokedInfo, | |
474 // unknown [2] IMPLICIT UnknownInfo } | |
475 if (!GetElement(&single_response, kContextSpecific | 0, NULL) && | |
476 !GetElement(&single_response, | |
477 kContextSpecific | kConstructed | 1, NULL) && | |
478 !GetElement(&single_response, kContextSpecific | 2, NULL)) | |
479 return false; | |
480 | |
481 // thisUpdate | |
482 if (!GetElement(&single_response, kGENERALIZEDTIME, NULL)) | |
483 return false; | |
484 // nextUpdate | |
485 if (!GetElement(&single_response, | |
486 kConstructed | kOptional | kContextSpecific | 0, NULL)) | |
487 return false; | |
488 | |
489 base::StringPiece single_extensions_outer; | |
490 if (!GetElement(&single_response, | |
491 kConstructed | kOptional | kContextSpecific | 1, | |
492 &single_extensions_outer)) | |
493 return false; | |
494 if (!single_response.empty()) | |
495 return false; | |
496 | |
497 if (single_extensions_outer.empty()) { | |
498 // No extensions; and since we should only have one singleResponse per | |
499 // certificate, we stop here. | |
500 return true; | |
501 } | |
502 | |
503 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension | |
504 base::StringPiece single_extensions; | |
505 if (!GetElement(&single_extensions_outer, kSEQUENCE, &single_extensions)) | |
506 return false; | |
507 | |
508 // Extension ::= SEQUENCE { | |
509 // extnID OBJECT IDENTIFIER, | |
510 // critical BOOLEAN DEFAULT FALSE, | |
511 // extnValue OCTET STRING | |
512 // -- contains the DER encoding of an ASN.1 value | |
513 // -- corresponding to the extension type identified | |
514 // -- by extnID | |
515 // } | |
516 | |
517 while (!single_extensions.empty()) { | |
518 base::StringPiece extension; | |
519 if (!GetElement(&single_extensions, kSEQUENCE, &extension)) | |
520 return false; | |
521 | |
522 base::StringPiece extn_id; | |
523 if (!GetElement(&extension, kOID, &extn_id)) | |
524 return false; | |
525 | |
526 static const uint8 kSignedCertTimestampListOID[] = { | |
527 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x05 | |
528 }; | |
529 if (extn_id.size() != sizeof(kSignedCertTimestampListOID) || | |
530 memcmp(extn_id.data(), kSignedCertTimestampListOID, | |
531 extn_id.size() != 0)) | |
532 continue; | |
533 | |
534 // critical | |
535 if (!GetElement(&extension, kBOOLEAN, NULL)) | |
536 return false; | |
537 | |
538 // extnValue | |
539 base::StringPiece extn_value; | |
540 if (!GetElement(&extension, kOCTETSTRING, &extn_value)) | |
541 return false; | |
542 if (!extension.empty()) | |
543 return false; | |
544 | |
545 // The value of this extension is an OCTET STRING: | |
546 // SignedCertificateTimestampList ::= OCTET STRING | |
547 base::StringPiece sct_list; | |
548 if (!GetElement(&extn_value, kOCTETSTRING, &sct_list)) | |
549 return false; | |
550 *sct_list_out = sct_list; | |
551 return true; | |
552 } | |
wtc
2013/12/03 01:18:06
We should also return true at the end of this (inn
ekasper
2013/12/03 13:50:51
Good catch, done as you suggested, break; followed
| |
553 } | |
554 | |
555 // No extension found. | |
556 return true; | |
wtc
2013/12/03 01:18:06
With the change I proposed above, the only reason
ekasper
2013/12/03 13:50:51
Yes, a false is probably better in this case. This
| |
557 } | |
558 | |
329 } // namespace asn1 | 559 } // namespace asn1 |
330 | 560 |
331 } // namespace net | 561 } // namespace net |
OLD | NEW |