Home | History | Annotate | Download | only in cert
      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.
      4 
      5 #include "net/cert/ct_objects_extractor.h"
      6 
      7 #include <string.h>
      8 
      9 #include <openssl/bytestring.h>
     10 #include <openssl/obj.h>
     11 #include <openssl/x509.h>
     12 
     13 #include "base/logging.h"
     14 #include "base/sha1.h"
     15 #include "base/strings/string_util.h"
     16 #include "crypto/scoped_openssl_types.h"
     17 #include "crypto/sha2.h"
     18 #include "net/cert/asn1_util.h"
     19 #include "net/cert/signed_certificate_timestamp.h"
     20 
     21 namespace net {
     22 
     23 namespace ct {
     24 
     25 namespace {
     26 
     27 typedef crypto::ScopedOpenSSL<X509, X509_free>::Type ScopedX509;
     28 
     29 void FreeX509_EXTENSIONS(X509_EXTENSIONS* ptr) {
     30   sk_X509_EXTENSION_pop_free(ptr, X509_EXTENSION_free);
     31 }
     32 
     33 typedef crypto::ScopedOpenSSL<X509_EXTENSIONS, FreeX509_EXTENSIONS>::Type
     34     ScopedX509_EXTENSIONS;
     35 
     36 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of
     37 // RFC6962.
     38 const uint8_t kEmbeddedSCTOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0xD6, 0x79,
     39                                    0x02, 0x04, 0x02};
     40 
     41 // The wire form of the OID 1.3.6.1.4.1.11129.2.4.5 - OCSP SingleExtension for
     42 // X.509v3 Certificate Transparency Signed Certificate Timestamp List, see
     43 // Section 3.3 of RFC6962.
     44 const uint8_t kOCSPExtensionOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0xD6, 0x79,
     45                                      0x02, 0x04, 0x05};
     46 
     47 bool StringEqualToCBS(const std::string& value1, const CBS* value2) {
     48   if (CBS_len(value2) != value1.size())
     49     return false;
     50   return memcmp(value1.data(), CBS_data(value2), CBS_len(value2)) == 0;
     51 }
     52 
     53 ScopedX509 OSCertHandleToOpenSSL(X509Certificate::OSCertHandle os_handle) {
     54 #if defined(USE_OPENSSL_CERTS)
     55   return ScopedX509(X509Certificate::DupOSCertHandle(os_handle));
     56 #else
     57   std::string der_encoded;
     58   if (!X509Certificate::GetDEREncoded(os_handle, &der_encoded))
     59     return ScopedX509();
     60   const uint8_t* bytes = reinterpret_cast<const uint8_t*>(der_encoded.data());
     61   return ScopedX509(d2i_X509(NULL, &bytes, der_encoded.size()));
     62 #endif
     63 }
     64 
     65 // Finds the SignedCertificateTimestampList in an extension with OID |oid| in
     66 // |x509_exts|. If found, returns true and sets |*out_sct_list| to the encoded
     67 // SCT list. |out_sct_list| may be NULL.
     68 bool GetSCTListFromX509_EXTENSIONS(const X509_EXTENSIONS* x509_exts,
     69                                    const uint8_t* oid,
     70                                    size_t oid_len,
     71                                    std::string* out_sct_list) {
     72   for (size_t i = 0; i < sk_X509_EXTENSION_num(x509_exts); i++) {
     73     X509_EXTENSION* x509_ext = sk_X509_EXTENSION_value(x509_exts, i);
     74     if (static_cast<size_t>(x509_ext->object->length) == oid_len &&
     75         memcmp(x509_ext->object->data, oid, oid_len) == 0) {
     76       // The SCT list is an OCTET STRING inside the extension.
     77       CBS ext_value, sct_list;
     78       CBS_init(&ext_value, x509_ext->value->data, x509_ext->value->length);
     79       if (!CBS_get_asn1(&ext_value, &sct_list, CBS_ASN1_OCTETSTRING) ||
     80           CBS_len(&ext_value) != 0) {
     81         return false;
     82       }
     83       if (out_sct_list) {
     84         *out_sct_list = std::string(
     85             reinterpret_cast<const char*>(CBS_data(&sct_list)),
     86             CBS_len(&sct_list));
     87       }
     88       return true;
     89     }
     90   }
     91   return false;
     92 }
     93 
     94 // Finds the SingleResponse in |responses| which matches |issuer| and
     95 // |cert_serial_number|. On success, returns true and sets
     96 // |*out_single_response| to the body of the SingleResponse starting at the
     97 // |certStatus| field.
     98 bool FindMatchingSingleResponse(CBS* responses,
     99                                 X509Certificate::OSCertHandle issuer,
    100                                 const std::string& cert_serial_number,
    101                                 CBS* out_single_response) {
    102   std::string issuer_der;
    103   if (!X509Certificate::GetDEREncoded(issuer, &issuer_der))
    104     return false;
    105 
    106   base::StringPiece issuer_spki;
    107   if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_spki))
    108     return false;
    109 
    110   // In OCSP, only the key itself is under hash.
    111   base::StringPiece issuer_spk;
    112   if (!asn1::ExtractSubjectPublicKeyFromSPKI(issuer_spki, &issuer_spk))
    113     return false;
    114 
    115   // ExtractSubjectPublicKey... does not remove the initial octet encoding the
    116   // number of unused bits in the ASN.1 BIT STRING so we do it here. For public
    117   // keys, the bitstring is in practice always byte-aligned.
    118   if (issuer_spk.empty() || issuer_spk[0] != 0)
    119     return false;
    120   issuer_spk.remove_prefix(1);
    121 
    122   // TODO(ekasper): add SHA-384 to crypto/sha2.h and here if it proves
    123   // necessary.
    124   // TODO(ekasper): only compute the hashes on demand.
    125   std::string issuer_key_sha256_hash = crypto::SHA256HashString(issuer_spk);
    126   std::string issuer_key_sha1_hash = base::SHA1HashString(
    127       issuer_spk.as_string());
    128 
    129   while (CBS_len(responses) > 0) {
    130     CBS single_response, cert_id;
    131     if (!CBS_get_asn1(responses, &single_response, CBS_ASN1_SEQUENCE) ||
    132         !CBS_get_asn1(&single_response, &cert_id, CBS_ASN1_SEQUENCE)) {
    133       return false;
    134     }
    135 
    136     CBS hash_algorithm, hash, serial_number, issuer_name_hash, issuer_key_hash;
    137     if (!CBS_get_asn1(&cert_id, &hash_algorithm, CBS_ASN1_SEQUENCE) ||
    138         !CBS_get_asn1(&hash_algorithm, &hash, CBS_ASN1_OBJECT) ||
    139         !CBS_get_asn1(&cert_id, &issuer_name_hash, CBS_ASN1_OCTETSTRING) ||
    140         !CBS_get_asn1(&cert_id, &issuer_key_hash, CBS_ASN1_OCTETSTRING) ||
    141         !CBS_get_asn1(&cert_id, &serial_number, CBS_ASN1_INTEGER) ||
    142         CBS_len(&cert_id) != 0) {
    143       return false;
    144     }
    145 
    146     // Check the serial number matches.
    147     if (!StringEqualToCBS(cert_serial_number, &serial_number))
    148       continue;
    149 
    150     // Check if the issuer_key_hash matches.
    151     // TODO(ekasper): also use the issuer name hash in matching.
    152     switch (OBJ_cbs2nid(&hash)) {
    153       case NID_sha1:
    154         if (StringEqualToCBS(issuer_key_sha1_hash, &issuer_key_hash)) {
    155           *out_single_response = single_response;
    156           return true;
    157         }
    158         break;
    159       case NID_sha256:
    160         if (StringEqualToCBS(issuer_key_sha256_hash, &issuer_key_hash)) {
    161           *out_single_response = single_response;
    162           return true;
    163         }
    164         break;
    165     }
    166   }
    167 
    168   return false;
    169 }
    170 
    171 }  // namespace
    172 
    173 bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert,
    174                             std::string* sct_list) {
    175   ScopedX509 x509(OSCertHandleToOpenSSL(cert));
    176   if (!x509)
    177     return false;
    178   X509_EXTENSIONS* x509_exts = x509->cert_info->extensions;
    179   if (!x509_exts)
    180     return false;
    181   return GetSCTListFromX509_EXTENSIONS(
    182       x509->cert_info->extensions, kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid),
    183       sct_list);
    184 }
    185 
    186 bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf,
    187                         X509Certificate::OSCertHandle issuer,
    188                         LogEntry* result) {
    189   result->Reset();
    190 
    191   ScopedX509 leaf_x509(OSCertHandleToOpenSSL(leaf));
    192   if (!leaf_x509)
    193     return false;
    194 
    195   // XXX(rsleevi): This check may be overkill, since we should be able to
    196   // generate precerts for certs without the extension. For now, just a sanity
    197   // check to match the reference implementation.
    198   if (!leaf_x509->cert_info->extensions ||
    199       !GetSCTListFromX509_EXTENSIONS(leaf_x509->cert_info->extensions,
    200                                      kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid),
    201                                      NULL)) {
    202     return false;
    203   }
    204 
    205   // The Precertificate log entry is the final certificate's TBSCertificate
    206   // without the SCT extension (RFC6962, section 3.2).
    207   ScopedX509 leaf_copy(X509_dup(leaf_x509.get()));
    208   if (!leaf_copy || !leaf_copy->cert_info->extensions) {
    209     NOTREACHED();
    210     return false;
    211   }
    212   X509_EXTENSIONS* leaf_copy_exts = leaf_copy->cert_info->extensions;
    213   for (size_t i = 0; i < sk_X509_EXTENSION_num(leaf_copy_exts); i++) {
    214     X509_EXTENSION* ext = sk_X509_EXTENSION_value(leaf_copy_exts, i);
    215     if (static_cast<size_t>(ext->object->length) == sizeof(kEmbeddedSCTOid) &&
    216         memcmp(ext->object->data,
    217                kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid)) == 0) {
    218       X509_EXTENSION_free(sk_X509_EXTENSION_delete(leaf_copy_exts, i));
    219       X509_CINF_set_modified(leaf_copy->cert_info);
    220       break;
    221     }
    222   }
    223 
    224   std::string to_be_signed;
    225   int len = i2d_X509_CINF(leaf_copy->cert_info, NULL);
    226   if (len < 0)
    227     return false;
    228   uint8_t* ptr = reinterpret_cast<uint8_t*>(WriteInto(&to_be_signed, len + 1));
    229   if (i2d_X509_CINF(leaf_copy->cert_info, &ptr) < 0)
    230     return false;
    231 
    232   // Extract the issuer's public key.
    233   std::string issuer_der;
    234   if (!X509Certificate::GetDEREncoded(issuer, &issuer_der))
    235     return ScopedX509();
    236   base::StringPiece issuer_key;
    237   if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_key))
    238     return false;
    239 
    240   // Fill in the LogEntry.
    241   result->type = ct::LogEntry::LOG_ENTRY_TYPE_PRECERT;
    242   result->tbs_certificate.swap(to_be_signed);
    243   crypto::SHA256HashString(issuer_key,
    244                            result->issuer_key_hash.data,
    245                            sizeof(result->issuer_key_hash.data));
    246 
    247   return true;
    248 }
    249 
    250 bool GetX509LogEntry(X509Certificate::OSCertHandle leaf, LogEntry* result) {
    251   DCHECK(leaf);
    252 
    253   std::string encoded;
    254   if (!X509Certificate::GetDEREncoded(leaf, &encoded))
    255     return false;
    256 
    257   result->Reset();
    258   result->type = ct::LogEntry::LOG_ENTRY_TYPE_X509;
    259   result->leaf_certificate.swap(encoded);
    260   return true;
    261 }
    262 
    263 bool ExtractSCTListFromOCSPResponse(X509Certificate::OSCertHandle issuer,
    264                                     const std::string& cert_serial_number,
    265                                     const std::string& ocsp_response,
    266                                     std::string* sct_list) {
    267   // The input is an OCSPResponse. See RFC2560, section 4.2.1. The SCT list is
    268   // in the extensions field of the SingleResponse which matches the input
    269   // certificate.
    270   CBS cbs;
    271   CBS_init(&cbs,
    272            reinterpret_cast<const uint8_t*>(ocsp_response.data()),
    273            ocsp_response.size());
    274 
    275   // Parse down to the ResponseBytes. The ResponseBytes is optional, but if it's
    276   // missing, this can't include an SCT list.
    277   CBS sequence, response_status, tagged_response_bytes, response_bytes;
    278   CBS response_type, response;
    279   if (!CBS_get_asn1(&cbs, &sequence, CBS_ASN1_SEQUENCE) ||
    280       CBS_len(&cbs) != 0 ||
    281       !CBS_get_asn1(&sequence, &response_status, CBS_ASN1_ENUMERATED) ||
    282       !CBS_get_asn1(&sequence, &tagged_response_bytes,
    283                     CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
    284       CBS_len(&sequence) != 0 ||
    285       !CBS_get_asn1(&tagged_response_bytes, &response_bytes,
    286                     CBS_ASN1_SEQUENCE) ||
    287       CBS_len(&tagged_response_bytes) != 0 ||
    288       !CBS_get_asn1(&response_bytes, &response_type, CBS_ASN1_OBJECT) ||
    289       !CBS_get_asn1(&response_bytes, &response, CBS_ASN1_OCTETSTRING) ||
    290       CBS_len(&response_bytes) != 0) {
    291     return false;
    292   }
    293 
    294   // The only relevant ResponseType is id-pkix-ocsp-basic.
    295   if (OBJ_cbs2nid(&response_type) != NID_id_pkix_OCSP_basic)
    296     return false;
    297 
    298   // Parse the ResponseData out of the BasicOCSPResponse. Ignore the rest.
    299   CBS basic_response, response_data, responses;
    300   if (!CBS_get_asn1(&response, &basic_response, CBS_ASN1_SEQUENCE) ||
    301       CBS_len(&response) != 0 ||
    302       !CBS_get_asn1(&basic_response, &response_data, CBS_ASN1_SEQUENCE)) {
    303   }
    304 
    305   // Skip the optional version.
    306   const int kVersionTag =
    307       CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0;
    308   if (CBS_len(&response_data) > 0 &&
    309       CBS_data(&response_data)[0] == kVersionTag &&
    310       !CBS_get_asn1(&response_data, NULL /* version */, kVersionTag)) {
    311     return false;
    312   }
    313 
    314   // Extract the list of SingleResponses.
    315   if (!CBS_get_any_asn1_element(&response_data,
    316                                 NULL /* responderID */, NULL, NULL) ||
    317       !CBS_get_any_asn1_element(&response_data,
    318                                 NULL /* producedAt */, NULL, NULL) ||
    319       !CBS_get_asn1(&response_data, &responses, CBS_ASN1_SEQUENCE)) {
    320     return false;
    321   }
    322 
    323   CBS single_response;
    324   if (!FindMatchingSingleResponse(&responses, issuer, cert_serial_number,
    325                                   &single_response)) {
    326     return false;
    327   }
    328 
    329   // Skip the certStatus and thisUpdate fields.
    330   if (!CBS_get_any_asn1_element(&single_response,
    331                                 NULL /* certStatus */, NULL, NULL) ||
    332       !CBS_get_any_asn1_element(&single_response,
    333                                 NULL /* thisUpdate */, NULL, NULL)) {
    334     return false;
    335   }
    336 
    337   const int kNextUpdateTag =
    338       CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0;
    339   const int kSingleExtensionsTag =
    340       CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1;
    341 
    342   // Skip the optional nextUpdate field.
    343   if (CBS_len(&single_response) > 0 &&
    344       CBS_data(&single_response)[0] == kNextUpdateTag &&
    345       !CBS_get_asn1(&single_response, NULL /* nextUpdate */, kNextUpdateTag)) {
    346     return false;
    347   }
    348 
    349   CBS extensions;
    350   if (!CBS_get_asn1(&single_response, &extensions, kSingleExtensionsTag))
    351     return false;
    352   const uint8_t* ptr = CBS_data(&extensions);
    353   ScopedX509_EXTENSIONS x509_exts(
    354       d2i_X509_EXTENSIONS(NULL, &ptr, CBS_len(&extensions)));
    355   if (!x509_exts || ptr != CBS_data(&extensions) + CBS_len(&extensions))
    356     return false;
    357 
    358   return GetSCTListFromX509_EXTENSIONS(
    359       x509_exts.get(), kOCSPExtensionOid, sizeof(kOCSPExtensionOid), sct_list);
    360 }
    361 
    362 }  // namespace ct
    363 
    364 }  // namespace net
    365