OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2012 The WebRTC Project Authors. All rights reserved. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ |
| 10 |
| 11 #include <algorithm> |
| 12 #include <string> |
| 13 #include <vector> |
| 14 |
| 15 #if HAVE_CONFIG_H |
| 16 #include "config.h" |
| 17 #endif // HAVE_CONFIG_H |
| 18 |
| 19 #if HAVE_NSS_SSL_H |
| 20 |
| 21 #include "webrtc/base/nssidentity.h" |
| 22 |
| 23 #include "cert.h" |
| 24 #include "cryptohi.h" |
| 25 #include "keyhi.h" |
| 26 #include "nss.h" |
| 27 #include "pk11pub.h" |
| 28 #include "sechash.h" |
| 29 |
| 30 #include "webrtc/base/logging.h" |
| 31 #include "webrtc/base/helpers.h" |
| 32 #include "webrtc/base/nssstreamadapter.h" |
| 33 #include "webrtc/base/safe_conversions.h" |
| 34 #include "webrtc/base/stringutils.h" |
| 35 |
| 36 namespace rtc { |
| 37 |
| 38 // Certificate validity lifetime in seconds. |
| 39 static const int CERTIFICATE_LIFETIME = 60*60*24*30; // 30 days, arbitrarily |
| 40 // Certificate validity window in seconds. |
| 41 // This is to compensate for slightly incorrect system clocks. |
| 42 static const int CERTIFICATE_WINDOW = -60*60*24; |
| 43 |
| 44 NSSKeyPair::~NSSKeyPair() { |
| 45 if (privkey_) |
| 46 SECKEY_DestroyPrivateKey(privkey_); |
| 47 if (pubkey_) |
| 48 SECKEY_DestroyPublicKey(pubkey_); |
| 49 } |
| 50 |
| 51 NSSKeyPair* NSSKeyPair::Generate(KeyType key_type) { |
| 52 SECKEYPrivateKey* privkey = nullptr; |
| 53 SECKEYPublicKey* pubkey = nullptr; |
| 54 SSLKEAType ssl_kea_type; |
| 55 if (key_type == KT_RSA) { |
| 56 PK11RSAGenParams rsa_params; |
| 57 rsa_params.keySizeInBits = 1024; |
| 58 rsa_params.pe = 0x010001; // 65537 -- a common RSA public exponent. |
| 59 |
| 60 privkey = PK11_GenerateKeyPair( |
| 61 NSSContext::GetSlot(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsa_params, &pubkey, |
| 62 PR_FALSE /*permanent*/, PR_FALSE /*sensitive*/, nullptr); |
| 63 |
| 64 ssl_kea_type = ssl_kea_rsa; |
| 65 } else if (key_type == KT_ECDSA) { |
| 66 unsigned char param_buf[12]; // OIDs are small |
| 67 SECItem ecdsa_params = {siBuffer, param_buf, sizeof(param_buf)}; |
| 68 SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); |
| 69 if (!oid_data || oid_data->oid.len > sizeof(param_buf) - 2) { |
| 70 LOG(LS_ERROR) << "oid_data incorrect: " << oid_data->oid.len; |
| 71 return nullptr; |
| 72 } |
| 73 ecdsa_params.data[0] = SEC_ASN1_OBJECT_ID; |
| 74 ecdsa_params.data[1] = oid_data->oid.len; |
| 75 memcpy(ecdsa_params.data + 2, oid_data->oid.data, oid_data->oid.len); |
| 76 ecdsa_params.len = oid_data->oid.len + 2; |
| 77 |
| 78 privkey = PK11_GenerateKeyPair( |
| 79 NSSContext::GetSlot(), CKM_EC_KEY_PAIR_GEN, &ecdsa_params, &pubkey, |
| 80 PR_FALSE /*permanent*/, PR_FALSE /*sensitive*/, nullptr); |
| 81 |
| 82 ssl_kea_type = ssl_kea_ecdh; |
| 83 } else { |
| 84 LOG(LS_ERROR) << "Key type requested not understood"; |
| 85 return nullptr; |
| 86 } |
| 87 |
| 88 if (!privkey) { |
| 89 LOG(LS_ERROR) << "Couldn't generate key pair: " << PORT_GetError(); |
| 90 return nullptr; |
| 91 } |
| 92 |
| 93 return new NSSKeyPair(privkey, pubkey, ssl_kea_type); |
| 94 } |
| 95 |
| 96 // Just make a copy. |
| 97 NSSKeyPair* NSSKeyPair::GetReference() { |
| 98 SECKEYPrivateKey* privkey = SECKEY_CopyPrivateKey(privkey_); |
| 99 if (!privkey) |
| 100 return nullptr; |
| 101 |
| 102 SECKEYPublicKey* pubkey = SECKEY_CopyPublicKey(pubkey_); |
| 103 if (!pubkey) { |
| 104 SECKEY_DestroyPrivateKey(privkey); |
| 105 return nullptr; |
| 106 } |
| 107 |
| 108 return new NSSKeyPair(privkey, pubkey, ssl_kea_type_); |
| 109 } |
| 110 |
| 111 NSSCertificate::NSSCertificate(CERTCertificate* cert) |
| 112 : certificate_(CERT_DupCertificate(cert)) { |
| 113 ASSERT(certificate_ != nullptr); |
| 114 } |
| 115 |
| 116 static void DeleteCert(SSLCertificate* cert) { |
| 117 delete cert; |
| 118 } |
| 119 |
| 120 NSSCertificate::NSSCertificate(CERTCertList* cert_list) { |
| 121 // Copy the first cert into certificate_. |
| 122 CERTCertListNode* node = CERT_LIST_HEAD(cert_list); |
| 123 certificate_ = CERT_DupCertificate(node->cert); |
| 124 |
| 125 // Put any remaining certificates into the chain. |
| 126 node = CERT_LIST_NEXT(node); |
| 127 std::vector<SSLCertificate*> certs; |
| 128 for (; !CERT_LIST_END(node, cert_list); node = CERT_LIST_NEXT(node)) { |
| 129 certs.push_back(new NSSCertificate(node->cert)); |
| 130 } |
| 131 |
| 132 if (!certs.empty()) |
| 133 chain_.reset(new SSLCertChain(certs)); |
| 134 |
| 135 // The SSLCertChain constructor copies its input, so now we have to delete |
| 136 // the originals. |
| 137 std::for_each(certs.begin(), certs.end(), DeleteCert); |
| 138 } |
| 139 |
| 140 NSSCertificate::NSSCertificate(CERTCertificate* cert, SSLCertChain* chain) |
| 141 : certificate_(CERT_DupCertificate(cert)) { |
| 142 ASSERT(certificate_ != nullptr); |
| 143 if (chain) |
| 144 chain_.reset(chain->Copy()); |
| 145 } |
| 146 |
| 147 NSSCertificate::~NSSCertificate() { |
| 148 if (certificate_) |
| 149 CERT_DestroyCertificate(certificate_); |
| 150 } |
| 151 |
| 152 NSSCertificate* NSSCertificate::FromPEMString(const std::string& pem_string) { |
| 153 std::string der; |
| 154 if (!SSLIdentity::PemToDer(kPemTypeCertificate, pem_string, &der)) |
| 155 return nullptr; |
| 156 |
| 157 SECItem der_cert; |
| 158 der_cert.data = reinterpret_cast<unsigned char *>(const_cast<char *>( |
| 159 der.data())); |
| 160 der_cert.len = checked_cast<unsigned int>(der.size()); |
| 161 CERTCertificate* cert = CERT_NewTempCertificate( |
| 162 CERT_GetDefaultCertDB(), &der_cert, nullptr, PR_FALSE, PR_TRUE); |
| 163 |
| 164 if (!cert) |
| 165 return nullptr; |
| 166 |
| 167 NSSCertificate* ret = new NSSCertificate(cert); |
| 168 CERT_DestroyCertificate(cert); |
| 169 return ret; |
| 170 } |
| 171 |
| 172 NSSCertificate* NSSCertificate::GetReference() const { |
| 173 return new NSSCertificate(certificate_, chain_.get()); |
| 174 } |
| 175 |
| 176 std::string NSSCertificate::ToPEMString() const { |
| 177 return SSLIdentity::DerToPem(kPemTypeCertificate, |
| 178 certificate_->derCert.data, |
| 179 certificate_->derCert.len); |
| 180 } |
| 181 |
| 182 void NSSCertificate::ToDER(Buffer* der_buffer) const { |
| 183 der_buffer->SetData(certificate_->derCert.data, certificate_->derCert.len); |
| 184 } |
| 185 |
| 186 static bool Certifies(CERTCertificate* parent, CERTCertificate* child) { |
| 187 // TODO(bemasc): Identify stricter validation checks to use here. In the |
| 188 // context of some future identity standard, it might make sense to check |
| 189 // the certificates' roles, expiration dates, self-signatures (if |
| 190 // self-signed), certificate transparency logging, or many other attributes. |
| 191 // NOTE: Future changes to this validation may reject some previously allowed |
| 192 // certificate chains. Users should be advised not to deploy chained |
| 193 // certificates except in controlled environments until the validity |
| 194 // requirements are finalized. |
| 195 |
| 196 // Check that the parent's name is the same as the child's claimed issuer. |
| 197 SECComparison name_status = |
| 198 CERT_CompareName(&child->issuer, &parent->subject); |
| 199 if (name_status != SECEqual) |
| 200 return false; |
| 201 |
| 202 // Extract the parent's public key, or fail if the key could not be read |
| 203 // (e.g. certificate is corrupted). |
| 204 SECKEYPublicKey* parent_key = CERT_ExtractPublicKey(parent); |
| 205 if (!parent_key) |
| 206 return false; |
| 207 |
| 208 // Check that the parent's privkey was actually used to generate the child's |
| 209 // signature. |
| 210 SECStatus verified = CERT_VerifySignedDataWithPublicKey(&child->signatureWrap, |
| 211 parent_key, nullptr); |
| 212 SECKEY_DestroyPublicKey(parent_key); |
| 213 return verified == SECSuccess; |
| 214 } |
| 215 |
| 216 bool NSSCertificate::IsValidChain(const CERTCertList* cert_list) { |
| 217 CERTCertListNode* child = CERT_LIST_HEAD(cert_list); |
| 218 for (CERTCertListNode* parent = CERT_LIST_NEXT(child); |
| 219 !CERT_LIST_END(parent, cert_list); |
| 220 child = parent, parent = CERT_LIST_NEXT(parent)) { |
| 221 if (!Certifies(parent->cert, child->cert)) |
| 222 return false; |
| 223 } |
| 224 return true; |
| 225 } |
| 226 |
| 227 bool NSSCertificate::GetDigestLength(const std::string& algorithm, |
| 228 size_t* length) { |
| 229 const SECHashObject* ho = nullptr; |
| 230 |
| 231 if (!GetDigestObject(algorithm, &ho)) |
| 232 return false; |
| 233 |
| 234 *length = ho->length; |
| 235 |
| 236 return true; |
| 237 } |
| 238 |
| 239 bool NSSCertificate::GetSignatureDigestAlgorithm(std::string* algorithm) const { |
| 240 // The function sec_DecodeSigAlg in NSS provides this mapping functionality. |
| 241 // Unfortunately it is private, so the functionality must be duplicated here. |
| 242 // See https://bugzilla.mozilla.org/show_bug.cgi?id=925165 . |
| 243 SECOidTag sig_alg = SECOID_GetAlgorithmTag(&certificate_->signature); |
| 244 switch (sig_alg) { |
| 245 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: |
| 246 *algorithm = DIGEST_MD5; |
| 247 break; |
| 248 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: |
| 249 case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: |
| 250 case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: |
| 251 case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: |
| 252 case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: |
| 253 case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: |
| 254 case SEC_OID_MISSI_DSS: |
| 255 case SEC_OID_MISSI_KEA_DSS: |
| 256 case SEC_OID_MISSI_KEA_DSS_OLD: |
| 257 case SEC_OID_MISSI_DSS_OLD: |
| 258 *algorithm = DIGEST_SHA_1; |
| 259 break; |
| 260 case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: |
| 261 case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: |
| 262 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST: |
| 263 *algorithm = DIGEST_SHA_224; |
| 264 break; |
| 265 case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: |
| 266 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: |
| 267 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST: |
| 268 *algorithm = DIGEST_SHA_256; |
| 269 break; |
| 270 case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: |
| 271 case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: |
| 272 *algorithm = DIGEST_SHA_384; |
| 273 break; |
| 274 case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: |
| 275 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: |
| 276 *algorithm = DIGEST_SHA_512; |
| 277 break; |
| 278 default: |
| 279 // Unknown algorithm. There are several unhandled options that are less |
| 280 // common and more complex. |
| 281 algorithm->clear(); |
| 282 return false; |
| 283 } |
| 284 return true; |
| 285 } |
| 286 |
| 287 bool NSSCertificate::ComputeDigest(const std::string& algorithm, |
| 288 unsigned char* digest, |
| 289 size_t size, |
| 290 size_t* length) const { |
| 291 const SECHashObject* ho = nullptr; |
| 292 |
| 293 if (!GetDigestObject(algorithm, &ho)) |
| 294 return false; |
| 295 |
| 296 if (size < ho->length) // Sanity check for fit |
| 297 return false; |
| 298 |
| 299 SECStatus rv = HASH_HashBuf(ho->type, digest, |
| 300 certificate_->derCert.data, |
| 301 certificate_->derCert.len); |
| 302 if (rv != SECSuccess) |
| 303 return false; |
| 304 |
| 305 *length = ho->length; |
| 306 |
| 307 return true; |
| 308 } |
| 309 |
| 310 bool NSSCertificate::GetChain(SSLCertChain** chain) const { |
| 311 if (!chain_) |
| 312 return false; |
| 313 |
| 314 *chain = chain_->Copy(); |
| 315 return true; |
| 316 } |
| 317 |
| 318 bool NSSCertificate::Equals(const NSSCertificate* tocompare) const { |
| 319 if (!certificate_->derCert.len) |
| 320 return false; |
| 321 if (!tocompare->certificate_->derCert.len) |
| 322 return false; |
| 323 |
| 324 if (certificate_->derCert.len != tocompare->certificate_->derCert.len) |
| 325 return false; |
| 326 |
| 327 return memcmp(certificate_->derCert.data, |
| 328 tocompare->certificate_->derCert.data, |
| 329 certificate_->derCert.len) == 0; |
| 330 } |
| 331 |
| 332 bool NSSCertificate::GetDigestObject(const std::string& algorithm, |
| 333 const SECHashObject** hop) { |
| 334 const SECHashObject* ho; |
| 335 HASH_HashType hash_type; |
| 336 |
| 337 if (algorithm == DIGEST_SHA_1) { |
| 338 hash_type = HASH_AlgSHA1; |
| 339 // HASH_AlgSHA224 is not supported in the chromium linux build system. |
| 340 #if 0 |
| 341 } else if (algorithm == DIGEST_SHA_224) { |
| 342 hash_type = HASH_AlgSHA224; |
| 343 #endif |
| 344 } else if (algorithm == DIGEST_SHA_256) { |
| 345 hash_type = HASH_AlgSHA256; |
| 346 } else if (algorithm == DIGEST_SHA_384) { |
| 347 hash_type = HASH_AlgSHA384; |
| 348 } else if (algorithm == DIGEST_SHA_512) { |
| 349 hash_type = HASH_AlgSHA512; |
| 350 } else { |
| 351 return false; |
| 352 } |
| 353 |
| 354 ho = HASH_GetHashObject(hash_type); |
| 355 |
| 356 ASSERT(ho->length >= 20); // Can't happen |
| 357 *hop = ho; |
| 358 |
| 359 return true; |
| 360 } |
| 361 |
| 362 NSSIdentity::NSSIdentity(NSSKeyPair* keypair, NSSCertificate* cert) |
| 363 : keypair_(keypair), certificate_(cert) { |
| 364 } |
| 365 |
| 366 NSSIdentity* NSSIdentity::GenerateInternal(const SSLIdentityParams& params) { |
| 367 std::string subject_name_string = "CN=" + params.common_name; |
| 368 CERTName* subject_name = |
| 369 CERT_AsciiToName(const_cast<char*>(subject_name_string.c_str())); |
| 370 NSSIdentity* identity = nullptr; |
| 371 CERTSubjectPublicKeyInfo* spki = nullptr; |
| 372 CERTCertificateRequest* certreq = nullptr; |
| 373 CERTValidity* validity = nullptr; |
| 374 CERTCertificate* certificate = nullptr; |
| 375 NSSKeyPair* keypair = NSSKeyPair::Generate(params.key_type); |
| 376 SECItem inner_der; |
| 377 SECStatus rv; |
| 378 PLArenaPool* arena; |
| 379 SECItem signed_cert; |
| 380 PRTime now = PR_Now(); |
| 381 PRTime not_before = |
| 382 now + static_cast<PRTime>(params.not_before) * PR_USEC_PER_SEC; |
| 383 PRTime not_after = |
| 384 now + static_cast<PRTime>(params.not_after) * PR_USEC_PER_SEC; |
| 385 |
| 386 inner_der.len = 0; |
| 387 inner_der.data = nullptr; |
| 388 |
| 389 if (!keypair) { |
| 390 LOG(LS_ERROR) << "Couldn't generate key pair"; |
| 391 goto fail; |
| 392 } |
| 393 |
| 394 if (!subject_name) { |
| 395 LOG(LS_ERROR) << "Couldn't convert subject name " << subject_name; |
| 396 goto fail; |
| 397 } |
| 398 |
| 399 spki = SECKEY_CreateSubjectPublicKeyInfo(keypair->pubkey()); |
| 400 if (!spki) { |
| 401 LOG(LS_ERROR) << "Couldn't create SPKI"; |
| 402 goto fail; |
| 403 } |
| 404 |
| 405 certreq = CERT_CreateCertificateRequest(subject_name, spki, nullptr); |
| 406 if (!certreq) { |
| 407 LOG(LS_ERROR) << "Couldn't create certificate signing request"; |
| 408 goto fail; |
| 409 } |
| 410 |
| 411 validity = CERT_CreateValidity(not_before, not_after); |
| 412 if (!validity) { |
| 413 LOG(LS_ERROR) << "Couldn't create validity"; |
| 414 goto fail; |
| 415 } |
| 416 |
| 417 unsigned long serial; |
| 418 // Note: This serial in principle could collide, but it's unlikely |
| 419 rv = PK11_GenerateRandom(reinterpret_cast<unsigned char *>(&serial), |
| 420 sizeof(serial)); |
| 421 if (rv != SECSuccess) { |
| 422 LOG(LS_ERROR) << "Couldn't generate random serial"; |
| 423 goto fail; |
| 424 } |
| 425 |
| 426 certificate = CERT_CreateCertificate(serial, subject_name, validity, certreq); |
| 427 if (!certificate) { |
| 428 LOG(LS_ERROR) << "Couldn't create certificate"; |
| 429 goto fail; |
| 430 } |
| 431 |
| 432 arena = certificate->arena; |
| 433 |
| 434 SECOidTag sec_oid; |
| 435 if (params.key_type == KT_RSA) { |
| 436 sec_oid = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; |
| 437 } else if (params.key_type == KT_ECDSA) { |
| 438 sec_oid = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; |
| 439 } else { |
| 440 // We should not arrive here since NSSKeyPair::Generate would have failed. |
| 441 // Play it safe in order to accomodate code changes. |
| 442 LOG(LS_ERROR) << "Key type requested not understood"; |
| 443 goto fail; |
| 444 } |
| 445 |
| 446 rv = SECOID_SetAlgorithmID(arena, &certificate->signature, sec_oid, nullptr); |
| 447 if (rv != SECSuccess) { |
| 448 LOG(LS_ERROR) << "Couldn't set hashing algorithm"; |
| 449 goto fail; |
| 450 } |
| 451 |
| 452 // Set version to X509v3. |
| 453 *(certificate->version.data) = 2; |
| 454 certificate->version.len = 1; |
| 455 |
| 456 if (!SEC_ASN1EncodeItem(arena, &inner_der, certificate, |
| 457 SEC_ASN1_GET(CERT_CertificateTemplate))) { |
| 458 LOG(LS_ERROR) << "Couldn't encode certificate"; |
| 459 goto fail; |
| 460 } |
| 461 |
| 462 rv = SEC_DerSignData(arena, &signed_cert, inner_der.data, inner_der.len, |
| 463 keypair->privkey(), sec_oid); |
| 464 if (rv != SECSuccess) { |
| 465 LOG(LS_ERROR) << "Couldn't sign certificate"; |
| 466 goto fail; |
| 467 } |
| 468 certificate->derCert = signed_cert; |
| 469 |
| 470 identity = new NSSIdentity(keypair, new NSSCertificate(certificate)); |
| 471 |
| 472 goto done; |
| 473 |
| 474 fail: |
| 475 delete keypair; |
| 476 |
| 477 done: |
| 478 if (certificate) CERT_DestroyCertificate(certificate); |
| 479 if (subject_name) CERT_DestroyName(subject_name); |
| 480 if (spki) SECKEY_DestroySubjectPublicKeyInfo(spki); |
| 481 if (certreq) CERT_DestroyCertificateRequest(certreq); |
| 482 if (validity) CERT_DestroyValidity(validity); |
| 483 return identity; |
| 484 } |
| 485 |
| 486 NSSIdentity* NSSIdentity::Generate(const std::string& common_name, |
| 487 KeyType key_type) { |
| 488 SSLIdentityParams params; |
| 489 params.common_name = common_name; |
| 490 params.not_before = CERTIFICATE_WINDOW; |
| 491 params.not_after = CERTIFICATE_LIFETIME; |
| 492 params.key_type = key_type; |
| 493 return GenerateInternal(params); |
| 494 } |
| 495 |
| 496 NSSIdentity* NSSIdentity::GenerateForTest(const SSLIdentityParams& params) { |
| 497 return GenerateInternal(params); |
| 498 } |
| 499 |
| 500 SSLIdentity* NSSIdentity::FromPEMStrings(const std::string& private_key, |
| 501 const std::string& certificate) { |
| 502 std::string private_key_der; |
| 503 if (!SSLIdentity::PemToDer( |
| 504 kPemTypeRsaPrivateKey, private_key, &private_key_der)) |
| 505 return nullptr; |
| 506 |
| 507 SECItem private_key_item; |
| 508 private_key_item.data = reinterpret_cast<unsigned char *>( |
| 509 const_cast<char *>(private_key_der.c_str())); |
| 510 private_key_item.len = checked_cast<unsigned int>(private_key_der.size()); |
| 511 |
| 512 const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | |
| 513 KU_DIGITAL_SIGNATURE; |
| 514 |
| 515 SECKEYPrivateKey* privkey = nullptr; |
| 516 SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( |
| 517 NSSContext::GetSlot(), &private_key_item, nullptr, nullptr, PR_FALSE, |
| 518 PR_FALSE, key_usage, &privkey, nullptr); |
| 519 if (rv != SECSuccess) { |
| 520 LOG(LS_ERROR) << "Couldn't import private key"; |
| 521 return nullptr; |
| 522 } |
| 523 |
| 524 SECKEYPublicKey* pubkey = SECKEY_ConvertToPublicKey(privkey); |
| 525 if (rv != SECSuccess) { |
| 526 SECKEY_DestroyPrivateKey(privkey); |
| 527 LOG(LS_ERROR) << "Couldn't convert private key to public key"; |
| 528 return nullptr; |
| 529 } |
| 530 |
| 531 SSLKEAType ssl_kea_type; |
| 532 if (rtc::starts_with(private_key.c_str(), |
| 533 "-----BEGIN RSA PRIVATE KEY-----")) { |
| 534 ssl_kea_type = ssl_kea_rsa; |
| 535 } else { |
| 536 // We might want to check more key types here. But since we're moving to |
| 537 // Open/BoringSSL, don't bother. Besides, this will likely be correct for |
| 538 // any future key type, causing a test to do more harm than good. |
| 539 ssl_kea_type = ssl_kea_ecdh; |
| 540 } |
| 541 |
| 542 // Assign to a scoped_ptr so we don't leak on error. |
| 543 scoped_ptr<NSSKeyPair> keypair(new NSSKeyPair(privkey, pubkey, ssl_kea_type)); |
| 544 |
| 545 scoped_ptr<NSSCertificate> cert(NSSCertificate::FromPEMString(certificate)); |
| 546 if (!cert) { |
| 547 LOG(LS_ERROR) << "Couldn't parse certificate"; |
| 548 return nullptr; |
| 549 } |
| 550 |
| 551 // TODO(ekr@rtfm.com): Check the public key against the certificate. |
| 552 return new NSSIdentity(keypair.release(), cert.release()); |
| 553 } |
| 554 |
| 555 NSSIdentity::~NSSIdentity() { |
| 556 LOG(LS_INFO) << "Destroying NSS identity"; |
| 557 } |
| 558 |
| 559 NSSIdentity* NSSIdentity::GetReference() const { |
| 560 NSSKeyPair* keypair = keypair_->GetReference(); |
| 561 if (!keypair) |
| 562 return nullptr; |
| 563 |
| 564 NSSCertificate* certificate = certificate_->GetReference(); |
| 565 if (!certificate) { |
| 566 delete keypair; |
| 567 return nullptr; |
| 568 } |
| 569 |
| 570 return new NSSIdentity(keypair, certificate); |
| 571 } |
| 572 |
| 573 |
| 574 NSSCertificate &NSSIdentity::certificate() const { |
| 575 return *certificate_; |
| 576 } |
| 577 |
| 578 |
| 579 } // rtc namespace |
| 580 |
| 581 #endif // HAVE_NSS_SSL_H |
OLD | NEW |