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

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: 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 <map>
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"
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 CSSMOIDCompare {
379 bool operator()(const CSSM_OID* a, const CSSM_OID* b) const {
380 return a < b;
381 }
382 };
383
384 typedef std::map<const CSSM_OID*, std::string, CSSMOIDCompare> CSSMOIDMap;
385
386 bool CERTNameToCSSMOIDMap(CERTName* name, CSSMOIDMap* out_values) {
Ryan Sleevi 2011/02/05 00:23:37 BUG: I could be reading wrong, but I don't think t
dmac 2011/02/08 01:23:45 Done.
387 struct OIDCSSMMap {
388 SECOidTag sec_OID_;
389 const CSSM_OID* cssm_OID_;
390 };
391
392 const OIDCSSMMap kOIDs[] = {
393 { SEC_OID_AVA_COMMON_NAME, &CSSMOID_CommonName },
394 { SEC_OID_AVA_COUNTRY_NAME, &CSSMOID_CountryName },
395 { SEC_OID_AVA_LOCALITY, &CSSMOID_LocalityName },
396 { SEC_OID_AVA_STATE_OR_PROVINCE, &CSSMOID_StateProvinceName },
397 { SEC_OID_AVA_STREET_ADDRESS, &CSSMOID_StreetAddress },
398 { SEC_OID_AVA_ORGANIZATION_NAME, &CSSMOID_OrganizationName },
399 { SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, &CSSMOID_OrganizationalUnitName },
400 { SEC_OID_AVA_DN_QUALIFIER, &CSSMOID_DNQualifier },
401 { SEC_OID_RFC1274_UID, &CSSMOID_UniqueIdentifier },
402 { SEC_OID_PKCS9_EMAIL_ADDRESS, &CSSMOID_EmailAddress },
403 };
404
405 CERTRDN** rdns = name->rdns;
406 for (size_t rdn = 0; rdns[rdn]; ++rdn) {
407 CERTAVA** avas = rdns[rdn]->avas;
408 for (size_t pair = 0; avas[pair] != 0; ++pair) {
409 SECOidTag tag = CERT_GetAVATag(avas[pair]);
410 if (tag == SEC_OID_UNKNOWN) {
411 return false;
412 }
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 }
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 (*out_values)[kOIDs[oid].cssm_OID_] = value;
424 SECITEM_FreeItem(decode_item, PR_TRUE);
425 found_oid = true;
426 break;
427 }
428 }
429 if (!found_oid) {
430 DLOG(ERROR) << "Unrecognized OID: " << tag;
431 }
432 }
433 }
434 return true;
435 }
436
437 class ScopedCertName {
438 public:
439 explicit ScopedCertName(CERTName* name) : name_(name) { }
440 ~ScopedCertName() {
441 if (name_) CERT_DestroyName(name_);
442 }
443 operator CERTName*() { return name_; }
444
445 private:
446 CERTName* name_;
447 };
448
372 } // namespace 449 } // namespace
373 450
374 void X509Certificate::Initialize() { 451 void X509Certificate::Initialize() {
375 const CSSM_X509_NAME* name; 452 const CSSM_X509_NAME* name;
376 OSStatus status = SecCertificateGetSubject(cert_handle_, &name); 453 OSStatus status = SecCertificateGetSubject(cert_handle_, &name);
377 if (!status) 454 if (!status)
378 subject_.Parse(name); 455 subject_.Parse(name);
379 456
380 status = SecCertificateGetIssuer(cert_handle_, &name); 457 status = SecCertificateGetIssuer(cert_handle_, &name);
381 if (!status) 458 if (!status)
(...skipping 17 matching lines...) Expand all
399 476
400 return CreateFromBytes(data, length); 477 return CreateFromBytes(data, length);
401 } 478 }
402 479
403 // static 480 // static
404 X509Certificate* X509Certificate::CreateSelfSigned( 481 X509Certificate* X509Certificate::CreateSelfSigned(
405 base::RSAPrivateKey* key, 482 base::RSAPrivateKey* key,
406 const std::string& subject, 483 const std::string& subject,
407 uint32 serial_number, 484 uint32 serial_number,
408 base::TimeDelta valid_duration) { 485 base::TimeDelta valid_duration) {
409 // TODO(port): Implement. 486 DCHECK(key);
410 return NULL; 487 DCHECK(subject.length() > 0);
Ryan Sleevi 2011/02/05 00:23:37 nit: DCHECK(!subject.empty()) or DCHECK_GT(subject
488
489 // There is a comment in
490 // http://www.opensource.apple.com/source/security_certtool/security_certtool- 31828/src/CertTool.cpp
491 // that serial_numbers being passed into CSSM_TP_SubmitCredRequest can't have
492 // their high bit set. We will continue though and mask it out below.
493 if (serial_number & 0x80000000) {
494 LOG(ERROR) << "serial_number has high bit set " << serial_number;
495 }
496
497 // NSS is used to parse the subject string into a set of
498 // CSSM_OID/string pairs. There doesn't appear to be a system routine for
499 // parsing Distinguished Name strings.
500 base::EnsureNSSInit();
501
502 CSSMOIDMap subject_name_oids;
503 ScopedCertName subject_name(
504 CERT_AsciiToName(const_cast<char*>(subject.c_str())));
505 if (!CERTNameToCSSMOIDMap(subject_name, &subject_name_oids)) {
506 DLOG(ERROR) << "Unable to generate CSSMOIDMap from " << subject;
507 return NULL;
508 }
509
510 // Convert the map of oid/string pairs into an array of
511 // CSSM_APPLE_TP_NAME_OIDs.
512 std::vector<CSSM_APPLE_TP_NAME_OID> cssm_subject_names;
513 for(CSSMOIDMap::iterator iter = subject_name_oids.begin();
514 iter != subject_name_oids.end(); ++iter) {
515 CSSM_APPLE_TP_NAME_OID cssm_subject_name;
516 cssm_subject_name.oid = iter->first;
517 cssm_subject_name.string = iter->second.c_str();
518 cssm_subject_names.push_back(cssm_subject_name);
519 }
520
521 if (cssm_subject_names.size() == 0) {
522 DLOG(ERROR) << "cssm_subject_names.size() == 0. Input: " << subject;
523 return NULL;
524 }
525
526 // Set up a certificate request.
527 CSSM_APPLE_TP_CERT_REQUEST certReq;
528 memset(&certReq, 0, sizeof(certReq));
529 certReq.challengeString = NULL;
530 certReq.cspHand = base::GetSharedCSPHandle();
531 certReq.clHand = base::GetSharedCLHandle();
532 certReq.numSubjectNames = cssm_subject_names.size();
533 certReq.subjectNames = &cssm_subject_names[0];
534 // See comment about serial numbers above.
535 certReq.serialNumber = serial_number & 0x7f000000;
536 certReq.numIssuerNames = 0; // Root.
537 certReq.issuerNames = NULL;
538 certReq.issuerNameX509 = NULL;
539 certReq.certPublicKey = key->public_key();
540 certReq.issuerPrivateKey = key->key();
541 // This is the Apple defaults.
Ryan Sleevi 2011/02/05 00:23:37 world's smallest nit: defaults -> default or this
dmac 2011/02/08 01:23:45 Done.
542 certReq.signatureAlg = CSSM_ALGID_SHA1WithRSA;
543 certReq.signatureOid = CSSMOID_SHA1WithRSA;
544 certReq.notBefore = 0;
545 certReq.notAfter = valid_duration.InSeconds();
Ryan Sleevi 2011/02/05 00:23:37 nit: InSeconds() returns an Int64, but notAfter ex
dmac 2011/02/08 01:23:45 Done.
546 certReq.numExtensions = 0;
547 certReq.extensions = NULL;
548
549 CSSM_TP_REQUEST_SET reqSet;
550 reqSet.NumberOfRequests = 1;
551 reqSet.Requests = &certReq;
552
553 CSSM_FIELD policyId;
554 memset(&policyId, 0, sizeof(policyId));
555 policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN;
556
557 CSSM_TP_CALLERAUTH_CONTEXT callerAuthContext;
558 memset(&callerAuthContext, 0, sizeof(callerAuthContext));
559 callerAuthContext.Policy.NumberOfPolicyIds = 1;
560 callerAuthContext.Policy.PolicyIds = &policyId;
561
562 CSSM_TP_HANDLE tp_handle = base::GetSharedTPHandle();
563 base::ScopedCSSMData refId;
564 sint32 estTime;
565 CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest(
566 tp_handle, NULL, CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, &reqSet,
567 &callerAuthContext, &estTime, refId);
568 if(crtn) {
569 DLOG(ERROR) << "CSSM_TP_SubmitCredRequest failed " << crtn;
570 return NULL;
571 }
572
573 CSSM_BOOL confirmRequired;
574 base::ScopedCSSMTPtr<CSSM_TP_RESULT_SET> resultSet;
575 crtn = CSSM_TP_RetrieveCredResult(tp_handle, refId, NULL, &estTime,
576 &confirmRequired, &resultSet.receive());
577 if (crtn) {
578 DLOG(ERROR) << "CSSM_TP_RetrieveCredResult failed " << crtn;
579 return NULL;
580 }
581
582 if (confirmRequired) {
Ryan Sleevi 2011/02/05 00:23:37 BUG/nit? If confirmRequired is true, it's still po
dmac 2011/02/08 01:23:45 Done.
583 DLOG(ERROR) << "CSSM_TP_RetrieveCredResult required confirmation";
584 return NULL;
585 }
586
Ryan Sleevi 2011/02/05 00:23:37 BUG: Check that resultSet->NumberOfResults == 1 be
dmac 2011/02/08 01:23:45 Done.
587 CSSM_ENCODED_CERT* encCert =
588 reinterpret_cast<CSSM_ENCODED_CERT*>(resultSet->Results);
589 base::mac::ScopedCFTypeRef<SecCertificateRef> scoped_cert;
590 {
591 base::AutoLock sec_lock(base::GetMacSecurityServicesLock());
Ryan Sleevi 2011/02/05 00:23:37 You shouldn't need to lock here. It's only needed
dmac 2011/02/08 01:23:45 Done.
592 SecCertificateRef certificate_ref = NULL;
593 OSStatus os_status = SecCertificateCreateFromData(&encCert->CertBlob,
594 encCert->CertType, encCert->CertEncoding, &certificate_ref);
595 if (os_status != 0) {
596 DLOG(ERROR) << "SecCertificateCreateFromData failed: " << os_status;
597 return NULL;
598 }
599 scoped_cert.reset(certificate_ref);
600 }
Ryan Sleevi 2011/02/05 00:23:37 BUG: You also need to free resultSet->Results and
dmac 2011/02/08 01:23:45 Done.
601 return CreateFromHandle(
602 scoped_cert, X509Certificate::SOURCE_LONE_CERT_IMPORT,
603 X509Certificate::OSCertHandles());
411 } 604 }
412 605
413 void X509Certificate::Persist(Pickle* pickle) { 606 void X509Certificate::Persist(Pickle* pickle) {
414 CSSM_DATA cert_data; 607 CSSM_DATA cert_data;
415 OSStatus status = SecCertificateGetData(cert_handle_, &cert_data); 608 OSStatus status = SecCertificateGetData(cert_handle_, &cert_data);
416 if (status) { 609 if (status) {
417 NOTREACHED(); 610 NOTREACHED();
418 return; 611 return;
419 } 612 }
420 613
(...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after
927 if (result) { 1120 if (result) {
928 LOG(ERROR) << "SecIdentityCreateWithCertificate error " << result; 1121 LOG(ERROR) << "SecIdentityCreateWithCertificate error " << result;
929 return NULL; 1122 return NULL;
930 } 1123 }
931 ScopedCFTypeRef<CFMutableArrayRef> chain( 1124 ScopedCFTypeRef<CFMutableArrayRef> chain(
932 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); 1125 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks));
933 CFArrayAppendValue(chain, identity); 1126 CFArrayAppendValue(chain, identity);
934 1127
935 CFArrayRef cert_chain = NULL; 1128 CFArrayRef cert_chain = NULL;
936 result = CopyCertChain(cert_handle_, &cert_chain); 1129 result = CopyCertChain(cert_handle_, &cert_chain);
1130 ScopedCFTypeRef<CFArrayRef> scoped_cert_chain(cert_chain);
937 if (result) { 1131 if (result) {
938 LOG(ERROR) << "CreateIdentityCertificateChain error " << result; 1132 LOG(ERROR) << "CreateIdentityCertificateChain error " << result;
939 return chain.release(); 1133 return chain.release();
940 } 1134 }
941 1135
942 // Append the intermediate certs from SecTrust to the result array: 1136 // Append the intermediate certs from SecTrust to the result array:
943 if (cert_chain) { 1137 if (cert_chain) {
944 int chain_count = CFArrayGetCount(cert_chain); 1138 int chain_count = CFArrayGetCount(cert_chain);
945 if (chain_count > 1) { 1139 if (chain_count > 1) {
946 CFArrayAppendArray(chain, 1140 CFArrayAppendArray(chain,
947 cert_chain, 1141 cert_chain,
948 CFRangeMake(1, chain_count - 1)); 1142 CFRangeMake(1, chain_count - 1));
949 } 1143 }
950 CFRelease(cert_chain);
951 } 1144 }
952 1145
953 return chain.release(); 1146 return chain.release();
954 } 1147 }
955 1148
956 } // namespace net 1149 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698