1 // Copyright 2013 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.
5 #include "net/cert/ct_objects_extractor.h"
12 #include "base/lazy_instance.h"
13 #include "base/sha1.h"
14 #include "crypto/scoped_nss_types.h"
15 #include "crypto/sha2.h"
16 #include "net/cert/asn1_util.h"
17 #include "net/cert/scoped_nss_types.h"
18 #include "net/cert/signed_certificate_timestamp.h"
26 // NSS black magic to get the address of externally defined template at runtime.
27 SEC_ASN1_MKSUB(SEC_IntegerTemplate
)
28 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate
)
29 SEC_ASN1_MKSUB(SEC_GeneralizedTimeTemplate
)
30 SEC_ASN1_MKSUB(CERT_SequenceOfCertExtensionTemplate
)
32 // Wrapper class to convert a X509Certificate::OSCertHandle directly
33 // into a CERTCertificate* usable with other NSS functions. This is used for
34 // platforms where X509Certificate::OSCertHandle refers to a different type
35 // than a CERTCertificate*.
36 struct NSSCertWrapper
{
37 explicit NSSCertWrapper(X509Certificate::OSCertHandle cert_handle
);
40 ScopedCERTCertificate cert
;
43 NSSCertWrapper::NSSCertWrapper(X509Certificate::OSCertHandle cert_handle
) {
45 cert
.reset(CERT_DupCertificate(cert_handle
));
49 if (!X509Certificate::GetDEREncoded(cert_handle
, &der_data
))
52 reinterpret_cast<unsigned char*>(const_cast<char*>(der_data
.data()));
53 der_cert
.len
= der_data
.size();
55 // Note: CERT_NewTempCertificate may return NULL if the certificate
56 // shares a serial number with another cert issued by the same CA,
57 // which is not supposed to happen.
58 cert
.reset(CERT_NewTempCertificate(
59 CERT_GetDefaultCertDB(), &der_cert
, NULL
, PR_FALSE
, PR_TRUE
));
61 DCHECK(cert
.get() != NULL
);
64 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of
66 const unsigned char kEmbeddedSCTOid
[] = {0x2B, 0x06, 0x01, 0x04, 0x01,
67 0xD6, 0x79, 0x02, 0x04, 0x02};
68 const char kEmbeddedSCTDescription
[] =
69 "X.509v3 Certificate Transparency Embedded Signed Certificate Timestamp "
72 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.5 - OCSP SingleExtension for
73 // X.509v3 Certificate Transparency Signed Certificate Timestamp List, see
74 // Section 3.3 of RFC6962.
75 const unsigned char kOCSPExtensionOid
[] = {0x2B, 0x06, 0x01, 0x04, 0x01,
76 0xD6, 0x79, 0x02, 0x04, 0x05};
78 const SECItem kOCSPExtensionOidItem
= {
79 siBuffer
, const_cast<unsigned char*>(kOCSPExtensionOid
),
80 sizeof(kOCSPExtensionOid
)
83 // id-ad-ocsp: 1.3.6.1.5.5.7.48.1.1
84 const unsigned char kBasicOCSPResponseOid
[] = {0x2B, 0x06, 0x01, 0x05, 0x05,
85 0x07, 0x30, 0x01, 0x01};
87 const SECItem kBasicOCSPResponseOidItem
= {
88 siBuffer
, const_cast<unsigned char*>(kBasicOCSPResponseOid
),
89 sizeof(kBasicOCSPResponseOid
)
93 // Initializes the necessary NSS internals for use with Certificate
95 class CTInitSingleton
{
97 SECOidTag
embedded_oid() const { return embedded_oid_
; }
100 friend struct base::DefaultLazyInstanceTraits
<CTInitSingleton
>;
102 CTInitSingleton() : embedded_oid_(SEC_OID_UNKNOWN
) {
103 embedded_oid_
= RegisterOid(
104 kEmbeddedSCTOid
, sizeof(kEmbeddedSCTOid
), kEmbeddedSCTDescription
);
107 ~CTInitSingleton() {}
109 SECOidTag
RegisterOid(const unsigned char* oid
,
110 unsigned int oid_len
,
111 const char* description
) {
113 oid_data
.oid
.len
= oid_len
;
114 oid_data
.oid
.data
= const_cast<unsigned char*>(oid
);
115 oid_data
.offset
= SEC_OID_UNKNOWN
;
116 oid_data
.desc
= description
;
117 oid_data
.mechanism
= CKM_INVALID_MECHANISM
;
118 // Setting this to SUPPORTED_CERT_EXTENSION ensures that if a certificate
119 // contains this extension with the critical bit set, NSS will not reject
120 // it. However, because verification of this extension happens after NSS,
121 // it is currently left as INVALID_CERT_EXTENSION.
122 oid_data
.supportedExtension
= INVALID_CERT_EXTENSION
;
124 SECOidTag result
= SECOID_AddEntry(&oid_data
);
125 CHECK_NE(SEC_OID_UNKNOWN
, result
);
130 SECOidTag embedded_oid_
;
132 DISALLOW_COPY_AND_ASSIGN(CTInitSingleton
);
135 base::LazyInstance
<CTInitSingleton
>::Leaky g_ct_singleton
=
136 LAZY_INSTANCE_INITIALIZER
;
138 // Obtains the data for an X.509v3 certificate extension identified by |oid|
139 // and encoded as an OCTET STRING. Returns true if the extension was found in
140 // the certificate, updating |ext_data| to be the extension data after removing
141 // the DER encoding of OCTET STRING.
142 bool GetCertOctetStringExtension(CERTCertificate
* cert
,
144 std::string
* extension_data
) {
146 SECStatus rv
= CERT_FindCertExtension(cert
, oid
, &extension
);
147 if (rv
!= SECSuccess
)
150 base::StringPiece
raw_data(reinterpret_cast<char*>(extension
.data
),
152 base::StringPiece parsed_data
;
153 if (!asn1::GetElement(&raw_data
, asn1::kOCTETSTRING
, &parsed_data
) ||
154 raw_data
.size() > 0) { // Decoding failure or raw data left
157 parsed_data
.CopyToString(extension_data
);
160 SECITEM_FreeItem(&extension
, PR_FALSE
);
161 return rv
== SECSuccess
;
164 // NSS offers CERT_FindCertExtension for certificates, but that only accepts
165 // CERTCertificate* inputs, so the method below extracts the SCT extension
166 // directly from the CERTCertExtension** of an OCSP response.
168 // Obtains the data for an OCSP extension identified by kOCSPExtensionOidItem
169 // and encoded as an OCTET STRING. Returns true if the extension was found in
170 // |extensions|, updating |extension_data| to be the extension data after
171 // removing the DER encoding of OCTET STRING.
172 bool GetSCTListFromOCSPExtension(PLArenaPool
* arena
,
173 const CERTCertExtension
* const* extensions
,
174 std::string
* extension_data
) {
178 const CERTCertExtension
* match
= NULL
;
180 for (const CERTCertExtension
* const* exts
= extensions
; *exts
; ++exts
) {
181 const CERTCertExtension
* ext
= *exts
;
182 if (SECITEM_ItemsAreEqual(&kOCSPExtensionOidItem
, &ext
->id
)) {
192 // SEC_QuickDERDecodeItem sets |contents| to point to |match|, so it is not
193 // necessary to free the contents of |contents|.
194 SECStatus rv
= SEC_QuickDERDecodeItem(arena
, &contents
,
195 SEC_ASN1_GET(SEC_OctetStringTemplate
),
197 if (rv
!= SECSuccess
)
200 base::StringPiece
parsed_data(reinterpret_cast<char*>(contents
.data
),
202 parsed_data
.CopyToString(extension_data
);
206 // Given a |cert|, extract the TBSCertificate from this certificate, also
207 // removing the X.509 extension with OID 1.3.6.1.4.1.11129.2.4.2 (that is,
209 bool ExtractTBSCertWithoutSCTs(CERTCertificate
* cert
,
210 std::string
* to_be_signed
) {
211 SECOidData
* oid
= SECOID_FindOIDByTag(g_ct_singleton
.Get().embedded_oid());
215 // This is a giant hack, due to the fact that NSS does not expose a good API
216 // for simply removing certificate fields from existing certificates.
217 CERTCertificate temp_cert
;
219 temp_cert
.extensions
= NULL
;
221 // Strip out the embedded SCT OID from the new certificate by directly
222 // mutating the extensions in place.
223 std::vector
<CERTCertExtension
*> new_extensions
;
224 if (cert
->extensions
) {
225 for (CERTCertExtension
** exts
= cert
->extensions
; *exts
; ++exts
) {
226 CERTCertExtension
* ext
= *exts
;
227 SECComparison result
= SECITEM_CompareItem(&oid
->oid
, &ext
->id
);
228 if (result
!= SECEqual
)
229 new_extensions
.push_back(ext
);
232 if (!new_extensions
.empty()) {
233 new_extensions
.push_back(NULL
);
234 temp_cert
.extensions
= &new_extensions
[0];
237 crypto::ScopedPLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
241 tbs_data
.data
= NULL
;
242 void* result
= SEC_ASN1EncodeItem(arena
.get(),
245 SEC_ASN1_GET(CERT_CertificateTemplate
));
249 to_be_signed
->assign(reinterpret_cast<char*>(tbs_data
.data
), tbs_data
.len
);
253 // The following code is adapted from the NSS OCSP module, in order to expose
254 // the internal structure of an OCSP response.
256 // ResponseBytes ::= SEQUENCE {
257 // responseType OBJECT IDENTIFIER,
258 // response OCTET STRING }
259 struct ResponseBytes
{
260 SECItem response_type
;
261 SECItem der_response
;
264 const SEC_ASN1Template kResponseBytesTemplate
[] = {
265 { SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(ResponseBytes
) },
266 { SEC_ASN1_OBJECT_ID
, offsetof(ResponseBytes
, response_type
) },
267 { SEC_ASN1_OCTET_STRING
, offsetof(ResponseBytes
, der_response
) },
271 // OCSPResponse ::= SEQUENCE {
272 // responseStatus OCSPResponseStatus,
273 // responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
274 struct OCSPResponse
{
275 SECItem response_status
;
276 // This indirection is needed because |response_bytes| is an optional
277 // component and we need a way to determine if it is missing.
278 ResponseBytes
* response_bytes
;
281 const SEC_ASN1Template kPointerToResponseBytesTemplate
[] = {
282 { SEC_ASN1_POINTER
, 0, kResponseBytesTemplate
}
285 const SEC_ASN1Template kOCSPResponseTemplate
[] = {
286 { SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(OCSPResponse
) },
287 { SEC_ASN1_ENUMERATED
, offsetof(OCSPResponse
, response_status
) },
288 { SEC_ASN1_OPTIONAL
| SEC_ASN1_EXPLICIT
| SEC_ASN1_CONSTRUCTED
|
289 SEC_ASN1_CONTEXT_SPECIFIC
| 0, offsetof(OCSPResponse
, response_bytes
),
290 kPointerToResponseBytesTemplate
},
294 // CertID ::= SEQUENCE {
295 // hashAlgorithm AlgorithmIdentifier,
296 // issuerNameHash OCTET STRING, -- Hash of Issuer's DN
297 // issuerKeyHash OCTET STRING, -- Hash of Issuers public key
298 // serialNumber CertificateSerialNumber }
300 SECAlgorithmID hash_algorithm
;
301 SECItem issuer_name_hash
;
302 SECItem issuer_key_hash
;
303 SECItem serial_number
;
306 const SEC_ASN1Template kCertIDTemplate
[] = {
307 { SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(CertID
) },
308 { SEC_ASN1_INLINE
| SEC_ASN1_XTRN
, offsetof(CertID
, hash_algorithm
),
309 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate
) },
310 { SEC_ASN1_OCTET_STRING
, offsetof(CertID
, issuer_name_hash
) },
311 { SEC_ASN1_OCTET_STRING
, offsetof(CertID
, issuer_key_hash
) },
312 { SEC_ASN1_INTEGER
, offsetof(CertID
, serial_number
) },
316 // SingleResponse ::= SEQUENCE {
318 // certStatus CertStatus,
319 // thisUpdate GeneralizedTime,
320 // nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
321 // singleExtensions [1] EXPLICIT Extensions OPTIONAL }
322 struct SingleResponse
{
324 // The following three fields are not used.
325 SECItem der_cert_status
;
328 CERTCertExtension
** single_extensions
;
331 const SEC_ASN1Template kSingleResponseTemplate
[] = {
332 { SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(SingleResponse
) },
333 { SEC_ASN1_INLINE
, offsetof(SingleResponse
, cert_id
), kCertIDTemplate
},
334 // Really a CHOICE but we make it an ANY because we don't care about the
335 // contents of this field.
336 // TODO(ekasper): use SEC_ASN1_CHOICE.
337 { SEC_ASN1_ANY
, offsetof(SingleResponse
, der_cert_status
) },
338 { SEC_ASN1_GENERALIZED_TIME
, offsetof(SingleResponse
, this_update
) },
339 { SEC_ASN1_OPTIONAL
| SEC_ASN1_EXPLICIT
|
340 SEC_ASN1_CONSTRUCTED
| SEC_ASN1_CONTEXT_SPECIFIC
| SEC_ASN1_XTRN
| 0,
341 offsetof(SingleResponse
, next_update
),
342 SEC_ASN1_SUB(SEC_GeneralizedTimeTemplate
) },
343 { SEC_ASN1_OPTIONAL
| SEC_ASN1_EXPLICIT
| SEC_ASN1_CONSTRUCTED
|
344 SEC_ASN1_CONTEXT_SPECIFIC
| SEC_ASN1_XTRN
| 1,
345 offsetof(SingleResponse
, single_extensions
),
346 SEC_ASN1_SUB(CERT_SequenceOfCertExtensionTemplate
) },
350 // ResponseData ::= SEQUENCE {
351 // version [0] EXPLICIT Version DEFAULT v1,
352 // responderID ResponderID,
353 // producedAt GeneralizedTime,
354 // responses SEQUENCE OF SingleResponse,
355 // responseExtensions [1] EXPLICIT Extensions OPTIONAL }
356 struct ResponseData
{
357 // The first three fields are not used.
359 SECItem der_responder_id
;
361 SingleResponse
** single_responses
;
365 const SEC_ASN1Template kResponseDataTemplate
[] = {
366 { SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(ResponseData
) },
367 { SEC_ASN1_OPTIONAL
| SEC_ASN1_EXPLICIT
| SEC_ASN1_CONSTRUCTED
|
368 SEC_ASN1_CONTEXT_SPECIFIC
| SEC_ASN1_XTRN
| 0,
369 offsetof(ResponseData
, version
), SEC_ASN1_SUB(SEC_IntegerTemplate
) },
370 // Really a CHOICE but we make it an ANY because we don't care about the
371 // contents of this field.
372 // TODO(ekasper): use SEC_ASN1_CHOICE.
373 { SEC_ASN1_ANY
, offsetof(ResponseData
, der_responder_id
) },
374 { SEC_ASN1_GENERALIZED_TIME
, offsetof(ResponseData
, produced_at
) },
375 { SEC_ASN1_SEQUENCE_OF
, offsetof(ResponseData
, single_responses
),
376 kSingleResponseTemplate
},
377 { SEC_ASN1_SKIP_REST
},
381 // BasicOCSPResponse ::= SEQUENCE {
382 // tbsResponseData ResponseData,
383 // signatureAlgorithm AlgorithmIdentifier,
384 // signature BIT STRING,
385 // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
386 struct BasicOCSPResponse
{
387 ResponseData tbs_response_data
;
388 // We do not care about the rest.
391 const SEC_ASN1Template kBasicOCSPResponseTemplate
[] = {
392 { SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(BasicOCSPResponse
) },
393 { SEC_ASN1_INLINE
, offsetof(BasicOCSPResponse
, tbs_response_data
),
394 kResponseDataTemplate
},
395 { SEC_ASN1_SKIP_REST
},
399 bool StringEqualToSECItem(const std::string
& value1
, const SECItem
& value2
) {
400 if (value1
.size() != value2
.len
)
402 return memcmp(value1
.data(), value2
.data
, value2
.len
) == 0;
405 // TODO(ekasper): also use the issuer name hash in matching.
406 bool CertIDMatches(const CertID
& cert_id
,
407 const std::string
& serial_number
,
408 const std::string
& issuer_key_sha1_hash
,
409 const std::string
& issuer_key_sha256_hash
) {
410 if (!StringEqualToSECItem(serial_number
, cert_id
.serial_number
))
413 SECOidTag hash_alg
= SECOID_FindOIDTag(&cert_id
.hash_algorithm
.algorithm
);
416 return StringEqualToSECItem(issuer_key_sha1_hash
,
417 cert_id
.issuer_key_hash
);
419 return StringEqualToSECItem(issuer_key_sha256_hash
,
420 cert_id
.issuer_key_hash
);
428 bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert
,
429 std::string
* sct_list
) {
432 NSSCertWrapper
leaf_cert(cert
);
436 return GetCertOctetStringExtension(leaf_cert
.cert
.get(),
437 g_ct_singleton
.Get().embedded_oid(),
441 bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf
,
442 X509Certificate::OSCertHandle issuer
,
447 NSSCertWrapper
leaf_cert(leaf
);
448 NSSCertWrapper
issuer_cert(issuer
);
451 // XXX(rsleevi): This check may be overkill, since we should be able to
452 // generate precerts for certs without the extension. For now, just a sanity
453 // check to match the reference implementation.
455 SECStatus rv
= CERT_FindCertExtension(
456 leaf_cert
.cert
.get(), g_ct_singleton
.Get().embedded_oid(), &extension
);
457 if (rv
!= SECSuccess
)
459 SECITEM_FreeItem(&extension
, PR_FALSE
);
461 std::string to_be_signed
;
462 if (!ExtractTBSCertWithoutSCTs(leaf_cert
.cert
.get(), &to_be_signed
))
465 if (!issuer_cert
.cert
) {
466 // This can happen when the issuer and leaf certs share the same serial
467 // number and are from the same CA, which should never be the case
468 // (but happened with bad test certs).
469 VLOG(1) << "Issuer cert is null, cannot generate Precert entry.";
473 SECKEYPublicKey
* issuer_pub_key
=
474 SECKEY_ExtractPublicKey(&(issuer_cert
.cert
->subjectPublicKeyInfo
));
475 if (!issuer_pub_key
) {
476 VLOG(1) << "Could not extract issuer public key, "
477 << "cannot generate Precert entry.";
481 SECItem
* encoded_issuer_pubKey
=
482 SECKEY_EncodeDERSubjectPublicKeyInfo(issuer_pub_key
);
483 if (!encoded_issuer_pubKey
) {
484 SECKEY_DestroyPublicKey(issuer_pub_key
);
488 result
->type
= ct::LogEntry::LOG_ENTRY_TYPE_PRECERT
;
489 result
->tbs_certificate
.swap(to_be_signed
);
491 crypto::SHA256HashString(
492 base::StringPiece(reinterpret_cast<char*>(encoded_issuer_pubKey
->data
),
493 encoded_issuer_pubKey
->len
),
494 result
->issuer_key_hash
.data
,
495 sizeof(result
->issuer_key_hash
.data
));
497 SECITEM_FreeItem(encoded_issuer_pubKey
, PR_TRUE
);
498 SECKEY_DestroyPublicKey(issuer_pub_key
);
503 bool GetX509LogEntry(X509Certificate::OSCertHandle leaf
, LogEntry
* result
) {
507 if (!X509Certificate::GetDEREncoded(leaf
, &encoded
))
511 result
->type
= ct::LogEntry::LOG_ENTRY_TYPE_X509
;
512 result
->leaf_certificate
.swap(encoded
);
516 bool ExtractSCTListFromOCSPResponse(X509Certificate::OSCertHandle issuer
,
517 const std::string
& cert_serial_number
,
518 const std::string
& ocsp_response
,
519 std::string
* sct_list
) {
522 // Any OCSP response is unlikely to be even close to 2^24 bytes; further, CT
523 // only uses stapled OCSP responses which have this limit imposed by the TLS
525 if (ocsp_response
.size() > 0xffffff)
528 crypto::ScopedPLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
530 OCSPResponse response
;
531 memset(&response
, 0, sizeof(response
));
533 SECItem src
= { siBuffer
,
534 reinterpret_cast<unsigned char*>(const_cast<char*>(
535 ocsp_response
.data())),
536 static_cast<unsigned int>(ocsp_response
.size()) };
538 // |response| will point directly into |src|, so it's not necessary to
539 // free the |response| contents, but they may only be used while |src|
540 // is valid (i.e., in this method).
541 SECStatus rv
= SEC_QuickDERDecodeItem(arena
.get(), &response
,
542 kOCSPResponseTemplate
, &src
);
543 if (rv
!= SECSuccess
)
546 if (!response
.response_bytes
)
549 if (!SECITEM_ItemsAreEqual(&kBasicOCSPResponseOidItem
,
550 &response
.response_bytes
->response_type
)) {
554 BasicOCSPResponse basic_response
;
555 memset(&basic_response
, 0, sizeof(basic_response
));
557 rv
= SEC_QuickDERDecodeItem(arena
.get(), &basic_response
,
558 kBasicOCSPResponseTemplate
,
559 &response
.response_bytes
->der_response
);
560 if (rv
!= SECSuccess
)
563 SingleResponse
** responses
=
564 basic_response
.tbs_response_data
.single_responses
;
568 std::string issuer_der
;
569 if (!X509Certificate::GetDEREncoded(issuer
, &issuer_der
))
572 base::StringPiece issuer_spki
;
573 if (!asn1::ExtractSPKIFromDERCert(issuer_der
, &issuer_spki
))
576 // In OCSP, only the key itself is under hash.
577 base::StringPiece issuer_spk
;
578 if (!asn1::ExtractSubjectPublicKeyFromSPKI(issuer_spki
, &issuer_spk
))
581 // ExtractSubjectPublicKey... does not remove the initial octet encoding the
582 // number of unused bits in the ASN.1 BIT STRING so we do it here. For public
583 // keys, the bitstring is in practice always byte-aligned.
584 if (issuer_spk
.empty() || issuer_spk
[0] != 0)
586 issuer_spk
.remove_prefix(1);
588 // NSS OCSP lib recognizes SHA1, MD5 and MD2; MD5 and MD2 are dead but
589 // https://bugzilla.mozilla.org/show_bug.cgi?id=663315 will add SHA-256
591 // TODO(ekasper): add SHA-384 to crypto/sha2.h and here if it proves
593 // TODO(ekasper): only compute the hashes on demand.
594 std::string issuer_key_sha256_hash
= crypto::SHA256HashString(issuer_spk
);
595 std::string issuer_key_sha1_hash
= base::SHA1HashString(
596 issuer_spk
.as_string());
598 const SingleResponse
* match
= NULL
;
599 for (const SingleResponse
* const* resps
= responses
; *resps
; ++resps
) {
600 const SingleResponse
* resp
= *resps
;
601 if (CertIDMatches(resp
->cert_id
, cert_serial_number
,
602 issuer_key_sha1_hash
, issuer_key_sha256_hash
)) {
611 return GetSCTListFromOCSPExtension(arena
.get(), match
->single_extensions
,