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

Unified 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, 11 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 side-by-side diff with in-line comments
Download patch
Index: net/base/x509_certificate_mac.cc
diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc
index 7c5cc643c650d0320b8ca227646c159f79d93235..c565cfa55196216fd8861db3515dab2714321d46 100644
--- a/net/base/x509_certificate_mac.cc
+++ b/net/base/x509_certificate_mac.cc
@@ -8,8 +8,13 @@
#include <Security/Security.h>
#include <time.h>
+#include <map>
+
+#include "base/crypto/cssm_init.h"
+#include "base/crypto/rsa_private_key.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/nss_util.h"
#include "base/pickle.h"
#include "base/singleton.h"
#include "base/mac/scoped_cftyperef.h"
@@ -18,6 +23,7 @@
#include "net/base/cert_verify_result.h"
#include "net/base/net_errors.h"
#include "net/base/test_root_certs.h"
+#include "third_party/nss/mozilla/security/nss/lib/certdb/cert.h"
using base::mac::ScopedCFTypeRef;
using base::Time;
@@ -369,6 +375,77 @@ void AddCertificatesFromBytes(const char* data, size_t length,
}
}
+struct CSSMOIDCompare {
+ bool operator()(const CSSM_OID* a, const CSSM_OID* b) const {
+ return a < b;
+ }
+};
+
+typedef std::map<const CSSM_OID*, std::string, CSSMOIDCompare> CSSMOIDMap;
+
+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.
+ struct OIDCSSMMap {
+ SECOidTag sec_OID_;
+ const CSSM_OID* cssm_OID_;
+ };
+
+ const OIDCSSMMap kOIDs[] = {
+ { SEC_OID_AVA_COMMON_NAME, &CSSMOID_CommonName },
+ { SEC_OID_AVA_COUNTRY_NAME, &CSSMOID_CountryName },
+ { SEC_OID_AVA_LOCALITY, &CSSMOID_LocalityName },
+ { SEC_OID_AVA_STATE_OR_PROVINCE, &CSSMOID_StateProvinceName },
+ { SEC_OID_AVA_STREET_ADDRESS, &CSSMOID_StreetAddress },
+ { SEC_OID_AVA_ORGANIZATION_NAME, &CSSMOID_OrganizationName },
+ { SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, &CSSMOID_OrganizationalUnitName },
+ { SEC_OID_AVA_DN_QUALIFIER, &CSSMOID_DNQualifier },
+ { SEC_OID_RFC1274_UID, &CSSMOID_UniqueIdentifier },
+ { SEC_OID_PKCS9_EMAIL_ADDRESS, &CSSMOID_EmailAddress },
+ };
+
+ CERTRDN** rdns = name->rdns;
+ for (size_t rdn = 0; rdns[rdn]; ++rdn) {
+ CERTAVA** avas = rdns[rdn]->avas;
+ for (size_t pair = 0; avas[pair] != 0; ++pair) {
+ SECOidTag tag = CERT_GetAVATag(avas[pair]);
+ if (tag == SEC_OID_UNKNOWN) {
+ return false;
+ }
+ bool found_oid = false;
+ for (size_t oid = 0; oid < ARRAYSIZE_UNSAFE(kOIDs); ++oid) {
+ if (kOIDs[oid].sec_OID_ == tag) {
+ SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value);
+ if (!decode_item) {
+ return false;
+ }
+ // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote.
+ std::string value(reinterpret_cast<char*>(decode_item->data),
+ decode_item->len);
+ (*out_values)[kOIDs[oid].cssm_OID_] = value;
+ SECITEM_FreeItem(decode_item, PR_TRUE);
+ found_oid = true;
+ break;
+ }
+ }
+ if (!found_oid) {
+ DLOG(ERROR) << "Unrecognized OID: " << tag;
+ }
+ }
+ }
+ return true;
+}
+
+class ScopedCertName {
+ public:
+ explicit ScopedCertName(CERTName* name) : name_(name) { }
+ ~ScopedCertName() {
+ if (name_) CERT_DestroyName(name_);
+ }
+ operator CERTName*() { return name_; }
+
+ private:
+ CERTName* name_;
+};
+
} // namespace
void X509Certificate::Initialize() {
@@ -406,8 +483,124 @@ X509Certificate* X509Certificate::CreateSelfSigned(
const std::string& subject,
uint32 serial_number,
base::TimeDelta valid_duration) {
- // TODO(port): Implement.
- return NULL;
+ DCHECK(key);
+ DCHECK(subject.length() > 0);
Ryan Sleevi 2011/02/05 00:23:37 nit: DCHECK(!subject.empty()) or DCHECK_GT(subject
+
+ // There is a comment in
+ // http://www.opensource.apple.com/source/security_certtool/security_certtool-31828/src/CertTool.cpp
+ // that serial_numbers being passed into CSSM_TP_SubmitCredRequest can't have
+ // their high bit set. We will continue though and mask it out below.
+ if (serial_number & 0x80000000) {
+ LOG(ERROR) << "serial_number has high bit set " << serial_number;
+ }
+
+ // NSS is used to parse the subject string into a set of
+ // CSSM_OID/string pairs. There doesn't appear to be a system routine for
+ // parsing Distinguished Name strings.
+ base::EnsureNSSInit();
+
+ CSSMOIDMap subject_name_oids;
+ ScopedCertName subject_name(
+ CERT_AsciiToName(const_cast<char*>(subject.c_str())));
+ if (!CERTNameToCSSMOIDMap(subject_name, &subject_name_oids)) {
+ DLOG(ERROR) << "Unable to generate CSSMOIDMap from " << subject;
+ return NULL;
+ }
+
+ // Convert the map of oid/string pairs into an array of
+ // CSSM_APPLE_TP_NAME_OIDs.
+ std::vector<CSSM_APPLE_TP_NAME_OID> cssm_subject_names;
+ for(CSSMOIDMap::iterator iter = subject_name_oids.begin();
+ iter != subject_name_oids.end(); ++iter) {
+ CSSM_APPLE_TP_NAME_OID cssm_subject_name;
+ cssm_subject_name.oid = iter->first;
+ cssm_subject_name.string = iter->second.c_str();
+ cssm_subject_names.push_back(cssm_subject_name);
+ }
+
+ if (cssm_subject_names.size() == 0) {
+ DLOG(ERROR) << "cssm_subject_names.size() == 0. Input: " << subject;
+ return NULL;
+ }
+
+ // Set up a certificate request.
+ CSSM_APPLE_TP_CERT_REQUEST certReq;
+ memset(&certReq, 0, sizeof(certReq));
+ certReq.challengeString = NULL;
+ certReq.cspHand = base::GetSharedCSPHandle();
+ certReq.clHand = base::GetSharedCLHandle();
+ certReq.numSubjectNames = cssm_subject_names.size();
+ certReq.subjectNames = &cssm_subject_names[0];
+ // See comment about serial numbers above.
+ certReq.serialNumber = serial_number & 0x7f000000;
+ certReq.numIssuerNames = 0; // Root.
+ certReq.issuerNames = NULL;
+ certReq.issuerNameX509 = NULL;
+ certReq.certPublicKey = key->public_key();
+ certReq.issuerPrivateKey = key->key();
+ // 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.
+ certReq.signatureAlg = CSSM_ALGID_SHA1WithRSA;
+ certReq.signatureOid = CSSMOID_SHA1WithRSA;
+ certReq.notBefore = 0;
+ 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.
+ certReq.numExtensions = 0;
+ certReq.extensions = NULL;
+
+ CSSM_TP_REQUEST_SET reqSet;
+ reqSet.NumberOfRequests = 1;
+ reqSet.Requests = &certReq;
+
+ CSSM_FIELD policyId;
+ memset(&policyId, 0, sizeof(policyId));
+ policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN;
+
+ CSSM_TP_CALLERAUTH_CONTEXT callerAuthContext;
+ memset(&callerAuthContext, 0, sizeof(callerAuthContext));
+ callerAuthContext.Policy.NumberOfPolicyIds = 1;
+ callerAuthContext.Policy.PolicyIds = &policyId;
+
+ CSSM_TP_HANDLE tp_handle = base::GetSharedTPHandle();
+ base::ScopedCSSMData refId;
+ sint32 estTime;
+ CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest(
+ tp_handle, NULL, CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, &reqSet,
+ &callerAuthContext, &estTime, refId);
+ if(crtn) {
+ DLOG(ERROR) << "CSSM_TP_SubmitCredRequest failed " << crtn;
+ return NULL;
+ }
+
+ CSSM_BOOL confirmRequired;
+ base::ScopedCSSMTPtr<CSSM_TP_RESULT_SET> resultSet;
+ crtn = CSSM_TP_RetrieveCredResult(tp_handle, refId, NULL, &estTime,
+ &confirmRequired, &resultSet.receive());
+ if (crtn) {
+ DLOG(ERROR) << "CSSM_TP_RetrieveCredResult failed " << crtn;
+ return NULL;
+ }
+
+ 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.
+ DLOG(ERROR) << "CSSM_TP_RetrieveCredResult required confirmation";
+ return NULL;
+ }
+
Ryan Sleevi 2011/02/05 00:23:37 BUG: Check that resultSet->NumberOfResults == 1 be
dmac 2011/02/08 01:23:45 Done.
+ CSSM_ENCODED_CERT* encCert =
+ reinterpret_cast<CSSM_ENCODED_CERT*>(resultSet->Results);
+ base::mac::ScopedCFTypeRef<SecCertificateRef> scoped_cert;
+ {
+ 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.
+ SecCertificateRef certificate_ref = NULL;
+ OSStatus os_status = SecCertificateCreateFromData(&encCert->CertBlob,
+ encCert->CertType, encCert->CertEncoding, &certificate_ref);
+ if (os_status != 0) {
+ DLOG(ERROR) << "SecCertificateCreateFromData failed: " << os_status;
+ return NULL;
+ }
+ scoped_cert.reset(certificate_ref);
+ }
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.
+ return CreateFromHandle(
+ scoped_cert, X509Certificate::SOURCE_LONE_CERT_IMPORT,
+ X509Certificate::OSCertHandles());
}
void X509Certificate::Persist(Pickle* pickle) {
@@ -934,6 +1127,7 @@ CFArrayRef X509Certificate::CreateClientCertificateChain() const {
CFArrayRef cert_chain = NULL;
result = CopyCertChain(cert_handle_, &cert_chain);
+ ScopedCFTypeRef<CFArrayRef> scoped_cert_chain(cert_chain);
if (result) {
LOG(ERROR) << "CreateIdentityCertificateChain error " << result;
return chain.release();
@@ -947,7 +1141,6 @@ CFArrayRef X509Certificate::CreateClientCertificateChain() const {
cert_chain,
CFRangeMake(1, chain_count - 1));
}
- CFRelease(cert_chain);
}
return chain.release();

Powered by Google App Engine
This is Rietveld 408576698