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 |