Home | History | Annotate | Download | only in net
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/common/net/x509_certificate_model.h"
      6 
      7 #include <cert.h>
      8 #include <cms.h>
      9 #include <hasht.h>
     10 #include <keyhi.h>  // SECKEY_DestroyPrivateKey
     11 #include <keythi.h>  // SECKEYPrivateKey
     12 #include <pk11pub.h>  // PK11_FindKeyByAnyCert
     13 #include <seccomon.h>  // SECItem
     14 #include <sechash.h>
     15 
     16 #include "base/logging.h"
     17 #include "base/strings/string_number_conversions.h"
     18 #include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h"
     19 #include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h"
     20 #include "chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h"
     21 #include "crypto/nss_util.h"
     22 #include "crypto/scoped_nss_types.h"
     23 #include "net/cert/x509_certificate.h"
     24 
     25 namespace psm = mozilla_security_manager;
     26 
     27 namespace {
     28 
     29 // Convert a char* return value from NSS into a std::string and free the NSS
     30 // memory.  If the arg is NULL, an empty string will be returned instead.
     31 std::string Stringize(char* nss_text, const std::string& alternative_text) {
     32   if (!nss_text)
     33     return alternative_text;
     34 
     35   std::string s = nss_text;
     36   PORT_Free(nss_text);
     37   return s;
     38 }
     39 
     40 // Hash a certificate using the given algorithm, return the result as a
     41 // colon-seperated hex string.  The len specified is the number of bytes
     42 // required for storing the raw fingerprint.
     43 // (It's a bit redundant that the caller needs to specify len in addition to the
     44 // algorithm, but given the limited uses, not worth fixing.)
     45 std::string HashCert(CERTCertificate* cert, HASH_HashType algorithm, int len) {
     46   unsigned char fingerprint[HASH_LENGTH_MAX];
     47 
     48   DCHECK(NULL != cert->derCert.data);
     49   DCHECK_NE(0U, cert->derCert.len);
     50   DCHECK_LE(len, HASH_LENGTH_MAX);
     51   memset(fingerprint, 0, len);
     52   SECStatus rv = HASH_HashBuf(algorithm, fingerprint, cert->derCert.data,
     53                               cert->derCert.len);
     54   DCHECK_EQ(rv, SECSuccess);
     55   return x509_certificate_model::ProcessRawBytes(fingerprint, len);
     56 }
     57 
     58 std::string ProcessSecAlgorithmInternal(SECAlgorithmID* algorithm_id) {
     59   return psm::GetOIDText(&algorithm_id->algorithm);
     60 }
     61 
     62 std::string ProcessExtension(
     63     const std::string& critical_label,
     64     const std::string& non_critical_label,
     65     CERTCertExtension* extension) {
     66   std::string criticality =
     67       extension->critical.data && extension->critical.data[0] ?
     68           critical_label : non_critical_label;
     69   return criticality + "\n" + psm::ProcessExtensionData(extension);
     70 }
     71 
     72 std::string GetNickname(net::X509Certificate::OSCertHandle cert_handle) {
     73   std::string name;
     74   if (cert_handle->nickname) {
     75     name = cert_handle->nickname;
     76     // Hack copied from mozilla: Cut off text before first :, which seems to
     77     // just be the token name.
     78     size_t colon_pos = name.find(':');
     79     if (colon_pos != std::string::npos)
     80       name = name.substr(colon_pos + 1);
     81   }
     82   return name;
     83 }
     84 
     85 ////////////////////////////////////////////////////////////////////////////////
     86 // NSS certificate export functions.
     87 
     88 struct NSSCMSMessageDeleter {
     89   inline void operator()(NSSCMSMessage* x) const {
     90     NSS_CMSMessage_Destroy(x);
     91   }
     92 };
     93 typedef scoped_ptr<NSSCMSMessage, NSSCMSMessageDeleter> ScopedNSSCMSMessage;
     94 
     95 struct FreeNSSCMSSignedData {
     96   inline void operator()(NSSCMSSignedData* x) const {
     97     NSS_CMSSignedData_Destroy(x);
     98   }
     99 };
    100 typedef scoped_ptr<NSSCMSSignedData, FreeNSSCMSSignedData>
    101     ScopedNSSCMSSignedData;
    102 
    103 }  // namespace
    104 
    105 namespace x509_certificate_model {
    106 
    107 using net::X509Certificate;
    108 using std::string;
    109 
    110 string GetCertNameOrNickname(X509Certificate::OSCertHandle cert_handle) {
    111   string name = ProcessIDN(
    112       Stringize(CERT_GetCommonName(&cert_handle->subject), std::string()));
    113   if (!name.empty())
    114     return name;
    115   return GetNickname(cert_handle);
    116 }
    117 
    118 string GetTokenName(X509Certificate::OSCertHandle cert_handle) {
    119   return psm::GetCertTokenName(cert_handle);
    120 }
    121 
    122 string GetVersion(X509Certificate::OSCertHandle cert_handle) {
    123   // If the version field is omitted from the certificate, the default
    124   // value is v1(0).
    125   unsigned long version = 0;
    126   if (cert_handle->version.len == 0 ||
    127       SEC_ASN1DecodeInteger(&cert_handle->version, &version) == SECSuccess) {
    128     return base::UintToString(version + 1);
    129   }
    130   return std::string();
    131 }
    132 
    133 net::CertType GetType(X509Certificate::OSCertHandle cert_handle) {
    134     return psm::GetCertType(cert_handle);
    135 }
    136 
    137 void GetUsageStrings(X509Certificate::OSCertHandle cert_handle,
    138                      std::vector<string>* usages) {
    139   psm::GetCertUsageStrings(cert_handle, usages);
    140 }
    141 
    142 string GetSerialNumberHexified(X509Certificate::OSCertHandle cert_handle,
    143                                const string& alternative_text) {
    144   return Stringize(CERT_Hexify(&cert_handle->serialNumber, true),
    145                    alternative_text);
    146 }
    147 
    148 string GetIssuerCommonName(X509Certificate::OSCertHandle cert_handle,
    149                            const string& alternative_text) {
    150   return Stringize(CERT_GetCommonName(&cert_handle->issuer), alternative_text);
    151 }
    152 
    153 string GetIssuerOrgName(X509Certificate::OSCertHandle cert_handle,
    154                         const string& alternative_text) {
    155   return Stringize(CERT_GetOrgName(&cert_handle->issuer), alternative_text);
    156 }
    157 
    158 string GetIssuerOrgUnitName(X509Certificate::OSCertHandle cert_handle,
    159                             const string& alternative_text) {
    160   return Stringize(CERT_GetOrgUnitName(&cert_handle->issuer), alternative_text);
    161 }
    162 
    163 string GetSubjectOrgName(X509Certificate::OSCertHandle cert_handle,
    164                          const string& alternative_text) {
    165   return Stringize(CERT_GetOrgName(&cert_handle->subject), alternative_text);
    166 }
    167 
    168 string GetSubjectOrgUnitName(X509Certificate::OSCertHandle cert_handle,
    169                              const string& alternative_text) {
    170   return Stringize(CERT_GetOrgUnitName(&cert_handle->subject),
    171                    alternative_text);
    172 }
    173 
    174 string GetSubjectCommonName(X509Certificate::OSCertHandle cert_handle,
    175                             const string& alternative_text) {
    176   return Stringize(CERT_GetCommonName(&cert_handle->subject), alternative_text);
    177 }
    178 
    179 bool GetTimes(X509Certificate::OSCertHandle cert_handle,
    180               base::Time* issued, base::Time* expires) {
    181   PRTime pr_issued, pr_expires;
    182   if (CERT_GetCertTimes(cert_handle, &pr_issued, &pr_expires) == SECSuccess) {
    183     *issued = crypto::PRTimeToBaseTime(pr_issued);
    184     *expires = crypto::PRTimeToBaseTime(pr_expires);
    185     return true;
    186   }
    187   return false;
    188 }
    189 
    190 string GetTitle(X509Certificate::OSCertHandle cert_handle) {
    191   return psm::GetCertTitle(cert_handle);
    192 }
    193 
    194 string GetIssuerName(X509Certificate::OSCertHandle cert_handle) {
    195   return psm::ProcessName(&cert_handle->issuer);
    196 }
    197 
    198 string GetSubjectName(X509Certificate::OSCertHandle cert_handle) {
    199   return psm::ProcessName(&cert_handle->subject);
    200 }
    201 
    202 void GetExtensions(
    203     const string& critical_label,
    204     const string& non_critical_label,
    205     X509Certificate::OSCertHandle cert_handle,
    206     Extensions* extensions) {
    207   if (cert_handle->extensions) {
    208     for (size_t i = 0; cert_handle->extensions[i] != NULL; ++i) {
    209       Extension extension;
    210       extension.name = psm::GetOIDText(&cert_handle->extensions[i]->id);
    211       extension.value = ProcessExtension(
    212           critical_label, non_critical_label, cert_handle->extensions[i]);
    213       extensions->push_back(extension);
    214     }
    215   }
    216 }
    217 
    218 string HashCertSHA256(X509Certificate::OSCertHandle cert_handle) {
    219   return HashCert(cert_handle, HASH_AlgSHA256, SHA256_LENGTH);
    220 }
    221 
    222 string HashCertSHA1(X509Certificate::OSCertHandle cert_handle) {
    223   return HashCert(cert_handle, HASH_AlgSHA1, SHA1_LENGTH);
    224 }
    225 
    226 void GetCertChainFromCert(X509Certificate::OSCertHandle cert_handle,
    227                           X509Certificate::OSCertHandles* cert_handles) {
    228   CERTCertList* cert_list =
    229       CERT_GetCertChainFromCert(cert_handle, PR_Now(), certUsageSSLServer);
    230   CERTCertListNode* node;
    231   for (node = CERT_LIST_HEAD(cert_list);
    232        !CERT_LIST_END(node, cert_list);
    233        node = CERT_LIST_NEXT(node)) {
    234     cert_handles->push_back(CERT_DupCertificate(node->cert));
    235   }
    236   CERT_DestroyCertList(cert_list);
    237 }
    238 
    239 void DestroyCertChain(X509Certificate::OSCertHandles* cert_handles) {
    240   for (X509Certificate::OSCertHandles::iterator i(cert_handles->begin());
    241        i != cert_handles->end(); ++i)
    242     CERT_DestroyCertificate(*i);
    243   cert_handles->clear();
    244 }
    245 
    246 string GetDerString(X509Certificate::OSCertHandle cert_handle) {
    247   return string(reinterpret_cast<const char*>(cert_handle->derCert.data),
    248                 cert_handle->derCert.len);
    249 }
    250 
    251 string GetCMSString(const X509Certificate::OSCertHandles& cert_chain,
    252                     size_t start, size_t end) {
    253   crypto::ScopedPLArenaPool arena(PORT_NewArena(1024));
    254   DCHECK(arena.get());
    255 
    256   ScopedNSSCMSMessage message(NSS_CMSMessage_Create(arena.get()));
    257   DCHECK(message.get());
    258 
    259   // First, create SignedData with the certificate only (no chain).
    260   ScopedNSSCMSSignedData signed_data(NSS_CMSSignedData_CreateCertsOnly(
    261       message.get(), cert_chain[start], PR_FALSE));
    262   if (!signed_data.get()) {
    263     DLOG(ERROR) << "NSS_CMSSignedData_Create failed";
    264     return std::string();
    265   }
    266   // Add the rest of the chain (if any).
    267   for (size_t i = start + 1; i < end; ++i) {
    268     if (NSS_CMSSignedData_AddCertificate(signed_data.get(), cert_chain[i]) !=
    269         SECSuccess) {
    270       DLOG(ERROR) << "NSS_CMSSignedData_AddCertificate failed on " << i;
    271       return std::string();
    272     }
    273   }
    274 
    275   NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(message.get());
    276   if (NSS_CMSContentInfo_SetContent_SignedData(
    277       message.get(), cinfo, signed_data.get()) == SECSuccess) {
    278     ignore_result(signed_data.release());
    279   } else {
    280     DLOG(ERROR) << "NSS_CMSMessage_GetContentInfo failed";
    281     return std::string();
    282   }
    283 
    284   SECItem cert_p7 = { siBuffer, NULL, 0 };
    285   NSSCMSEncoderContext *ecx = NSS_CMSEncoder_Start(message.get(), NULL, NULL,
    286                                                    &cert_p7, arena.get(), NULL,
    287                                                    NULL, NULL, NULL, NULL,
    288                                                    NULL);
    289   if (!ecx) {
    290     DLOG(ERROR) << "NSS_CMSEncoder_Start failed";
    291     return std::string();
    292   }
    293 
    294   if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
    295     DLOG(ERROR) << "NSS_CMSEncoder_Finish failed";
    296     return std::string();
    297   }
    298 
    299   return string(reinterpret_cast<const char*>(cert_p7.data), cert_p7.len);
    300 }
    301 
    302 string ProcessSecAlgorithmSignature(X509Certificate::OSCertHandle cert_handle) {
    303   return ProcessSecAlgorithmInternal(&cert_handle->signature);
    304 }
    305 
    306 string ProcessSecAlgorithmSubjectPublicKey(
    307     X509Certificate::OSCertHandle cert_handle) {
    308   return ProcessSecAlgorithmInternal(
    309       &cert_handle->subjectPublicKeyInfo.algorithm);
    310 }
    311 
    312 string ProcessSecAlgorithmSignatureWrap(
    313     X509Certificate::OSCertHandle cert_handle) {
    314   return ProcessSecAlgorithmInternal(
    315       &cert_handle->signatureWrap.signatureAlgorithm);
    316 }
    317 
    318 string ProcessSubjectPublicKeyInfo(X509Certificate::OSCertHandle cert_handle) {
    319   return psm::ProcessSubjectPublicKeyInfo(&cert_handle->subjectPublicKeyInfo);
    320 }
    321 
    322 string ProcessRawBitsSignatureWrap(X509Certificate::OSCertHandle cert_handle) {
    323   return ProcessRawBits(cert_handle->signatureWrap.signature.data,
    324                         cert_handle->signatureWrap.signature.len);
    325 }
    326 
    327 }  // namespace x509_certificate_model
    328