Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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/ct_objects_extractor.h" | 5 #include "net/cert/ct_objects_extractor.h" |
| 6 | 6 |
| 7 #include <string.h> | 7 #include <string.h> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/sha1.h" | 10 #include "base/sha1.h" |
| 11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
| 12 #include "crypto/sha2.h" | 12 #include "crypto/sha2.h" |
| 13 #include "net/cert/asn1_util.h" | 13 #include "net/cert/asn1_util.h" |
| 14 #include "net/cert/signed_certificate_timestamp.h" | 14 #include "net/cert/signed_certificate_timestamp.h" |
| 15 #include "third_party/boringssl/src/include/openssl/bytestring.h" | 15 #include "third_party/boringssl/src/include/openssl/bytestring.h" |
| 16 #include "third_party/boringssl/src/include/openssl/obj.h" | 16 #include "third_party/boringssl/src/include/openssl/mem.h" |
| 17 #include "third_party/boringssl/src/include/openssl/x509.h" | |
| 18 | 17 |
| 19 namespace net { | 18 namespace net { |
| 20 | 19 |
| 21 namespace ct { | 20 namespace ct { |
| 22 | 21 |
| 23 namespace { | 22 namespace { |
| 24 | 23 |
| 25 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of | 24 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of |
| 26 // RFC6962. | 25 // RFC6962. |
| 27 const uint8_t kEmbeddedSCTOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01, | 26 const uint8_t kEmbeddedSCTOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01, |
| 28 0xD6, 0x79, 0x02, 0x04, 0x02}; | 27 0xD6, 0x79, 0x02, 0x04, 0x02}; |
| 29 | 28 |
| 30 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.5 - OCSP SingleExtension for | 29 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.5 - OCSP SingleExtension for |
| 31 // X.509v3 Certificate Transparency Signed Certificate Timestamp List, see | 30 // X.509v3 Certificate Transparency Signed Certificate Timestamp List, see |
| 32 // Section 3.3 of RFC6962. | 31 // Section 3.3 of RFC6962. |
| 33 const uint8_t kOCSPExtensionOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01, | 32 const uint8_t kOCSPExtensionOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01, |
| 34 0xD6, 0x79, 0x02, 0x04, 0x05}; | 33 0xD6, 0x79, 0x02, 0x04, 0x05}; |
| 35 | 34 |
| 35 // The wire form of the OID 1.3.6.1.5.5.7.48.1.1. See RFC 6960. | |
| 36 const uint8_t kOCSPBasicResponseOid[] = {0x2b, 0x06, 0x01, 0x05, 0x05, | |
| 37 0x07, 0x30, 0x01, 0x01}; | |
| 38 | |
| 39 // The wire form of the OID 1.3.14.3.2.26. | |
| 40 const uint8_t kSHA1Oid[] = {0x2b, 0x0e, 0x03, 0x02, 0x1a}; | |
| 41 | |
| 42 // The wire form of the OID 2.16.840.1.101.3.4.2.1. | |
| 43 const uint8_t kSHA256Oid[] = {0x60, 0x86, 0x48, 0x01, 0x65, | |
| 44 0x03, 0x04, 0x02, 0x01}; | |
| 45 | |
| 36 bool StringEqualToCBS(const std::string& value1, const CBS* value2) { | 46 bool StringEqualToCBS(const std::string& value1, const CBS* value2) { |
| 37 if (CBS_len(value2) != value1.size()) | 47 if (CBS_len(value2) != value1.size()) |
| 38 return false; | 48 return false; |
| 39 return memcmp(value1.data(), CBS_data(value2), CBS_len(value2)) == 0; | 49 return memcmp(value1.data(), CBS_data(value2), CBS_len(value2)) == 0; |
| 40 } | 50 } |
| 41 | 51 |
| 42 bssl::UniquePtr<X509> OSCertHandleToOpenSSL( | 52 bool SkipElements(CBS* cbs, int count) { |
| 43 X509Certificate::OSCertHandle os_handle) { | 53 for (int i = 0; i < count; i++) { |
| 44 #if defined(USE_OPENSSL_CERTS) | 54 if (!CBS_get_any_asn1_element(cbs, nullptr, nullptr, nullptr)) |
| 45 return bssl::UniquePtr<X509>(X509Certificate::DupOSCertHandle(os_handle)); | 55 return false; |
| 46 #else | 56 } |
| 47 std::string der_encoded; | 57 return true; |
| 48 if (!X509Certificate::GetDEREncoded(os_handle, &der_encoded)) | 58 } |
| 49 return bssl::UniquePtr<X509>(); | 59 |
| 50 const uint8_t* bytes = reinterpret_cast<const uint8_t*>(der_encoded.data()); | 60 bool SkipOptionalElement(CBS* cbs, unsigned tag) { |
| 51 return bssl::UniquePtr<X509>(d2i_X509(NULL, &bytes, der_encoded.size())); | 61 CBS unused; |
| 52 #endif | 62 return !CBS_peek_asn1_tag(cbs, tag) || CBS_get_asn1(cbs, &unused, tag); |
| 63 } | |
| 64 | |
| 65 // Copies all the bytes in |outer| which are before |inner| to |out|. |inner| | |
| 66 // must be a subset of |outer|. | |
| 67 bool CopyBefore(const CBS& outer, const CBS& inner, CBB* out) { | |
| 68 CHECK_LE(CBS_data(&outer), CBS_data(&inner)); | |
| 69 CHECK_LE(CBS_data(&inner) + CBS_len(&inner), | |
| 70 CBS_data(&outer) + CBS_len(&outer)); | |
| 71 | |
| 72 return !!CBB_add_bytes(out, CBS_data(&outer), | |
| 73 CBS_data(&inner) - CBS_data(&outer)); | |
| 74 } | |
| 75 | |
| 76 // Copies all the bytes in |outer| which are after |inner| to |out|. |inner| | |
| 77 // must be a subset of |outer|. | |
| 78 bool CopyAfter(const CBS& outer, const CBS& inner, CBB* out) { | |
| 79 CHECK_LE(CBS_data(&outer), CBS_data(&inner)); | |
| 80 CHECK_LE(CBS_data(&inner) + CBS_len(&inner), | |
| 81 CBS_data(&outer) + CBS_len(&outer)); | |
| 82 | |
| 83 return !!CBB_add_bytes( | |
| 84 out, CBS_data(&inner) + CBS_len(&inner), | |
| 85 CBS_data(&outer) + CBS_len(&outer) - CBS_data(&inner) - CBS_len(&inner)); | |
| 86 } | |
| 87 | |
| 88 // Skips |tbs_cert|, which must be a TBSCertificate body, to just before the | |
| 89 // extensions element. | |
| 90 bool SkipTBSCertificateToExtensions(CBS* tbs_cert) { | |
| 91 constexpr unsigned kVersionTag = | |
| 92 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0; | |
| 93 constexpr unsigned kIssuerUniqueIDTag = | |
| 94 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1; | |
| 95 constexpr unsigned kSubjectUniqueIDTag = | |
| 96 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 2; | |
| 97 return SkipOptionalElement(tbs_cert, kVersionTag) && | |
| 98 SkipElements(tbs_cert, | |
| 99 6 /* serialNumber through subjectPublicKeyInfo */) && | |
| 100 SkipOptionalElement(tbs_cert, kIssuerUniqueIDTag) && | |
| 101 SkipOptionalElement(tbs_cert, kSubjectUniqueIDTag); | |
| 102 } | |
| 103 | |
| 104 // Looks for the extension with the specified OID in |extensions|, which must | |
| 105 // contain the contents of a SEQUENCE of X.509 extension structures. If found, | |
| 106 // returns true and sets |*out| to the full extension element. | |
| 107 bool FindExtensionElement(const CBS& extensions, | |
| 108 const uint8_t* oid, | |
| 109 size_t oid_len, | |
| 110 CBS* out) { | |
| 111 CBS extensions_copy = extensions; | |
| 112 CBS result; | |
| 113 CBS_init(&result, nullptr, 0); | |
| 114 bool found = false; | |
| 115 while (CBS_len(&extensions_copy) > 0) { | |
| 116 CBS extension_element; | |
| 117 if (!CBS_get_asn1_element(&extensions_copy, &extension_element, | |
| 118 CBS_ASN1_SEQUENCE)) { | |
| 119 return false; | |
| 120 } | |
| 121 | |
| 122 CBS copy = extension_element; | |
| 123 CBS extension, extension_oid; | |
| 124 if (!CBS_get_asn1(©, &extension, CBS_ASN1_SEQUENCE) || | |
| 125 !CBS_get_asn1(&extension, &extension_oid, CBS_ASN1_OBJECT)) { | |
| 126 return false; | |
| 127 } | |
| 128 | |
| 129 if (CBS_mem_equal(&extension_oid, oid, oid_len)) { | |
| 130 if (found) | |
| 131 return false; | |
| 132 found = true; | |
| 133 result = extension_element; | |
| 134 } | |
| 135 } | |
| 136 if (!found) | |
| 137 return false; | |
| 138 | |
| 139 *out = result; | |
| 140 return true; | |
| 53 } | 141 } |
| 54 | 142 |
| 55 // Finds the SignedCertificateTimestampList in an extension with OID |oid| in | 143 // Finds the SignedCertificateTimestampList in an extension with OID |oid| in |
| 56 // |x509_exts|. If found, returns true and sets |*out_sct_list| to the encoded | 144 // |x509_exts|. If found, returns true and sets |*out_sct_list| to the encoded |
| 57 // SCT list. |out_sct_list| may be NULL. | 145 // SCT list. |
| 58 bool GetSCTListFromX509_EXTENSIONS(const X509_EXTENSIONS* x509_exts, | 146 bool ParseSCTListFromExtensions(const CBS& extensions, |
| 59 const uint8_t* oid, | 147 const uint8_t* oid, |
| 60 size_t oid_len, | 148 size_t oid_len, |
| 61 std::string* out_sct_list) { | 149 std::string* out_sct_list) { |
| 62 for (size_t i = 0; i < sk_X509_EXTENSION_num(x509_exts); i++) { | 150 CBS extension_element, extension, extension_oid, value, sct_list; |
| 63 X509_EXTENSION* x509_ext = sk_X509_EXTENSION_value(x509_exts, i); | 151 if (!FindExtensionElement(extensions, oid, oid_len, &extension_element) || |
| 64 if (static_cast<size_t>(x509_ext->object->length) == oid_len && | 152 !CBS_get_asn1(&extension_element, &extension, CBS_ASN1_SEQUENCE) || |
| 65 memcmp(x509_ext->object->data, oid, oid_len) == 0) { | 153 !CBS_get_asn1(&extension, &extension_oid, CBS_ASN1_OBJECT) || |
| 66 // The SCT list is an OCTET STRING inside the extension. | 154 // Skip the optional critical element. |
| 67 CBS ext_value, sct_list; | 155 !SkipOptionalElement(&extension, CBS_ASN1_BOOLEAN) || |
| 68 CBS_init(&ext_value, x509_ext->value->data, x509_ext->value->length); | 156 // The extension value is stored in an OCTET STRING. |
| 69 if (!CBS_get_asn1(&ext_value, &sct_list, CBS_ASN1_OCTETSTRING) || | 157 !CBS_get_asn1(&extension, &value, CBS_ASN1_OCTETSTRING) || |
| 70 CBS_len(&ext_value) != 0) { | 158 CBS_len(&extension) != 0 || |
| 71 return false; | 159 // The extension value itself is an OCTET STRING containing the |
| 72 } | 160 // serialized SCT list. |
| 73 if (out_sct_list) { | 161 !CBS_get_asn1(&value, &sct_list, CBS_ASN1_OCTETSTRING) || |
| 74 *out_sct_list = | 162 CBS_len(&value) != 0) { |
| 75 std::string(reinterpret_cast<const char*>(CBS_data(&sct_list)), | 163 return false; |
| 76 CBS_len(&sct_list)); | |
| 77 } | |
| 78 return true; | |
| 79 } | |
| 80 } | 164 } |
| 81 return false; | 165 |
| 166 DCHECK(CBS_mem_equal(&extension_oid, oid, oid_len)); | |
| 167 *out_sct_list = std::string( | |
| 168 reinterpret_cast<const char*>(CBS_data(&sct_list)), CBS_len(&sct_list)); | |
| 169 return true; | |
| 82 } | 170 } |
| 83 | 171 |
| 84 // Finds the SingleResponse in |responses| which matches |issuer| and | 172 // Finds the SingleResponse in |responses| which matches |issuer| and |
| 85 // |cert_serial_number|. On success, returns true and sets | 173 // |cert_serial_number|. On success, returns true and sets |
| 86 // |*out_single_response| to the body of the SingleResponse starting at the | 174 // |*out_single_response| to the body of the SingleResponse starting at the |
| 87 // |certStatus| field. | 175 // |certStatus| field. |
| 88 bool FindMatchingSingleResponse(CBS* responses, | 176 bool FindMatchingSingleResponse(CBS* responses, |
| 89 X509Certificate::OSCertHandle issuer, | 177 X509Certificate::OSCertHandle issuer, |
| 90 const std::string& cert_serial_number, | 178 const std::string& cert_serial_number, |
| 91 CBS* out_single_response) { | 179 CBS* out_single_response) { |
| 92 std::string issuer_der; | 180 std::string issuer_der; |
| 93 if (!X509Certificate::GetDEREncoded(issuer, &issuer_der)) | 181 if (!X509Certificate::GetDEREncoded(issuer, &issuer_der)) |
| 94 return false; | 182 return false; |
| 95 | 183 |
| 96 base::StringPiece issuer_spki; | 184 base::StringPiece issuer_spki; |
| 97 if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_spki)) | 185 if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_spki)) |
| 98 return false; | 186 return false; |
| 99 | 187 |
| 100 // In OCSP, only the key itself is under hash. | 188 // In OCSP, only the key itself is under hash. |
| 101 base::StringPiece issuer_spk; | 189 base::StringPiece issuer_spk; |
| 102 if (!asn1::ExtractSubjectPublicKeyFromSPKI(issuer_spki, &issuer_spk)) | 190 if (!asn1::ExtractSubjectPublicKeyFromSPKI(issuer_spki, &issuer_spk)) |
| 103 return false; | 191 return false; |
| 104 | 192 |
| 105 // ExtractSubjectPublicKey... does not remove the initial octet encoding the | 193 // ExtractSubjectPublicKeyFromSPKI does not remove the initial octet encoding |
| 106 // number of unused bits in the ASN.1 BIT STRING so we do it here. For public | 194 // the number of unused bits in the ASN.1 BIT STRING so we do it here. For |
| 107 // keys, the bitstring is in practice always byte-aligned. | 195 // public keys, the bitstring is in practice always byte-aligned. |
| 108 if (issuer_spk.empty() || issuer_spk[0] != 0) | 196 if (issuer_spk.empty() || issuer_spk[0] != 0) |
| 109 return false; | 197 return false; |
| 110 issuer_spk.remove_prefix(1); | 198 issuer_spk.remove_prefix(1); |
| 111 | 199 |
| 112 // TODO(ekasper): add SHA-384 to crypto/sha2.h and here if it proves | 200 // TODO(ekasper): add SHA-384 to crypto/sha2.h and here if it proves |
| 113 // necessary. | 201 // necessary. |
| 114 // TODO(ekasper): only compute the hashes on demand. | 202 // TODO(ekasper): only compute the hashes on demand. |
| 115 std::string issuer_key_sha256_hash = crypto::SHA256HashString(issuer_spk); | 203 std::string issuer_key_sha256_hash = crypto::SHA256HashString(issuer_spk); |
| 116 std::string issuer_key_sha1_hash = | 204 std::string issuer_key_sha1_hash = |
| 117 base::SHA1HashString(issuer_spk.as_string()); | 205 base::SHA1HashString(issuer_spk.as_string()); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 132 CBS_len(&cert_id) != 0) { | 220 CBS_len(&cert_id) != 0) { |
| 133 return false; | 221 return false; |
| 134 } | 222 } |
| 135 | 223 |
| 136 // Check the serial number matches. | 224 // Check the serial number matches. |
| 137 if (!StringEqualToCBS(cert_serial_number, &serial_number)) | 225 if (!StringEqualToCBS(cert_serial_number, &serial_number)) |
| 138 continue; | 226 continue; |
| 139 | 227 |
| 140 // Check if the issuer_key_hash matches. | 228 // Check if the issuer_key_hash matches. |
| 141 // TODO(ekasper): also use the issuer name hash in matching. | 229 // TODO(ekasper): also use the issuer name hash in matching. |
| 142 switch (OBJ_cbs2nid(&hash)) { | 230 if (CBS_mem_equal(&hash, kSHA1Oid, sizeof(kSHA1Oid))) { |
| 143 case NID_sha1: | 231 if (StringEqualToCBS(issuer_key_sha1_hash, &issuer_key_hash)) { |
| 144 if (StringEqualToCBS(issuer_key_sha1_hash, &issuer_key_hash)) { | 232 *out_single_response = single_response; |
| 145 *out_single_response = single_response; | 233 return true; |
| 146 return true; | 234 } |
| 147 } | 235 } else if (CBS_mem_equal(&hash, kSHA256Oid, sizeof(kSHA256Oid))) { |
| 148 break; | 236 if (StringEqualToCBS(issuer_key_sha256_hash, &issuer_key_hash)) { |
| 149 case NID_sha256: | 237 *out_single_response = single_response; |
| 150 if (StringEqualToCBS(issuer_key_sha256_hash, &issuer_key_hash)) { | 238 return true; |
| 151 *out_single_response = single_response; | 239 } |
| 152 return true; | |
| 153 } | |
| 154 break; | |
| 155 } | 240 } |
| 156 } | 241 } |
| 157 | 242 |
| 158 return false; | 243 return false; |
| 159 } | 244 } |
| 160 | 245 |
| 161 } // namespace | 246 } // namespace |
| 162 | 247 |
| 163 bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert, | 248 bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert, |
| 164 std::string* sct_list) { | 249 std::string* sct_list) { |
| 165 bssl::UniquePtr<X509> x509(OSCertHandleToOpenSSL(cert)); | 250 std::string der; |
| 166 if (!x509) | 251 if (!X509Certificate::GetDEREncoded(cert, &der)) |
| 167 return false; | 252 return false; |
| 168 X509_EXTENSIONS* x509_exts = x509->cert_info->extensions; | 253 CBS cert_cbs; |
| 169 if (!x509_exts) | 254 CBS_init(&cert_cbs, reinterpret_cast<const uint8_t*>(der.data()), der.size()); |
| 255 CBS cert_body, tbs_cert, extensions_wrap, extensions; | |
| 256 if (!CBS_get_asn1(&cert_cbs, &cert_body, CBS_ASN1_SEQUENCE) || | |
| 257 CBS_len(&cert_cbs) != 0 || | |
| 258 !CBS_get_asn1(&cert_body, &tbs_cert, CBS_ASN1_SEQUENCE) || | |
| 259 !SkipTBSCertificateToExtensions(&tbs_cert) || | |
| 260 // Extract the extensions list. | |
| 261 !CBS_get_asn1(&tbs_cert, &extensions_wrap, | |
| 262 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 3) || | |
| 263 !CBS_get_asn1(&extensions_wrap, &extensions, CBS_ASN1_SEQUENCE) || | |
| 264 CBS_len(&extensions_wrap) != 0 || CBS_len(&tbs_cert) != 0) { | |
| 170 return false; | 265 return false; |
| 171 return GetSCTListFromX509_EXTENSIONS(x509->cert_info->extensions, | 266 } |
| 172 kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid), | 267 |
| 173 sct_list); | 268 return ParseSCTListFromExtensions(extensions, kEmbeddedSCTOid, |
| 269 sizeof(kEmbeddedSCTOid), sct_list); | |
| 174 } | 270 } |
| 175 | 271 |
| 176 bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf, | 272 bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf, |
| 177 X509Certificate::OSCertHandle issuer, | 273 X509Certificate::OSCertHandle issuer, |
| 178 LogEntry* result) { | 274 LogEntry* result) { |
| 179 result->Reset(); | 275 result->Reset(); |
| 180 | 276 |
| 181 bssl::UniquePtr<X509> leaf_x509(OSCertHandleToOpenSSL(leaf)); | 277 std::string leaf_der; |
| 182 if (!leaf_x509) | 278 if (!X509Certificate::GetDEREncoded(leaf, &leaf_der)) |
| 183 return false; | 279 return false; |
| 184 | 280 CBS cert_cbs; |
| 185 // XXX(rsleevi): This check may be overkill, since we should be able to | 281 CBS_init(&cert_cbs, reinterpret_cast<const uint8_t*>(leaf_der.data()), |
| 186 // generate precerts for certs without the extension. For now, just a sanity | 282 leaf_der.size()); |
| 187 // check to match the reference implementation. | 283 CBS cert_body, tbs_cert; |
|
mattm
2017/04/18 03:07:56
Should this comment be retained?
davidben
2017/04/22 05:51:22
I'm not sure it's possible for it to matter, but I
| |
| 188 if (!leaf_x509->cert_info->extensions || | 284 if (!CBS_get_asn1(&cert_cbs, &cert_body, CBS_ASN1_SEQUENCE) || |
| 189 !GetSCTListFromX509_EXTENSIONS(leaf_x509->cert_info->extensions, | 285 CBS_len(&cert_cbs) != 0 || |
| 190 kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid), | 286 !CBS_get_asn1(&cert_body, &tbs_cert, CBS_ASN1_SEQUENCE)) { |
| 191 NULL)) { | |
| 192 return false; | 287 return false; |
| 193 } | 288 } |
| 194 | 289 |
| 195 // The Precertificate log entry is the final certificate's TBSCertificate | 290 // Copy everything up to the extensions to the output. |
| 196 // without the SCT extension (RFC6962, section 3.2). | 291 CBS tbs_cert_copy = tbs_cert; |
| 197 bssl::UniquePtr<X509> leaf_copy(X509_dup(leaf_x509.get())); | 292 bssl::ScopedCBB cbb; |
| 198 if (!leaf_copy || !leaf_copy->cert_info->extensions) { | 293 CBB tbs_cert_cbb; |
|
mattm
2017/04/18 03:07:56
I found this function to be a bit hard to follow.
davidben
2017/04/22 05:51:22
The ones that end in _cbb are the ones being gener
| |
| 199 NOTREACHED(); | 294 if (!CBB_init(cbb.get(), CBS_len(&tbs_cert)) || |
| 295 !CBB_add_asn1(cbb.get(), &tbs_cert_cbb, CBS_ASN1_SEQUENCE) || | |
| 296 !SkipTBSCertificateToExtensions(&tbs_cert) || | |
| 297 !CopyBefore(tbs_cert_copy, tbs_cert, &tbs_cert_cbb)) { | |
| 200 return false; | 298 return false; |
| 201 } | 299 } |
| 202 X509_EXTENSIONS* leaf_copy_exts = leaf_copy->cert_info->extensions; | 300 |
| 203 for (size_t i = 0; i < sk_X509_EXTENSION_num(leaf_copy_exts); i++) { | 301 // Extract and mirror the extensions list. |
| 204 X509_EXTENSION* ext = sk_X509_EXTENSION_value(leaf_copy_exts, i); | 302 constexpr unsigned kExtensionsTag = |
| 205 if (static_cast<size_t>(ext->object->length) == sizeof(kEmbeddedSCTOid) && | 303 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 3; |
| 206 memcmp(ext->object->data, kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid)) == | 304 CBS extensions_wrap, extensions; |
| 207 0) { | 305 CBB extensions_wrap_cbb, extensions_cbb; |
| 208 X509_EXTENSION_free(sk_X509_EXTENSION_delete(leaf_copy_exts, i)); | 306 if (!CBS_get_asn1(&tbs_cert, &extensions_wrap, kExtensionsTag) || |
| 209 X509_CINF_set_modified(leaf_copy->cert_info); | 307 !CBS_get_asn1(&extensions_wrap, &extensions, CBS_ASN1_SEQUENCE) || |
| 210 break; | 308 CBS_len(&extensions_wrap) != 0 || CBS_len(&tbs_cert) != 0 || |
| 211 } | 309 !CBB_add_asn1(&tbs_cert_cbb, &extensions_wrap_cbb, kExtensionsTag) || |
| 310 !CBB_add_asn1(&extensions_wrap_cbb, &extensions_cbb, CBS_ASN1_SEQUENCE)) { | |
| 311 return false; | |
| 212 } | 312 } |
| 213 | 313 |
| 214 std::string to_be_signed; | 314 // Copy all extensions except the embedded SCT extension. |
| 215 int len = i2d_X509_CINF(leaf_copy->cert_info, NULL); | 315 CBS sct_extension; |
| 216 if (len < 0) | 316 if (!FindExtensionElement(extensions, kEmbeddedSCTOid, |
| 317 sizeof(kEmbeddedSCTOid), &sct_extension) || | |
| 318 !CopyBefore(extensions, sct_extension, &extensions_cbb) || | |
| 319 !CopyAfter(extensions, sct_extension, &extensions_cbb)) { | |
| 217 return false; | 320 return false; |
| 218 uint8_t* ptr = | 321 } |
| 219 reinterpret_cast<uint8_t*>(base::WriteInto(&to_be_signed, len + 1)); | 322 |
| 220 if (i2d_X509_CINF(leaf_copy->cert_info, &ptr) < 0) | 323 uint8_t* new_tbs_cert; |
| 324 size_t new_tbs_cert_len; | |
| 325 if (!CBB_finish(cbb.get(), &new_tbs_cert, &new_tbs_cert_len)) | |
| 221 return false; | 326 return false; |
| 327 bssl::UniquePtr<uint8_t> scoped_new_tbs_cert(new_tbs_cert); | |
| 222 | 328 |
| 223 // Extract the issuer's public key. | 329 // Extract the issuer's public key. |
| 224 std::string issuer_der; | 330 std::string issuer_der; |
| 225 if (!X509Certificate::GetDEREncoded(issuer, &issuer_der)) | 331 if (!X509Certificate::GetDEREncoded(issuer, &issuer_der)) |
| 226 return false; | 332 return false; |
| 227 base::StringPiece issuer_key; | 333 base::StringPiece issuer_key; |
| 228 if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_key)) | 334 if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_key)) |
| 229 return false; | 335 return false; |
| 230 | 336 |
| 231 // Fill in the LogEntry. | 337 // Fill in the LogEntry. |
| 232 result->type = ct::LogEntry::LOG_ENTRY_TYPE_PRECERT; | 338 result->type = ct::LogEntry::LOG_ENTRY_TYPE_PRECERT; |
| 233 result->tbs_certificate.swap(to_be_signed); | 339 result->tbs_certificate.assign(reinterpret_cast<const char*>(new_tbs_cert), |
| 340 new_tbs_cert_len); | |
| 234 crypto::SHA256HashString(issuer_key, result->issuer_key_hash.data, | 341 crypto::SHA256HashString(issuer_key, result->issuer_key_hash.data, |
| 235 sizeof(result->issuer_key_hash.data)); | 342 sizeof(result->issuer_key_hash.data)); |
| 236 | 343 |
| 237 return true; | 344 return true; |
| 238 } | 345 } |
| 239 | 346 |
| 240 bool GetX509LogEntry(X509Certificate::OSCertHandle leaf, LogEntry* result) { | 347 bool GetX509LogEntry(X509Certificate::OSCertHandle leaf, LogEntry* result) { |
| 241 DCHECK(leaf); | 348 DCHECK(leaf); |
| 242 | 349 |
| 243 std::string encoded; | 350 std::string encoded; |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 256 std::string* sct_list) { | 363 std::string* sct_list) { |
| 257 // The input is an OCSPResponse. See RFC2560, section 4.2.1. The SCT list is | 364 // The input is an OCSPResponse. See RFC2560, section 4.2.1. The SCT list is |
| 258 // in the extensions field of the SingleResponse which matches the input | 365 // in the extensions field of the SingleResponse which matches the input |
| 259 // certificate. | 366 // certificate. |
| 260 CBS cbs; | 367 CBS cbs; |
| 261 CBS_init(&cbs, reinterpret_cast<const uint8_t*>(ocsp_response.data()), | 368 CBS_init(&cbs, reinterpret_cast<const uint8_t*>(ocsp_response.data()), |
| 262 ocsp_response.size()); | 369 ocsp_response.size()); |
| 263 | 370 |
| 264 // Parse down to the ResponseBytes. The ResponseBytes is optional, but if it's | 371 // Parse down to the ResponseBytes. The ResponseBytes is optional, but if it's |
| 265 // missing, this can't include an SCT list. | 372 // missing, this can't include an SCT list. |
| 266 CBS sequence, response_status, tagged_response_bytes, response_bytes; | 373 CBS sequence, tagged_response_bytes, response_bytes, response_type, response; |
| 267 CBS response_type, response; | |
| 268 if (!CBS_get_asn1(&cbs, &sequence, CBS_ASN1_SEQUENCE) || CBS_len(&cbs) != 0 || | 374 if (!CBS_get_asn1(&cbs, &sequence, CBS_ASN1_SEQUENCE) || CBS_len(&cbs) != 0 || |
| 269 !CBS_get_asn1(&sequence, &response_status, CBS_ASN1_ENUMERATED) || | 375 !SkipElements(&sequence, 1 /* responderStatus */) || |
|
mattm
2017/04/18 03:07:56
responseStatus
davidben
2017/04/22 05:51:22
Done.
| |
| 270 !CBS_get_asn1(&sequence, &tagged_response_bytes, | 376 !CBS_get_asn1(&sequence, &tagged_response_bytes, |
| 271 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || | 377 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || |
| 272 CBS_len(&sequence) != 0 || | 378 CBS_len(&sequence) != 0 || |
| 273 !CBS_get_asn1(&tagged_response_bytes, &response_bytes, | 379 !CBS_get_asn1(&tagged_response_bytes, &response_bytes, |
| 274 CBS_ASN1_SEQUENCE) || | 380 CBS_ASN1_SEQUENCE) || |
| 275 CBS_len(&tagged_response_bytes) != 0 || | 381 CBS_len(&tagged_response_bytes) != 0 || |
| 276 !CBS_get_asn1(&response_bytes, &response_type, CBS_ASN1_OBJECT) || | 382 !CBS_get_asn1(&response_bytes, &response_type, CBS_ASN1_OBJECT) || |
| 277 !CBS_get_asn1(&response_bytes, &response, CBS_ASN1_OCTETSTRING) || | 383 !CBS_get_asn1(&response_bytes, &response, CBS_ASN1_OCTETSTRING) || |
| 278 CBS_len(&response_bytes) != 0) { | 384 CBS_len(&response_bytes) != 0) { |
| 279 return false; | 385 return false; |
| 280 } | 386 } |
| 281 | 387 |
| 282 // The only relevant ResponseType is id-pkix-ocsp-basic. | 388 // The only relevant ResponseType is id-pkix-ocsp-basic. |
| 283 if (OBJ_cbs2nid(&response_type) != NID_id_pkix_OCSP_basic) | 389 if (!CBS_mem_equal(&response_type, kOCSPBasicResponseOid, |
| 390 sizeof(kOCSPBasicResponseOid))) { | |
| 284 return false; | 391 return false; |
| 392 } | |
| 285 | 393 |
| 286 // Parse the ResponseData out of the BasicOCSPResponse. Ignore the rest. | 394 // Parse the ResponseData out of the BasicOCSPResponse. Ignore the rest. |
| 395 constexpr unsigned kVersionTag = | |
| 396 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0; | |
| 287 CBS basic_response, response_data, responses; | 397 CBS basic_response, response_data, responses; |
| 288 if (!CBS_get_asn1(&response, &basic_response, CBS_ASN1_SEQUENCE) || | 398 if (!CBS_get_asn1(&response, &basic_response, CBS_ASN1_SEQUENCE) || |
| 289 CBS_len(&response) != 0 || | 399 CBS_len(&response) != 0 || |
| 290 !CBS_get_asn1(&basic_response, &response_data, CBS_ASN1_SEQUENCE)) { | 400 !CBS_get_asn1(&basic_response, &response_data, CBS_ASN1_SEQUENCE)) { |
| 291 } | |
| 292 | |
| 293 // Skip the optional version. | |
| 294 const int kVersionTag = CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0; | |
| 295 if (CBS_len(&response_data) > 0 && | |
| 296 CBS_data(&response_data)[0] == kVersionTag && | |
| 297 !CBS_get_asn1(&response_data, NULL /* version */, kVersionTag)) { | |
| 298 return false; | 401 return false; |
| 299 } | 402 } |
| 300 | 403 |
| 301 // Extract the list of SingleResponses. | 404 // Extract the list of SingleResponses from the ResponseData. |
| 302 if (!CBS_get_any_asn1_element(&response_data, NULL /* responderID */, NULL, | 405 if (!SkipOptionalElement(&response_data, kVersionTag) || |
| 303 NULL) || | 406 !SkipElements(&response_data, 2 /* responseID, producedAt */) || |
|
mattm
2017/04/18 03:07:56
responderID
davidben
2017/04/22 05:51:22
Done.
| |
| 304 !CBS_get_any_asn1_element(&response_data, NULL /* producedAt */, NULL, | |
| 305 NULL) || | |
| 306 !CBS_get_asn1(&response_data, &responses, CBS_ASN1_SEQUENCE)) { | 407 !CBS_get_asn1(&response_data, &responses, CBS_ASN1_SEQUENCE)) { |
| 307 return false; | 408 return false; |
| 308 } | 409 } |
| 309 | 410 |
| 310 CBS single_response; | 411 CBS single_response; |
| 311 if (!FindMatchingSingleResponse(&responses, issuer, cert_serial_number, | 412 if (!FindMatchingSingleResponse(&responses, issuer, cert_serial_number, |
| 312 &single_response)) { | 413 &single_response)) { |
| 313 return false; | 414 return false; |
| 314 } | 415 } |
| 315 | 416 |
| 316 // Skip the certStatus and thisUpdate fields. | 417 // Parse the extensions out of the SingleResponse. |
| 317 if (!CBS_get_any_asn1_element(&single_response, NULL /* certStatus */, NULL, | 418 constexpr unsigned kNextUpdateTag = |
| 318 NULL) || | 419 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0; |
| 319 !CBS_get_any_asn1_element(&single_response, NULL /* thisUpdate */, NULL, | 420 constexpr unsigned kSingleExtensionsTag = |
| 320 NULL)) { | 421 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1; |
| 422 CBS extensions_wrap, extensions; | |
| 423 if (!SkipElements(&single_response, 2 /* certStatus, thisUpdate */) || | |
| 424 !SkipOptionalElement(&single_response, kNextUpdateTag) || | |
| 425 !CBS_get_asn1(&single_response, &extensions_wrap, kSingleExtensionsTag) || | |
| 426 !CBS_get_asn1(&extensions_wrap, &extensions, CBS_ASN1_SEQUENCE) || | |
| 427 CBS_len(&extensions_wrap) != 0) { | |
| 321 return false; | 428 return false; |
| 322 } | 429 } |
| 323 | 430 |
| 324 const int kNextUpdateTag = | 431 return ParseSCTListFromExtensions(extensions, kOCSPExtensionOid, |
| 325 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0; | 432 sizeof(kOCSPExtensionOid), sct_list); |
| 326 const int kSingleExtensionsTag = | |
| 327 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1; | |
| 328 | |
| 329 // Skip the optional nextUpdate field. | |
| 330 if (CBS_len(&single_response) > 0 && | |
| 331 CBS_data(&single_response)[0] == kNextUpdateTag && | |
| 332 !CBS_get_asn1(&single_response, NULL /* nextUpdate */, kNextUpdateTag)) { | |
| 333 return false; | |
| 334 } | |
| 335 | |
| 336 CBS extensions; | |
| 337 if (!CBS_get_asn1(&single_response, &extensions, kSingleExtensionsTag)) | |
| 338 return false; | |
| 339 const uint8_t* ptr = CBS_data(&extensions); | |
| 340 bssl::UniquePtr<X509_EXTENSIONS> x509_exts( | |
| 341 d2i_X509_EXTENSIONS(NULL, &ptr, CBS_len(&extensions))); | |
| 342 if (!x509_exts || ptr != CBS_data(&extensions) + CBS_len(&extensions)) | |
| 343 return false; | |
| 344 | |
| 345 return GetSCTListFromX509_EXTENSIONS(x509_exts.get(), kOCSPExtensionOid, | |
| 346 sizeof(kOCSPExtensionOid), sct_list); | |
| 347 } | 433 } |
| 348 | 434 |
| 349 } // namespace ct | 435 } // namespace ct |
| 350 | 436 |
| 351 } // namespace net | 437 } // namespace net |
| OLD | NEW |