OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/base/x509_util.h" | 5 #include "net/base/x509_util.h" |
6 #include "net/base/x509_util_nss.h" | 6 #include "net/base/x509_util_nss.h" |
7 | 7 |
8 #include <cert.h> | 8 #include <cert.h> |
9 #include <cryptohi.h> | 9 #include <cryptohi.h> |
| 10 #include <nss.h> |
10 #include <pk11pub.h> | 11 #include <pk11pub.h> |
11 #include <prerror.h> | 12 #include <prerror.h> |
| 13 #include <secder.h> |
12 #include <secmod.h> | 14 #include <secmod.h> |
13 #include <secport.h> | 15 #include <secport.h> |
14 | 16 |
15 #include "base/debug/leak_annotations.h" | 17 #include "base/debug/leak_annotations.h" |
16 #include "base/logging.h" | 18 #include "base/logging.h" |
17 #include "base/memory/scoped_ptr.h" | 19 #include "base/memory/scoped_ptr.h" |
18 #include "base/memory/singleton.h" | 20 #include "base/memory/singleton.h" |
| 21 #include "base/pickle.h" |
19 #include "crypto/ec_private_key.h" | 22 #include "crypto/ec_private_key.h" |
20 #include "crypto/nss_util.h" | 23 #include "crypto/nss_util.h" |
21 #include "crypto/nss_util_internal.h" | 24 #include "crypto/nss_util_internal.h" |
22 #include "crypto/scoped_nss_types.h" | 25 #include "crypto/scoped_nss_types.h" |
23 #include "crypto/third_party/nss/chromium-nss.h" | 26 #include "crypto/third_party/nss/chromium-nss.h" |
| 27 #include "net/base/x509_certificate.h" |
| 28 |
| 29 namespace net { |
24 | 30 |
25 namespace { | 31 namespace { |
26 | 32 |
27 class DomainBoundCertOIDWrapper { | 33 class DomainBoundCertOIDWrapper { |
28 public: | 34 public: |
29 static DomainBoundCertOIDWrapper* GetInstance() { | 35 static DomainBoundCertOIDWrapper* GetInstance() { |
30 // Instantiated as a leaky singleton to allow the singleton to be | 36 // Instantiated as a leaky singleton to allow the singleton to be |
31 // constructed on a worker thead that is not joined when a process | 37 // constructed on a worker thead that is not joined when a process |
32 // shuts down. | 38 // shuts down. |
33 return Singleton<DomainBoundCertOIDWrapper, | 39 return Singleton<DomainBoundCertOIDWrapper, |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 | 247 |
242 DCHECK(cert->derCert.len); | 248 DCHECK(cert->derCert.len); |
243 // XXX copied from X509Certificate::GetDEREncoded | 249 // XXX copied from X509Certificate::GetDEREncoded |
244 der_cert->clear(); | 250 der_cert->clear(); |
245 der_cert->append(reinterpret_cast<char*>(cert->derCert.data), | 251 der_cert->append(reinterpret_cast<char*>(cert->derCert.data), |
246 cert->derCert.len); | 252 cert->derCert.len); |
247 CERT_DestroyCertificate(cert); | 253 CERT_DestroyCertificate(cert); |
248 return true; | 254 return true; |
249 } | 255 } |
250 | 256 |
| 257 // Callback for CERT_DecodeCertPackage(), used in |
| 258 // CreateOSCertHandlesFromBytes(). |
| 259 SECStatus PR_CALLBACK CollectCertsCallback(void* arg, |
| 260 SECItem** certs, |
| 261 int num_certs) { |
| 262 X509Certificate::OSCertHandles* results = |
| 263 reinterpret_cast<X509Certificate::OSCertHandles*>(arg); |
| 264 |
| 265 for (int i = 0; i < num_certs; ++i) { |
| 266 X509Certificate::OSCertHandle handle = |
| 267 X509Certificate::CreateOSCertHandleFromBytes( |
| 268 reinterpret_cast<char*>(certs[i]->data), certs[i]->len); |
| 269 if (handle) |
| 270 results->push_back(handle); |
| 271 } |
| 272 |
| 273 return SECSuccess; |
| 274 } |
| 275 |
251 } // namespace | 276 } // namespace |
252 | 277 |
253 namespace net { | |
254 | |
255 namespace x509_util { | 278 namespace x509_util { |
256 | 279 |
257 CERTCertificate* CreateSelfSignedCert( | 280 CERTCertificate* CreateSelfSignedCert( |
258 SECKEYPublicKey* public_key, | 281 SECKEYPublicKey* public_key, |
259 SECKEYPrivateKey* private_key, | 282 SECKEYPrivateKey* private_key, |
260 const std::string& subject, | 283 const std::string& subject, |
261 uint32 serial_number, | 284 uint32 serial_number, |
262 base::Time not_valid_before, | 285 base::Time not_valid_before, |
263 base::Time not_valid_after) { | 286 base::Time not_valid_after) { |
264 CERTCertificate* cert = CreateCertificate(public_key, | 287 CERTCertificate* cert = CreateCertificate(public_key, |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 DCHECK(key); | 323 DCHECK(key); |
301 return CreateDomainBoundCertInternal(key->public_key(), | 324 return CreateDomainBoundCertInternal(key->public_key(), |
302 key->key(), | 325 key->key(), |
303 domain, | 326 domain, |
304 serial_number, | 327 serial_number, |
305 not_valid_before, | 328 not_valid_before, |
306 not_valid_after, | 329 not_valid_after, |
307 der_cert); | 330 der_cert); |
308 } | 331 } |
309 | 332 |
| 333 #if defined(USE_NSS) || defined(OS_IOS) |
| 334 void ParsePrincipal(CERTName* name, CertPrincipal* principal) { |
| 335 typedef char* (*CERTGetNameFunc)(CERTName* name); |
| 336 |
| 337 // TODO(jcampan): add business_category and serial_number. |
| 338 // TODO(wtc): NSS has the CERT_GetOrgName, CERT_GetOrgUnitName, and |
| 339 // CERT_GetDomainComponentName functions, but they return only the most |
| 340 // general (the first) RDN. NSS doesn't have a function for the street |
| 341 // address. |
| 342 static const SECOidTag kOIDs[] = { |
| 343 SEC_OID_AVA_STREET_ADDRESS, |
| 344 SEC_OID_AVA_ORGANIZATION_NAME, |
| 345 SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, |
| 346 SEC_OID_AVA_DC }; |
| 347 |
| 348 std::vector<std::string>* values[] = { |
| 349 &principal->street_addresses, |
| 350 &principal->organization_names, |
| 351 &principal->organization_unit_names, |
| 352 &principal->domain_components }; |
| 353 DCHECK_EQ(arraysize(kOIDs), arraysize(values)); |
| 354 |
| 355 CERTRDN** rdns = name->rdns; |
| 356 for (size_t rdn = 0; rdns[rdn]; ++rdn) { |
| 357 CERTAVA** avas = rdns[rdn]->avas; |
| 358 for (size_t pair = 0; avas[pair] != 0; ++pair) { |
| 359 SECOidTag tag = CERT_GetAVATag(avas[pair]); |
| 360 for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) { |
| 361 if (kOIDs[oid] == tag) { |
| 362 SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value); |
| 363 if (!decode_item) |
| 364 break; |
| 365 // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote. |
| 366 std::string value(reinterpret_cast<char*>(decode_item->data), |
| 367 decode_item->len); |
| 368 values[oid]->push_back(value); |
| 369 SECITEM_FreeItem(decode_item, PR_TRUE); |
| 370 break; |
| 371 } |
| 372 } |
| 373 } |
| 374 } |
| 375 |
| 376 // Get CN, L, S, and C. |
| 377 CERTGetNameFunc get_name_funcs[4] = { |
| 378 CERT_GetCommonName, CERT_GetLocalityName, |
| 379 CERT_GetStateName, CERT_GetCountryName }; |
| 380 std::string* single_values[4] = { |
| 381 &principal->common_name, &principal->locality_name, |
| 382 &principal->state_or_province_name, &principal->country_name }; |
| 383 for (size_t i = 0; i < arraysize(get_name_funcs); ++i) { |
| 384 char* value = get_name_funcs[i](name); |
| 385 if (value) { |
| 386 single_values[i]->assign(value); |
| 387 PORT_Free(value); |
| 388 } |
| 389 } |
| 390 } |
| 391 |
| 392 void ParseDate(const SECItem* der_date, base::Time* result) { |
| 393 PRTime prtime; |
| 394 SECStatus rv = DER_DecodeTimeChoice(&prtime, der_date); |
| 395 DCHECK_EQ(SECSuccess, rv); |
| 396 *result = crypto::PRTimeToBaseTime(prtime); |
| 397 } |
| 398 |
| 399 std::string ParseSerialNumber(const CERTCertificate* certificate) { |
| 400 return std::string(reinterpret_cast<char*>(certificate->serialNumber.data), |
| 401 certificate->serialNumber.len); |
| 402 } |
| 403 |
| 404 void GetSubjectAltName(CERTCertificate* cert_handle, |
| 405 std::vector<std::string>* dns_names, |
| 406 std::vector<std::string>* ip_addrs) { |
| 407 if (dns_names) |
| 408 dns_names->clear(); |
| 409 if (ip_addrs) |
| 410 ip_addrs->clear(); |
| 411 |
| 412 SECItem alt_name; |
| 413 SECStatus rv = CERT_FindCertExtension(cert_handle, |
| 414 SEC_OID_X509_SUBJECT_ALT_NAME, |
| 415 &alt_name); |
| 416 if (rv != SECSuccess) |
| 417 return; |
| 418 |
| 419 PLArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
| 420 DCHECK(arena != NULL); |
| 421 |
| 422 CERTGeneralName* alt_name_list; |
| 423 alt_name_list = CERT_DecodeAltNameExtension(arena, &alt_name); |
| 424 SECITEM_FreeItem(&alt_name, PR_FALSE); |
| 425 |
| 426 CERTGeneralName* name = alt_name_list; |
| 427 while (name) { |
| 428 // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs |
| 429 // respectively, both of which can be byte copied from |
| 430 // SECItemType::data into the appropriate output vector. |
| 431 if (dns_names && name->type == certDNSName) { |
| 432 dns_names->push_back(std::string( |
| 433 reinterpret_cast<char*>(name->name.other.data), |
| 434 name->name.other.len)); |
| 435 } else if (ip_addrs && name->type == certIPAddress) { |
| 436 ip_addrs->push_back(std::string( |
| 437 reinterpret_cast<char*>(name->name.other.data), |
| 438 name->name.other.len)); |
| 439 } |
| 440 name = CERT_GetNextGeneralName(name); |
| 441 if (name == alt_name_list) |
| 442 break; |
| 443 } |
| 444 PORT_FreeArena(arena, PR_FALSE); |
| 445 } |
| 446 |
| 447 X509Certificate::OSCertHandles CreateOSCertHandlesFromBytes( |
| 448 const char* data, |
| 449 int length, |
| 450 X509Certificate::Format format) { |
| 451 X509Certificate::OSCertHandles results; |
| 452 if (length < 0) |
| 453 return results; |
| 454 |
| 455 crypto::EnsureNSSInit(); |
| 456 |
| 457 if (!NSS_IsInitialized()) |
| 458 return results; |
| 459 |
| 460 switch (format) { |
| 461 case X509Certificate::FORMAT_SINGLE_CERTIFICATE: { |
| 462 X509Certificate::OSCertHandle handle = |
| 463 X509Certificate::CreateOSCertHandleFromBytes(data, length); |
| 464 if (handle) |
| 465 results.push_back(handle); |
| 466 break; |
| 467 } |
| 468 case X509Certificate::FORMAT_PKCS7: { |
| 469 // Make a copy since CERT_DecodeCertPackage may modify it |
| 470 std::vector<char> data_copy(data, data + length); |
| 471 |
| 472 SECStatus result = CERT_DecodeCertPackage(&data_copy[0], |
| 473 length, CollectCertsCallback, &results); |
| 474 if (result != SECSuccess) |
| 475 results.clear(); |
| 476 break; |
| 477 } |
| 478 default: |
| 479 NOTREACHED() << "Certificate format " << format << " unimplemented"; |
| 480 break; |
| 481 } |
| 482 |
| 483 return results; |
| 484 } |
| 485 |
| 486 X509Certificate::OSCertHandle ReadOSCertHandleFromPickle( |
| 487 PickleIterator* pickle_iter) { |
| 488 const char* data; |
| 489 int length; |
| 490 if (!pickle_iter->ReadData(&data, &length)) |
| 491 return NULL; |
| 492 |
| 493 return X509Certificate::CreateOSCertHandleFromBytes(data, length); |
| 494 } |
| 495 |
| 496 void GetPublicKeyInfo(CERTCertificate* handle, |
| 497 size_t* size_bits, |
| 498 X509Certificate::PublicKeyType* type) { |
| 499 // Since we might fail, set the output parameters to default values first. |
| 500 *type = X509Certificate::kPublicKeyTypeUnknown; |
| 501 *size_bits = 0; |
| 502 |
| 503 crypto::ScopedSECKEYPublicKey key(CERT_ExtractPublicKey(handle)); |
| 504 if (!key.get()) |
| 505 return; |
| 506 |
| 507 *size_bits = SECKEY_PublicKeyStrengthInBits(key.get()); |
| 508 |
| 509 switch (key->keyType) { |
| 510 case rsaKey: |
| 511 *type = X509Certificate::kPublicKeyTypeRSA; |
| 512 break; |
| 513 case dsaKey: |
| 514 *type = X509Certificate::kPublicKeyTypeDSA; |
| 515 break; |
| 516 case dhKey: |
| 517 *type = X509Certificate::kPublicKeyTypeDH; |
| 518 break; |
| 519 case ecKey: |
| 520 *type = X509Certificate::kPublicKeyTypeECDSA; |
| 521 break; |
| 522 default: |
| 523 *type = X509Certificate::kPublicKeyTypeUnknown; |
| 524 *size_bits = 0; |
| 525 break; |
| 526 } |
| 527 } |
| 528 #endif // defined(USE_NSS) || defined(OS_IOS) |
| 529 |
310 } // namespace x509_util | 530 } // namespace x509_util |
311 | 531 |
312 } // namespace net | 532 } // namespace net |
OLD | NEW |