Home | History | Annotate | Download | only in net
      1 // Copyright (c) 2011 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/string_number_conversions.h"
     18 #include "crypto/nss_util.h"
     19 #include "net/base/x509_certificate.h"
     20 #include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h"
     21 #include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h"
     22 #include "chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h"
     23 
     24 namespace psm = mozilla_security_manager;
     25 
     26 namespace {
     27 
     28 // Convert a char* return value from NSS into a std::string and free the NSS
     29 // memory.  If the arg is NULL, an empty string will be returned instead.
     30 std::string Stringize(char* nss_text, const std::string& alternative_text) {
     31   if (!nss_text)
     32     return alternative_text;
     33 
     34   std::string s = nss_text;
     35   PORT_Free(nss_text);
     36   return s;
     37 }
     38 
     39 // Hash a certificate using the given algorithm, return the result as a
     40 // colon-seperated hex string.  The len specified is the number of bytes
     41 // required for storing the raw fingerprint.
     42 // (It's a bit redundant that the caller needs to specify len in addition to the
     43 // algorithm, but given the limited uses, not worth fixing.)
     44 std::string HashCert(CERTCertificate* cert, HASH_HashType algorithm, int len) {
     45   unsigned char fingerprint[HASH_LENGTH_MAX];
     46 
     47   DCHECK(NULL != cert->derCert.data);
     48   DCHECK_NE(0U, cert->derCert.len);
     49   DCHECK_LE(len, HASH_LENGTH_MAX);
     50   memset(fingerprint, 0, len);
     51   SECStatus rv = HASH_HashBuf(algorithm, fingerprint, cert->derCert.data,
     52                               cert->derCert.len);
     53   DCHECK_EQ(rv, SECSuccess);
     54   return x509_certificate_model::ProcessRawBytes(fingerprint, len);
     55 }
     56 
     57 std::string ProcessSecAlgorithmInternal(SECAlgorithmID* algorithm_id) {
     58   return psm::GetOIDText(&algorithm_id->algorithm);
     59 }
     60 
     61 std::string ProcessExtension(
     62     const std::string& critical_label,
     63     const std::string& non_critical_label,
     64     CERTCertExtension* extension) {
     65   std::string criticality =
     66       extension->critical.data && extension->critical.data[0] ?
     67           critical_label : non_critical_label;
     68   return criticality + "\n" +
     69       psm::ProcessExtensionData(SECOID_FindOIDTag(&extension->id),
     70                                 &extension->value);
     71 }
     72 
     73 ////////////////////////////////////////////////////////////////////////////////
     74 // NSS certificate export functions.
     75 
     76 class FreeNSSCMSMessage {
     77  public:
     78   inline void operator()(NSSCMSMessage* x) const {
     79     NSS_CMSMessage_Destroy(x);
     80   }
     81 };
     82 typedef scoped_ptr_malloc<NSSCMSMessage, FreeNSSCMSMessage>
     83     ScopedNSSCMSMessage;
     84 
     85 class FreeNSSCMSSignedData {
     86  public:
     87   inline void operator()(NSSCMSSignedData* x) const {
     88     NSS_CMSSignedData_Destroy(x);
     89   }
     90 };
     91 typedef scoped_ptr_malloc<NSSCMSSignedData, FreeNSSCMSSignedData>
     92     ScopedNSSCMSSignedData;
     93 
     94 }  // namespace
     95 
     96 namespace x509_certificate_model {
     97 
     98 using net::X509Certificate;
     99 using std::string;
    100 
    101 string GetCertNameOrNickname(X509Certificate::OSCertHandle cert_handle) {
    102   string name = ProcessIDN(Stringize(CERT_GetCommonName(&cert_handle->subject),
    103                                      ""));
    104   if (!name.empty())
    105     return name;
    106   return GetNickname(cert_handle);
    107 }
    108 
    109 string GetNickname(X509Certificate::OSCertHandle cert_handle) {
    110   string name;
    111   if (cert_handle->nickname) {
    112     name = cert_handle->nickname;
    113     // Hack copied from mozilla: Cut off text before first :, which seems to
    114     // just be the token name.
    115     size_t colon_pos = name.find(':');
    116     if (colon_pos != string::npos)
    117       name = name.substr(colon_pos + 1);
    118   }
    119   return name;
    120 }
    121 
    122 string GetTokenName(X509Certificate::OSCertHandle cert_handle) {
    123   return psm::GetCertTokenName(cert_handle);
    124 }
    125 
    126 string GetVersion(X509Certificate::OSCertHandle cert_handle) {
    127   unsigned long version = ULONG_MAX;
    128   if (SEC_ASN1DecodeInteger(&cert_handle->version, &version) == SECSuccess &&
    129       version != ULONG_MAX)
    130     return base::UintToString(version + 1);
    131   return "";
    132 }
    133 
    134 net::CertType GetType(X509Certificate::OSCertHandle cert_handle) {
    135     return psm::GetCertType(cert_handle);
    136 }
    137 
    138 string GetEmailAddress(X509Certificate::OSCertHandle cert_handle) {
    139   if (cert_handle->emailAddr)
    140     return cert_handle->emailAddr;
    141   return "";
    142 }
    143 
    144 void GetUsageStrings(X509Certificate::OSCertHandle cert_handle,
    145                      std::vector<string>* usages) {
    146   psm::GetCertUsageStrings(cert_handle, usages);
    147 }
    148 
    149 string GetKeyUsageString(X509Certificate::OSCertHandle cert_handle) {
    150   SECItem key_usage;
    151   key_usage.data = NULL;
    152   string key_usage_str;
    153   if (CERT_FindKeyUsageExtension(cert_handle, &key_usage) == SECSuccess) {
    154     key_usage_str = psm::ProcessKeyUsageBitString(&key_usage, ',');
    155     PORT_Free(key_usage.data);
    156   }
    157   return key_usage_str;
    158 }
    159 
    160 string GetSerialNumberHexified(X509Certificate::OSCertHandle cert_handle,
    161                                const string& alternative_text) {
    162   return Stringize(CERT_Hexify(&cert_handle->serialNumber, true),
    163                    alternative_text);
    164 }
    165 
    166 string GetIssuerCommonName(X509Certificate::OSCertHandle cert_handle,
    167                            const string& alternative_text) {
    168   return Stringize(CERT_GetCommonName(&cert_handle->issuer), alternative_text);
    169 }
    170 
    171 string GetIssuerOrgName(X509Certificate::OSCertHandle cert_handle,
    172                         const string& alternative_text) {
    173   return Stringize(CERT_GetOrgName(&cert_handle->issuer), alternative_text);
    174 }
    175 
    176 string GetIssuerOrgUnitName(X509Certificate::OSCertHandle cert_handle,
    177                             const string& alternative_text) {
    178   return Stringize(CERT_GetOrgUnitName(&cert_handle->issuer), alternative_text);
    179 }
    180 
    181 string GetSubjectOrgName(X509Certificate::OSCertHandle cert_handle,
    182                          const string& alternative_text) {
    183   return Stringize(CERT_GetOrgName(&cert_handle->subject), alternative_text);
    184 }
    185 
    186 string GetSubjectOrgUnitName(X509Certificate::OSCertHandle cert_handle,
    187                              const string& alternative_text) {
    188   return Stringize(CERT_GetOrgUnitName(&cert_handle->subject),
    189                    alternative_text);
    190 }
    191 
    192 string GetSubjectCommonName(X509Certificate::OSCertHandle cert_handle,
    193                             const string& alternative_text) {
    194   return Stringize(CERT_GetCommonName(&cert_handle->subject), alternative_text);
    195 }
    196 
    197 bool GetTimes(X509Certificate::OSCertHandle cert_handle,
    198               base::Time* issued, base::Time* expires) {
    199   PRTime pr_issued, pr_expires;
    200   if (CERT_GetCertTimes(cert_handle, &pr_issued, &pr_expires) == SECSuccess) {
    201     *issued = crypto::PRTimeToBaseTime(pr_issued);
    202     *expires = crypto::PRTimeToBaseTime(pr_expires);
    203     return true;
    204   }
    205   return false;
    206 }
    207 
    208 string GetTitle(X509Certificate::OSCertHandle cert_handle) {
    209   return psm::GetCertTitle(cert_handle);
    210 }
    211 
    212 string GetIssuerName(X509Certificate::OSCertHandle cert_handle) {
    213   return psm::ProcessName(&cert_handle->issuer);
    214 }
    215 
    216 string GetSubjectName(X509Certificate::OSCertHandle cert_handle) {
    217   return psm::ProcessName(&cert_handle->subject);
    218 }
    219 
    220 void GetEmailAddresses(X509Certificate::OSCertHandle cert_handle,
    221                        std::vector<string>* email_addresses) {
    222   for (const char* addr = CERT_GetFirstEmailAddress(cert_handle);
    223        addr; addr = CERT_GetNextEmailAddress(cert_handle, addr)) {
    224     // The first email addr (from Subject) may be duplicated in Subject
    225     // Alternative Name, so check subsequent addresses are not equal to the
    226     // first one before adding to the list.
    227     if (!email_addresses->size() || (*email_addresses)[0] != addr)
    228       email_addresses->push_back(addr);
    229   }
    230 }
    231 
    232 void GetNicknameStringsFromCertList(
    233     const std::vector<scoped_refptr<X509Certificate> >& certs,
    234     const string& cert_expired,
    235     const string& cert_not_yet_valid,
    236     std::vector<string>* nick_names) {
    237   CERTCertList* cert_list = CERT_NewCertList();
    238   for (size_t i = 0; i < certs.size(); ++i) {
    239     CERT_AddCertToListTail(
    240         cert_list,
    241         CERT_DupCertificate(certs[i]->os_cert_handle()));
    242   }
    243   // Would like to use CERT_GetCertNicknameWithValidity on each cert
    244   // individually instead of having to build a CERTCertList for this, but that
    245   // function is not exported.
    246   CERTCertNicknames* cert_nicknames = CERT_NicknameStringsFromCertList(
    247       cert_list,
    248       const_cast<char*>(cert_expired.c_str()),
    249       const_cast<char*>(cert_not_yet_valid.c_str()));
    250   DCHECK_EQ(cert_nicknames->numnicknames,
    251             static_cast<int>(certs.size()));
    252 
    253   for (int i = 0; i < cert_nicknames->numnicknames; ++i)
    254     nick_names->push_back(cert_nicknames->nicknames[i]);
    255 
    256   CERT_FreeNicknames(cert_nicknames);
    257   CERT_DestroyCertList(cert_list);
    258 }
    259 
    260 // For background see this discussion on dev-tech-crypto.lists.mozilla.org:
    261 // http://web.archiveorange.com/archive/v/6JJW7E40sypfZGtbkzxX
    262 //
    263 // NOTE: This function relies on the convention that the same PKCS#11 ID
    264 // is shared between a certificate and its associated private and public
    265 // keys.  I tried to implement this with PK11_GetLowLevelKeyIDForCert(),
    266 // but that always returns NULL on Chrome OS for me.
    267 std::string GetPkcs11Id(net::X509Certificate::OSCertHandle cert_handle) {
    268   std::string pkcs11_id;
    269   SECKEYPrivateKey *priv_key = PK11_FindKeyByAnyCert(cert_handle,
    270                                                      NULL /* wincx */);
    271   if (priv_key) {
    272     // Get the CKA_ID attribute for a key.
    273     SECItem* sec_item = PK11_GetLowLevelKeyIDForPrivateKey(priv_key);
    274     if (sec_item) {
    275       pkcs11_id = base::HexEncode(sec_item->data, sec_item->len);
    276       SECITEM_FreeItem(sec_item, PR_TRUE);
    277     }
    278     SECKEY_DestroyPrivateKey(priv_key);
    279   }
    280   return pkcs11_id;
    281 }
    282 
    283 void GetExtensions(
    284     const string& critical_label,
    285     const string& non_critical_label,
    286     X509Certificate::OSCertHandle cert_handle,
    287     Extensions* extensions) {
    288   if (cert_handle->extensions) {
    289     for (size_t i = 0; cert_handle->extensions[i] != NULL; ++i) {
    290       Extension extension;
    291       extension.name = psm::GetOIDText(&cert_handle->extensions[i]->id);
    292       extension.value = ProcessExtension(
    293           critical_label, non_critical_label, cert_handle->extensions[i]);
    294       extensions->push_back(extension);
    295     }
    296   }
    297 }
    298 
    299 string HashCertSHA256(X509Certificate::OSCertHandle cert_handle) {
    300   return HashCert(cert_handle, HASH_AlgSHA256, SHA256_LENGTH);
    301 }
    302 
    303 string HashCertSHA1(X509Certificate::OSCertHandle cert_handle) {
    304   return HashCert(cert_handle, HASH_AlgSHA1, SHA1_LENGTH);
    305 }
    306 
    307 void GetCertChainFromCert(X509Certificate::OSCertHandle cert_handle,
    308                           X509Certificate::OSCertHandles* cert_handles) {
    309   CERTCertList* cert_list =
    310       CERT_GetCertChainFromCert(cert_handle, PR_Now(), certUsageSSLServer);
    311   CERTCertListNode* node;
    312   for (node = CERT_LIST_HEAD(cert_list);
    313        !CERT_LIST_END(node, cert_list);
    314        node = CERT_LIST_NEXT(node)) {
    315     cert_handles->push_back(CERT_DupCertificate(node->cert));
    316   }
    317   CERT_DestroyCertList(cert_list);
    318 }
    319 
    320 void DestroyCertChain(X509Certificate::OSCertHandles* cert_handles) {
    321   for (X509Certificate::OSCertHandles::iterator i(cert_handles->begin());
    322        i != cert_handles->end(); ++i)
    323     CERT_DestroyCertificate(*i);
    324   cert_handles->clear();
    325 }
    326 
    327 string GetDerString(X509Certificate::OSCertHandle cert_handle) {
    328   return string(reinterpret_cast<const char*>(cert_handle->derCert.data),
    329                 cert_handle->derCert.len);
    330 }
    331 
    332 string GetCMSString(const X509Certificate::OSCertHandles& cert_chain,
    333                     size_t start, size_t end) {
    334   ScopedPRArenaPool arena(PORT_NewArena(1024));
    335   CHECK(arena.get());
    336 
    337   ScopedNSSCMSMessage message(NSS_CMSMessage_Create(arena.get()));
    338   CHECK(message.get());
    339 
    340   // First, create SignedData with the certificate only (no chain).
    341   ScopedNSSCMSSignedData signed_data(NSS_CMSSignedData_CreateCertsOnly(
    342       message.get(), cert_chain[start], PR_FALSE));
    343   if (!signed_data.get()) {
    344     LOG(ERROR) << "NSS_CMSSignedData_Create failed";
    345     return "";
    346   }
    347   // Add the rest of the chain (if any).
    348   for (size_t i = start + 1; i < end; ++i) {
    349     if (NSS_CMSSignedData_AddCertificate(signed_data.get(), cert_chain[i]) !=
    350         SECSuccess) {
    351       LOG(ERROR) << "NSS_CMSSignedData_AddCertificate failed on " << i;
    352       return "";
    353     }
    354   }
    355 
    356   NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(message.get());
    357   if (NSS_CMSContentInfo_SetContent_SignedData(
    358       message.get(), cinfo, signed_data.get()) == SECSuccess) {
    359     ignore_result(signed_data.release());
    360   } else {
    361     LOG(ERROR) << "NSS_CMSMessage_GetContentInfo failed";
    362     return "";
    363   }
    364 
    365   SECItem cert_p7 = { siBuffer, NULL, 0 };
    366   NSSCMSEncoderContext *ecx = NSS_CMSEncoder_Start(message.get(), NULL, NULL,
    367                                                    &cert_p7, arena.get(), NULL,
    368                                                    NULL, NULL, NULL, NULL,
    369                                                    NULL);
    370   if (!ecx) {
    371     LOG(ERROR) << "NSS_CMSEncoder_Start failed";
    372     return "";
    373   }
    374 
    375   if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
    376     LOG(ERROR) << "NSS_CMSEncoder_Finish failed";
    377     return "";
    378   }
    379 
    380   return string(reinterpret_cast<const char*>(cert_p7.data), cert_p7.len);
    381 }
    382 
    383 string ProcessSecAlgorithmSignature(X509Certificate::OSCertHandle cert_handle) {
    384   return ProcessSecAlgorithmInternal(&cert_handle->signature);
    385 }
    386 
    387 string ProcessSecAlgorithmSubjectPublicKey(
    388     X509Certificate::OSCertHandle cert_handle) {
    389   return ProcessSecAlgorithmInternal(
    390       &cert_handle->subjectPublicKeyInfo.algorithm);
    391 }
    392 
    393 string ProcessSecAlgorithmSignatureWrap(
    394     X509Certificate::OSCertHandle cert_handle) {
    395   return ProcessSecAlgorithmInternal(
    396       &cert_handle->signatureWrap.signatureAlgorithm);
    397 }
    398 
    399 string ProcessSubjectPublicKeyInfo(X509Certificate::OSCertHandle cert_handle) {
    400   return psm::ProcessSubjectPublicKeyInfo(&cert_handle->subjectPublicKeyInfo);
    401 }
    402 
    403 string ProcessRawBitsSignatureWrap(X509Certificate::OSCertHandle cert_handle) {
    404   return ProcessRawBits(cert_handle->signatureWrap.signature.data,
    405                         cert_handle->signatureWrap.signature.len);
    406 }
    407 
    408 void RegisterDynamicOids() {
    409 }
    410 
    411 }  // namespace x509_certificate_model
    412