| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/base/cert_database.h" | 5 #include "net/base/cert_database.h" |
| 6 | 6 |
| 7 #include <cert.h> |
| 8 #include <certdb.h> |
| 7 #include <pk11pub.h> | 9 #include <pk11pub.h> |
| 8 #include <secmod.h> | 10 #include <secmod.h> |
| 9 #include <ssl.h> | 11 #include <ssl.h> |
| 10 #include <nssb64.h> // NSSBase64_EncodeItem() | 12 #include <nssb64.h> // NSSBase64_EncodeItem() |
| 11 #include <secder.h> // DER_Encode() | 13 #include <secder.h> // DER_Encode() |
| 14 #include <secerr.h> |
| 12 #include <cryptohi.h> // SEC_DerSignData() | 15 #include <cryptohi.h> // SEC_DerSignData() |
| 13 #include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo() | 16 #include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo() |
| 14 | 17 |
| 15 #include "base/logging.h" | 18 #include "base/logging.h" |
| 16 #include "base/scoped_ptr.h" | 19 #include "base/scoped_ptr.h" |
| 17 #include "base/nss_util.h" | 20 #include "base/nss_util.h" |
| 21 #include "base/crypto/scoped_nss_types.h" |
| 18 #include "net/base/net_errors.h" | 22 #include "net/base/net_errors.h" |
| 19 #include "net/base/x509_certificate.h" | 23 #include "net/base/x509_certificate.h" |
| 20 | 24 |
| 21 namespace net { | 25 namespace net { |
| 22 | 26 |
| 27 namespace { |
| 28 |
| 29 typedef scoped_ptr_malloc<CERTCertList, |
| 30 base::NSSDestroyer<CERTCertList, |
| 31 CERT_DestroyCertList> > ScopedCERTCertList; |
| 32 |
| 33 typedef scoped_ptr_malloc<CERTCertificateList, |
| 34 base::NSSDestroyer<CERTCertificateList, |
| 35 CERT_DestroyCertificateList> > ScopedCERTCertificateList; |
| 36 |
| 37 // From an arbitrary, unordered list of certificate, attempt to import every |
| 38 // certificate that: |
| 39 // 1) Is a CA |
| 40 // 2) Results in a valid certificate chain |
| 41 // It is adapted from the PSM logic located in |
| 42 // security/manager/ssl/src/nsNSSCertificateDB.cpp |
| 43 void ImportValidIntermediates( |
| 44 const X509Certificate::OSCertHandles& intermediates) { |
| 45 if (intermediates.empty()) |
| 46 return; |
| 47 |
| 48 ScopedCERTCertList os_intermediates(CERT_NewCertList()); |
| 49 if (os_intermediates == NULL) |
| 50 return; |
| 51 |
| 52 for (X509Certificate::OSCertHandles::const_iterator it = |
| 53 intermediates.begin(); it != intermediates.end(); ++it) { |
| 54 // CERTCertList will free each certificate when it's destroyed, so we must |
| 55 // duplicate each cert prior to adding to the list, as we do not own the |
| 56 // intermediates (see x509_certificate.h) |
| 57 CERTCertificate* cert = CERT_DupCertificate( |
| 58 const_cast<CERTCertificate*>(*it)); |
| 59 if (cert) |
| 60 CERT_AddCertToListTail(os_intermediates.get(), cert); |
| 61 } |
| 62 |
| 63 // Filter out any certificates which are not valid CA certificates |
| 64 SECStatus rv = CERT_FilterCertListByUsage(os_intermediates.get(), |
| 65 certUsageAnyCA, |
| 66 PR_TRUE); |
| 67 if (rv != SECSuccess) |
| 68 return; |
| 69 |
| 70 PRTime now = PR_Now(); |
| 71 size_t offset = 0; |
| 72 for (CERTCertListNode* node = CERT_LIST_HEAD(os_intermediates); |
| 73 !CERT_LIST_END(node, os_intermediates); |
| 74 node = CERT_LIST_NEXT(node), ++offset) { |
| 75 // Validate the certificate |
| 76 SECStatus verify_result = CERT_VerifyCert(CERT_GetDefaultCertDB(), |
| 77 node->cert, PR_TRUE, |
| 78 certUsageVerifyCA, now, NULL, |
| 79 NULL); |
| 80 if (verify_result != SECSuccess) { |
| 81 DLOG(WARNING) << "Unable to validate the intermediate at " << offset |
| 82 << ". Skipping import of this certificate. Result was " |
| 83 << verify_result; |
| 84 continue; |
| 85 } |
| 86 |
| 87 // Attempt to construct a chain. The presumption here is that if |
| 88 // construction of chain depends on other certificates that were part of |
| 89 // |intermediates|, they will all be available in the same |
| 90 // CERTCertDBHandle. This is true if they were created via |
| 91 // X509Certificate::CreateFromBytes(), since under the hood that creates |
| 92 // temporary objects in CERT_GetDefaultCertDB(), but that may not be true |
| 93 // if they were obtained by other means. |
| 94 // |
| 95 // Note: If multiple CertDBs are ever supported, this chain building logic |
| 96 // will need to be adjusted accordingly. |
| 97 ScopedCERTCertificateList chain( |
| 98 CERT_CertChainFromCert(node->cert, certUsageAnyCA, PR_FALSE)); |
| 99 if (chain == NULL) { |
| 100 DLOG(WARNING) << "Unable to construct certificate chain for" |
| 101 << "intermediate " << offset << ". Skipping import of " |
| 102 << "this certificate."; |
| 103 continue; |
| 104 } |
| 105 |
| 106 // CertChainFromCert returns an array of SECItems, but ImportCerts |
| 107 // requires an array of SECItem pointers, so convert. |
| 108 scoped_array<SECItem*> items(new SECItem*[chain->len]); |
| 109 if (items == NULL) |
| 110 continue; |
| 111 |
| 112 for (int i = 0; i < chain->len; i++) { |
| 113 items[i] = &chain->certs[i]; |
| 114 } |
| 115 CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageAnyCA, chain->len, |
| 116 items.get(), NULL, PR_TRUE, PR_TRUE, NULL); |
| 117 } |
| 118 } |
| 119 |
| 120 } // namespace |
| 121 |
| 23 CertDatabase::CertDatabase() { | 122 CertDatabase::CertDatabase() { |
| 24 base::EnsureNSSInit(); | 123 base::EnsureNSSInit(); |
| 25 } | 124 } |
| 26 | 125 |
| 27 int CertDatabase::CheckUserCert(X509Certificate* cert_obj) { | 126 int CertDatabase::CheckUserCert(X509Certificate* cert_obj) { |
| 28 if (!cert_obj) | 127 if (!cert_obj) |
| 29 return ERR_CERT_INVALID; | 128 return ERR_CERT_INVALID; |
| 30 if (cert_obj->HasExpired()) | 129 if (cert_obj->HasExpired()) |
| 31 return ERR_CERT_DATE_INVALID; | 130 return ERR_CERT_DATE_INVALID; |
| 32 | 131 |
| 33 // Check if the private key corresponding to the certificate exist | 132 // Check if the private key corresponding to the certificate exist. We |
| 34 // We shouldn't accept any random client certificate sent by a CA. | 133 // shouldn't accept any random client certificate sent by a CA. |
| 35 | 134 // |
| 36 // Note: The NSS source documentation wrongly suggests that this | 135 // Note: The NSS source documentation wrongly suggests that this also |
| 37 // also imports the certificate if the private key exists. This | 136 // imports the certificate if the private key exists. This doesn't seem to |
| 38 // doesn't seem to be the case. | 137 // be the case. |
| 39 | |
| 40 CERTCertificate* cert = cert_obj->os_cert_handle(); | 138 CERTCertificate* cert = cert_obj->os_cert_handle(); |
| 41 PK11SlotInfo* slot = PK11_KeyForCertExists(cert, NULL, NULL); | 139 PK11SlotInfo* slot = PK11_KeyForCertExists(cert, NULL, NULL); |
| 42 if (!slot) { | 140 if (!slot) { |
| 43 LOG(ERROR) << "No corresponding private key in store"; | 141 LOG(ERROR) << "No corresponding private key in store"; |
| 44 return ERR_NO_PRIVATE_KEY_FOR_CERT; | 142 return ERR_NO_PRIVATE_KEY_FOR_CERT; |
| 45 } | 143 } |
| 46 PK11_FreeSlot(slot); | 144 PK11_FreeSlot(slot); |
| 47 | 145 |
| 48 return OK; | 146 return OK; |
| 49 } | 147 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 71 nickname = username + "'s " + ca_name + " ID"; | 169 nickname = username + "'s " + ca_name + " ID"; |
| 72 | 170 |
| 73 slot = PK11_ImportCertForKey(cert, | 171 slot = PK11_ImportCertForKey(cert, |
| 74 const_cast<char*>(nickname.c_str()), | 172 const_cast<char*>(nickname.c_str()), |
| 75 NULL); | 173 NULL); |
| 76 if (!slot) { | 174 if (!slot) { |
| 77 LOG(ERROR) << "Couldn't import user certificate."; | 175 LOG(ERROR) << "Couldn't import user certificate."; |
| 78 return ERR_ADD_USER_CERT_FAILED; | 176 return ERR_ADD_USER_CERT_FAILED; |
| 79 } | 177 } |
| 80 PK11_FreeSlot(slot); | 178 PK11_FreeSlot(slot); |
| 179 |
| 180 ImportValidIntermediates(cert_obj->GetIntermediateCertificates()); |
| 81 return OK; | 181 return OK; |
| 82 } | 182 } |
| 83 | 183 |
| 84 } // namespace net | 184 } // namespace net |
| OLD | NEW |