| 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 |