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