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

Side by Side Diff: net/base/x509_certificate_mac.cc

Issue 6312157: Add ability to create self signed certs to mac. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: More code cleanup Created 9 years, 10 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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_certificate.h" 5 #include "net/base/x509_certificate.h"
6 6
7 #include <CommonCrypto/CommonDigest.h> 7 #include <CommonCrypto/CommonDigest.h>
8 #include <Security/Security.h> 8 #include <Security/Security.h>
9 #include <time.h> 9 #include <time.h>
10 10
11 #include <vector>
12
13 #include "base/crypto/cssm_init.h"
14 #include "base/crypto/rsa_private_key.h"
11 #include "base/lazy_instance.h" 15 #include "base/lazy_instance.h"
12 #include "base/logging.h" 16 #include "base/logging.h"
17 #include "base/nss_util.h"
13 #include "base/pickle.h" 18 #include "base/pickle.h"
14 #include "base/singleton.h" 19 #include "base/singleton.h"
15 #include "base/mac/scoped_cftyperef.h" 20 #include "base/mac/scoped_cftyperef.h"
16 #include "base/sys_string_conversions.h" 21 #include "base/sys_string_conversions.h"
17 #include "net/base/cert_status_flags.h" 22 #include "net/base/cert_status_flags.h"
18 #include "net/base/cert_verify_result.h" 23 #include "net/base/cert_verify_result.h"
19 #include "net/base/net_errors.h" 24 #include "net/base/net_errors.h"
20 #include "net/base/test_root_certs.h" 25 #include "net/base/test_root_certs.h"
26 #include "third_party/nss/mozilla/security/nss/lib/certdb/cert.h"
wtc 2011/02/09 01:03:31 The reason we went through the pain of writing sev
21 27
22 using base::mac::ScopedCFTypeRef; 28 using base::mac::ScopedCFTypeRef;
23 using base::Time; 29 using base::Time;
24 30
25 namespace net { 31 namespace net {
26 32
27 namespace { 33 namespace {
28 34
29 typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef, 35 typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef,
30 CFDictionaryRef*); 36 CFDictionaryRef*);
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 // is properly decoded as a PKCS#7, whether PEM or not, which avoids 368 // is properly decoded as a PKCS#7, whether PEM or not, which avoids
363 // the need to fallback to internal decoding. 369 // the need to fallback to internal decoding.
364 if (IsValidOSCertHandle(cert)) { 370 if (IsValidOSCertHandle(cert)) {
365 CFRetain(cert); 371 CFRetain(cert);
366 output->push_back(cert); 372 output->push_back(cert);
367 } 373 }
368 } 374 }
369 } 375 }
370 } 376 }
371 377
378 struct CSSMOIDString {
379 const CSSM_OID* oid_;
380 std::string string_;
381 };
382
383 typedef std::vector<CSSMOIDString> CSSMOIDStringVector;
384
385 bool CERTNameToCSSMOIDVector(CERTName* name, CSSMOIDStringVector* out_values) {
386 struct OIDCSSMMap {
387 SECOidTag sec_OID_;
388 const CSSM_OID* cssm_OID_;
389 };
390
391 const OIDCSSMMap kOIDs[] = {
392 { SEC_OID_AVA_COMMON_NAME, &CSSMOID_CommonName },
393 { SEC_OID_AVA_COUNTRY_NAME, &CSSMOID_CountryName },
394 { SEC_OID_AVA_LOCALITY, &CSSMOID_LocalityName },
395 { SEC_OID_AVA_STATE_OR_PROVINCE, &CSSMOID_StateProvinceName },
396 { SEC_OID_AVA_STREET_ADDRESS, &CSSMOID_StreetAddress },
397 { SEC_OID_AVA_ORGANIZATION_NAME, &CSSMOID_OrganizationName },
398 { SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, &CSSMOID_OrganizationalUnitName },
399 { SEC_OID_AVA_DN_QUALIFIER, &CSSMOID_DNQualifier },
400 { SEC_OID_RFC1274_UID, &CSSMOID_UniqueIdentifier },
401 { SEC_OID_PKCS9_EMAIL_ADDRESS, &CSSMOID_EmailAddress },
402 };
403
404 CERTRDN** rdns = name->rdns;
405 for (size_t rdn = 0; rdns[rdn]; ++rdn) {
406 CERTAVA** avas = rdns[rdn]->avas;
407 for (size_t pair = 0; avas[pair] != 0; ++pair) {
408 SECOidTag tag = CERT_GetAVATag(avas[pair]);
409 if (tag == SEC_OID_UNKNOWN) {
410 return false;
411 }
412 CSSMOIDString oidString;
413 bool found_oid = false;
414 for (size_t oid = 0; oid < ARRAYSIZE_UNSAFE(kOIDs); ++oid) {
415 if (kOIDs[oid].sec_OID_ == tag) {
416 SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value);
417 if (!decode_item) {
418 return false;
419 }
Ryan Sleevi 2011/02/08 02:27:55 nit: no need for braces around 1-line if.
420 // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote.
421 std::string value(reinterpret_cast<char*>(decode_item->data),
422 decode_item->len);
423 oidString.oid_ = kOIDs[oid].cssm_OID_;
424 oidString.string_ = value;
425 out_values->push_back(oidString);
426 SECITEM_FreeItem(decode_item, PR_TRUE);
427 found_oid = true;
428 break;
429 }
430 }
431 if (!found_oid) {
432 DLOG(ERROR) << "Unrecognized OID: " << tag;
433 }
Ryan Sleevi 2011/02/08 02:27:55 nit: no need for braces around 1-line if.
434 }
435 }
436 return true;
437 }
438
439 class ScopedCertName {
440 public:
441 explicit ScopedCertName(CERTName* name) : name_(name) { }
442 ~ScopedCertName() {
443 if (name_) CERT_DestroyName(name_);
444 }
445 operator CERTName*() { return name_; }
446
447 private:
448 CERTName* name_;
449 };
450
451 class ScopedEncodedCertResults {
452 public:
453 explicit ScopedEncodedCertResults(CSSM_TP_RESULT_SET* results)
454 : results_(results) { }
455 ~ScopedEncodedCertResults() {
456 if (results_) {
457 for (uint32 i = 0; i < results_->NumberOfResults; i++) {
458 CSSM_ENCODED_CERT* encCert =
459 reinterpret_cast<CSSM_ENCODED_CERT*>(results_->Results);
Ryan Sleevi 2011/02/08 02:27:55 nit: move lines 458-459 outside of the loop?
460 base::CSSMFree(encCert[i].CertBlob.Data);
461 }
462 }
463 base::CSSMFree(results_->Results);
464 base::CSSMFree(results_);
465 }
466
467 private:
468 CSSM_TP_RESULT_SET* results_;
469 };
470
372 } // namespace 471 } // namespace
373 472
374 void X509Certificate::Initialize() { 473 void X509Certificate::Initialize() {
375 const CSSM_X509_NAME* name; 474 const CSSM_X509_NAME* name;
376 OSStatus status = SecCertificateGetSubject(cert_handle_, &name); 475 OSStatus status = SecCertificateGetSubject(cert_handle_, &name);
377 if (!status) 476 if (!status)
378 subject_.Parse(name); 477 subject_.Parse(name);
379 478
380 status = SecCertificateGetIssuer(cert_handle_, &name); 479 status = SecCertificateGetIssuer(cert_handle_, &name);
381 if (!status) 480 if (!status)
(...skipping 17 matching lines...) Expand all
399 498
400 return CreateFromBytes(data, length); 499 return CreateFromBytes(data, length);
401 } 500 }
402 501
403 // static 502 // static
404 X509Certificate* X509Certificate::CreateSelfSigned( 503 X509Certificate* X509Certificate::CreateSelfSigned(
405 base::RSAPrivateKey* key, 504 base::RSAPrivateKey* key,
406 const std::string& subject, 505 const std::string& subject,
407 uint32 serial_number, 506 uint32 serial_number,
408 base::TimeDelta valid_duration) { 507 base::TimeDelta valid_duration) {
409 // TODO(port): Implement. 508 DCHECK(key);
410 return NULL; 509 DCHECK(!subject.empty());
510
511 if (valid_duration.InSeconds() > UINT32_MAX) {
512 LOG(ERROR) << "valid_duration too big" << valid_duration.InSeconds();
513 valid_duration = base::TimeDelta::FromSeconds(UINT32_MAX);
514 }
515
516 // There is a comment in
517 // http://www.opensource.apple.com/source/security_certtool/security_certtool- 31828/src/CertTool.cpp
518 // that serial_numbers being passed into CSSM_TP_SubmitCredRequest can't have
519 // their high bit set. We will continue though and mask it out below.
520 if (serial_number & 0x80000000) {
521 LOG(ERROR) << "serial_number has high bit set " << serial_number;
522 }
Ryan Sleevi 2011/02/08 02:27:55 nit: no braces for one-line if's
523
524 // NSS is used to parse the subject string into a set of
525 // CSSM_OID/string pairs. There doesn't appear to be a system routine for
526 // parsing Distinguished Name strings.
527 base::EnsureNSSInit();
528
529 CSSMOIDStringVector subject_name_oids;
530 ScopedCertName subject_name(
531 CERT_AsciiToName(const_cast<char*>(subject.c_str())));
532 if (!CERTNameToCSSMOIDVector(subject_name, &subject_name_oids)) {
533 DLOG(ERROR) << "Unable to generate CSSMOIDMap from " << subject;
534 return NULL;
535 }
536
537 // Convert the map of oid/string pairs into an array of
538 // CSSM_APPLE_TP_NAME_OIDs.
539 std::vector<CSSM_APPLE_TP_NAME_OID> cssm_subject_names;
540 for(CSSMOIDStringVector::iterator iter = subject_name_oids.begin();
541 iter != subject_name_oids.end(); ++iter) {
542 CSSM_APPLE_TP_NAME_OID cssm_subject_name;
543 cssm_subject_name.oid = iter->oid_;
544 cssm_subject_name.string = iter->string_.c_str();
545 cssm_subject_names.push_back(cssm_subject_name);
546 }
547
548 if (cssm_subject_names.size() == 0) {
549 DLOG(ERROR) << "cssm_subject_names.size() == 0. Input: " << subject;
550 return NULL;
551 }
552
553 // Set up a certificate request.
554 CSSM_APPLE_TP_CERT_REQUEST certReq;
555 memset(&certReq, 0, sizeof(certReq));
556 certReq.cspHand = base::GetSharedCSPHandle();
557 certReq.clHand = base::GetSharedCLHandle();
558 // See comment about serial numbers above.
Ryan Sleevi 2011/02/08 02:27:55 nit: remove extra spaces
559 certReq.serialNumber = serial_number & 0x7fffffff;
560 certReq.numSubjectNames = cssm_subject_names.size();
561 certReq.subjectNames = &cssm_subject_names[0];
562 certReq.numIssuerNames = 0; // Root.
563 certReq.issuerNames = NULL;
564 certReq.issuerNameX509 = NULL;
565 certReq.certPublicKey = key->public_key();
566 certReq.issuerPrivateKey = key->key();
567 // These are the Apple defaults.
568 certReq.signatureAlg = CSSM_ALGID_SHA1WithRSA;
569 certReq.signatureOid = CSSMOID_SHA1WithRSA;
570 certReq.notBefore = 0;
571 certReq.notAfter = static_cast<uint32>(valid_duration.InSeconds());
572 certReq.numExtensions = 0;
573 certReq.extensions = NULL;
574 certReq.challengeString = NULL;
575
576 CSSM_TP_REQUEST_SET reqSet;
577 reqSet.NumberOfRequests = 1;
578 reqSet.Requests = &certReq;
579
580 CSSM_FIELD policyId;
581 memset(&policyId, 0, sizeof(policyId));
582 policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN;
583
584 CSSM_TP_CALLERAUTH_CONTEXT callerAuthContext;
585 memset(&callerAuthContext, 0, sizeof(callerAuthContext));
586 callerAuthContext.Policy.NumberOfPolicyIds = 1;
587 callerAuthContext.Policy.PolicyIds = &policyId;
588
589 CSSM_TP_HANDLE tp_handle = base::GetSharedTPHandle();
590 CSSM_DATA refId;
591 memset(&refId, 0, sizeof(refId));
592 sint32 estTime;
593 CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest(tp_handle, NULL,
594 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, &reqSet, &callerAuthContext,
595 &estTime, &refId);
Ryan Sleevi 2011/02/08 02:27:55 nit: extra space
596 if(crtn) {
597 DLOG(ERROR) << "CSSM_TP_SubmitCredRequest failed " << crtn;
598 return NULL;
599 }
600
601 CSSM_BOOL confirmRequired;
602 CSSM_TP_RESULT_SET *resultSet = NULL;
603 crtn = CSSM_TP_RetrieveCredResult(tp_handle, &refId, NULL, &estTime,
604 &confirmRequired, &resultSet);
605 ScopedEncodedCertResults scopedResults(resultSet);
606 base::CSSMFree(refId.Data);
607 if (crtn) {
608 DLOG(ERROR) << "CSSM_TP_RetrieveCredResult failed " << crtn;
609 return NULL;
610 }
611
612 if (confirmRequired) {
613 // Potential leak here of resultSet. |confirmRequired| should never be
614 // true,
Ryan Sleevi 2011/02/08 02:27:55 world's smallest nit pt 2: , -> .
615 DLOG(ERROR) << "CSSM_TP_RetrieveCredResult required confirmation";
616 return NULL;
617 }
618
619 if (resultSet->NumberOfResults != 1) {
620 DLOG(ERROR) << "Unexpected number of results: "
621 << resultSet->NumberOfResults;
Ryan Sleevi 2011/02/08 02:27:55 nit: missing space
622 return NULL;
623 }
624
625 CSSM_ENCODED_CERT* encCert =
626 reinterpret_cast<CSSM_ENCODED_CERT*>(resultSet->Results);
627 base::mac::ScopedCFTypeRef<SecCertificateRef> scoped_cert;
628 SecCertificateRef certificate_ref = NULL;
629 OSStatus os_status = SecCertificateCreateFromData(&encCert->CertBlob,
630 encCert->CertType, encCert->CertEncoding, &certificate_ref);
Ryan Sleevi 2011/02/08 02:27:55 Is this style OK? I thought it was either align th
631 if (os_status != 0) {
632 DLOG(ERROR) << "SecCertificateCreateFromData failed: " << os_status;
633 return NULL;
634 }
635 scoped_cert.reset(certificate_ref);
636
637 return CreateFromHandle(
638 scoped_cert, X509Certificate::SOURCE_LONE_CERT_IMPORT,
639 X509Certificate::OSCertHandles());
411 } 640 }
412 641
413 void X509Certificate::Persist(Pickle* pickle) { 642 void X509Certificate::Persist(Pickle* pickle) {
414 CSSM_DATA cert_data; 643 CSSM_DATA cert_data;
415 OSStatus status = SecCertificateGetData(cert_handle_, &cert_data); 644 OSStatus status = SecCertificateGetData(cert_handle_, &cert_data);
416 if (status) { 645 if (status) {
417 NOTREACHED(); 646 NOTREACHED();
418 return; 647 return;
419 } 648 }
420 649
(...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after
927 if (result) { 1156 if (result) {
928 LOG(ERROR) << "SecIdentityCreateWithCertificate error " << result; 1157 LOG(ERROR) << "SecIdentityCreateWithCertificate error " << result;
929 return NULL; 1158 return NULL;
930 } 1159 }
931 ScopedCFTypeRef<CFMutableArrayRef> chain( 1160 ScopedCFTypeRef<CFMutableArrayRef> chain(
932 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); 1161 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks));
933 CFArrayAppendValue(chain, identity); 1162 CFArrayAppendValue(chain, identity);
934 1163
935 CFArrayRef cert_chain = NULL; 1164 CFArrayRef cert_chain = NULL;
936 result = CopyCertChain(cert_handle_, &cert_chain); 1165 result = CopyCertChain(cert_handle_, &cert_chain);
1166 ScopedCFTypeRef<CFArrayRef> scoped_cert_chain(cert_chain);
937 if (result) { 1167 if (result) {
938 LOG(ERROR) << "CreateIdentityCertificateChain error " << result; 1168 LOG(ERROR) << "CreateIdentityCertificateChain error " << result;
939 return chain.release(); 1169 return chain.release();
940 } 1170 }
941 1171
942 // Append the intermediate certs from SecTrust to the result array: 1172 // Append the intermediate certs from SecTrust to the result array:
943 if (cert_chain) { 1173 if (cert_chain) {
944 int chain_count = CFArrayGetCount(cert_chain); 1174 int chain_count = CFArrayGetCount(cert_chain);
945 if (chain_count > 1) { 1175 if (chain_count > 1) {
946 CFArrayAppendArray(chain, 1176 CFArrayAppendArray(chain,
947 cert_chain, 1177 cert_chain,
948 CFRangeMake(1, chain_count - 1)); 1178 CFRangeMake(1, chain_count - 1));
949 } 1179 }
950 CFRelease(cert_chain);
951 } 1180 }
952 1181
953 return chain.release(); 1182 return chain.release();
954 } 1183 }
955 1184
956 } // namespace net 1185 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698