Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(153)

Side by Side Diff: webrtc/base/nssidentity.cc

Issue 1313233005: purge nss files and dependencies (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/base/nssidentity.h ('k') | webrtc/base/nssstreamadapter.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « webrtc/base/nssidentity.h ('k') | webrtc/base/nssstreamadapter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698