summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordmaclach@chromium.org <dmaclach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-08 14:28:29 +0000
committerdmaclach@chromium.org <dmaclach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-08 14:28:29 +0000
commiteed0011868749ef759ab95cb906fc0fe8e23cde1 (patch)
tree88c449642e823cb60826b424c01fa4ceac2d7b7e
parent13f50ec8d5db4bc3b6dd5f2b062f96cd9f5cc031 (diff)
downloadchromium_src-eed0011868749ef759ab95cb906fc0fe8e23cde1.zip
chromium_src-eed0011868749ef759ab95cb906fc0fe8e23cde1.tar.gz
chromium_src-eed0011868749ef759ab95cb906fc0fe8e23cde1.tar.bz2
Add ability to create self signed certs to mac.
BUG=67929 TEST=BUILD Review URL: http://codereview.chromium.org/6312157 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@74115 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/crypto/cssm_init.cc134
-rw-r--r--base/crypto/cssm_init.h31
-rw-r--r--base/crypto/rsa_private_key.cc32
-rw-r--r--base/crypto/rsa_private_key.h6
-rw-r--r--base/crypto/rsa_private_key_mac.cc51
-rw-r--r--base/crypto/signature_creator_mac.cc10
-rw-r--r--net/DEPS1
-rw-r--r--net/base/x509_certificate_mac.cc235
-rw-r--r--net/base/x509_certificate_unittest.cc98
9 files changed, 537 insertions, 61 deletions
diff --git a/base/crypto/cssm_init.cc b/base/crypto/cssm_init.cc
index eea9d1b..570dcc3 100644
--- a/base/crypto/cssm_init.cc
+++ b/base/crypto/cssm_init.cc
@@ -7,6 +7,7 @@
#include <Security/SecBase.h>
#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
#include "base/singleton.h"
#include "base/synchronization/lock.h"
#include "base/sys_string_conversions.h"
@@ -20,6 +21,22 @@
namespace {
+void* CSSMMalloc(CSSM_SIZE size, void* alloc_ref) {
+ return malloc(size);
+}
+
+void CSSMFree(void* mem_ptr, void* alloc_ref) {
+ free(mem_ptr);
+}
+
+void* CSSMRealloc(void* ptr, CSSM_SIZE size, void* alloc_ref) {
+ return realloc(ptr, size);
+}
+
+void* CSSMCalloc(uint32 num, CSSM_SIZE size, void* alloc_ref) {
+ return calloc(num, size);
+}
+
class CSSMInitSingleton {
public:
static CSSMInitSingleton* GetInstance() {
@@ -27,10 +44,15 @@ class CSSMInitSingleton {
LeakySingletonTraits<CSSMInitSingleton> >::get();
}
- CSSM_CSP_HANDLE csp_handle() const { return csp_handle_; }
+ CSSM_CSP_HANDLE csp_handle() const { return csp_handle_; }
+ CSSM_CL_HANDLE cl_handle() const { return cl_handle_; }
+ CSSM_TP_HANDLE tp_handle() const { return tp_handle_; }
private:
- CSSMInitSingleton() : inited_(false), loaded_(false), csp_handle_(NULL) {
+ CSSMInitSingleton()
+ : inited_(false), csp_loaded_(false), cl_loaded_(false),
+ tp_loaded_(false), csp_handle_(NULL), cl_handle_(NULL),
+ tp_handle_(NULL) {
static CSSM_VERSION version = {2, 0};
// TODO(wtc): what should our caller GUID be?
static const CSSM_GUID test_guid = {
@@ -51,13 +73,42 @@ class CSSMInitSingleton {
NOTREACHED();
return;
}
- loaded_ = true;
+ csp_loaded_ = true;
+ crtn = CSSM_ModuleLoad(
+ &gGuidAppleX509CL, CSSM_KEY_HIERARCHY_NONE, NULL, NULL);
+ if (crtn) {
+ NOTREACHED();
+ return;
+ }
+ cl_loaded_ = true;
+ crtn = CSSM_ModuleLoad(
+ &gGuidAppleX509TP, CSSM_KEY_HIERARCHY_NONE, NULL, NULL);
+ if (crtn) {
+ NOTREACHED();
+ return;
+ }
+ tp_loaded_ = true;
+
+ const CSSM_API_MEMORY_FUNCS cssmMemoryFunctions = {
+ CSSMMalloc,
+ CSSMFree,
+ CSSMRealloc,
+ CSSMCalloc,
+ NULL
+ };
- crtn = CSSM_ModuleAttach(&gGuidAppleCSP, &version,
- &base::kCssmMemoryFunctions, 0,
+ crtn = CSSM_ModuleAttach(&gGuidAppleCSP, &version, &cssmMemoryFunctions, 0,
CSSM_SERVICE_CSP, 0, CSSM_KEY_HIERARCHY_NONE,
NULL, 0, NULL, &csp_handle_);
DCHECK(crtn == CSSM_OK);
+ crtn = CSSM_ModuleAttach(&gGuidAppleX509CL, &version, &cssmMemoryFunctions,
+ 0, CSSM_SERVICE_CL, 0, CSSM_KEY_HIERARCHY_NONE,
+ NULL, 0, NULL, &cl_handle_);
+ DCHECK(crtn == CSSM_OK);
+ crtn = CSSM_ModuleAttach(&gGuidAppleX509TP, &version, &cssmMemoryFunctions,
+ 0, CSSM_SERVICE_TP, 0, CSSM_KEY_HIERARCHY_NONE,
+ NULL, 0, NULL, &tp_handle_);
+ DCHECK(crtn == CSSM_OK);
}
~CSSMInitSingleton() {
@@ -66,10 +117,26 @@ class CSSMInitSingleton {
CSSM_RETURN crtn = CSSM_ModuleDetach(csp_handle_);
DCHECK(crtn == CSSM_OK);
}
- if (loaded_) {
+ if (cl_handle_) {
+ CSSM_RETURN crtn = CSSM_ModuleDetach(cl_handle_);
+ DCHECK(crtn == CSSM_OK);
+ }
+ if (tp_handle_) {
+ CSSM_RETURN crtn = CSSM_ModuleDetach(tp_handle_);
+ DCHECK(crtn == CSSM_OK);
+ }
+ if (csp_loaded_) {
crtn = CSSM_ModuleUnload(&gGuidAppleCSP, NULL, NULL);
DCHECK(crtn == CSSM_OK);
}
+ if (cl_loaded_) {
+ crtn = CSSM_ModuleUnload(&gGuidAppleX509CL, NULL, NULL);
+ DCHECK(crtn == CSSM_OK);
+ }
+ if (tp_loaded_) {
+ crtn = CSSM_ModuleUnload(&gGuidAppleX509TP, NULL, NULL);
+ DCHECK(crtn == CSSM_OK);
+ }
if (inited_) {
crtn = CSSM_Terminate();
DCHECK(crtn == CSSM_OK);
@@ -77,8 +144,12 @@ class CSSMInitSingleton {
}
bool inited_; // True if CSSM_Init has been called successfully.
- bool loaded_; // True if CSSM_ModuleLoad has been called successfully.
+ bool csp_loaded_; // True if gGuidAppleCSP has been loaded
+ bool cl_loaded_; // True if gGuidAppleX509CL has been loaded.
+ bool tp_loaded_; // True if gGuidAppleX509TP has been loaded.
CSSM_CSP_HANDLE csp_handle_;
+ CSSM_CL_HANDLE cl_handle_;
+ CSSM_TP_HANDLE tp_handle_;
friend struct DefaultSingletonTraits<CSSMInitSingleton>;
};
@@ -117,45 +188,44 @@ CSSM_CSP_HANDLE GetSharedCSPHandle() {
return CSSMInitSingleton::GetInstance()->csp_handle();
}
-void* CSSMMalloc(CSSM_SIZE size, void *alloc_ref) {
- return malloc(size);
+CSSM_CL_HANDLE GetSharedCLHandle() {
+ return CSSMInitSingleton::GetInstance()->cl_handle();
}
-void CSSMFree(void* mem_ptr, void* alloc_ref) {
- free(mem_ptr);
+CSSM_TP_HANDLE GetSharedTPHandle() {
+ return CSSMInitSingleton::GetInstance()->tp_handle();
}
-void* CSSMRealloc(void* ptr, CSSM_SIZE size, void* alloc_ref) {
- return realloc(ptr, size);
+void* CSSMMalloc(CSSM_SIZE size) {
+ return ::CSSMMalloc(size, NULL);
}
-void* CSSMCalloc(uint32 num, CSSM_SIZE size, void* alloc_ref) {
- return calloc(num, size);
+void CSSMFree(void* ptr) {
+ ::CSSMFree(ptr, NULL);
}
-const CSSM_API_MEMORY_FUNCS kCssmMemoryFunctions = {
- CSSMMalloc,
- CSSMFree,
- CSSMRealloc,
- CSSMCalloc,
- NULL
-};
-
-void LogCSSMError(const char *fn_name, CSSM_RETURN err) {
+void LogCSSMError(const char* fn_name, CSSM_RETURN err) {
if (!err)
return;
- CFStringRef cfstr = SecCopyErrorMessageString(err, NULL);
- if (cfstr) {
- std::string err_name = SysCFStringRefToUTF8(cfstr);
- CFRelease(cfstr);
- LOG(ERROR) << fn_name << " returned " << err << " (" << err_name << ")";
- } else {
- LOG(ERROR) << fn_name << " returned " << err;
- }
+ base::mac::ScopedCFTypeRef<CFStringRef> cfstr(
+ SecCopyErrorMessageString(err, NULL));
+ LOG(ERROR) << fn_name << " returned " << err
+ << " (" << SysCFStringRefToUTF8(cfstr) << ")";
}
base::Lock& GetMacSecurityServicesLock() {
return SecurityServicesSingleton::GetInstance()->lock();
}
+ScopedCSSMData::ScopedCSSMData() {
+ memset(&data_, 0, sizeof(data_));
+}
+
+ScopedCSSMData::~ScopedCSSMData() {
+ if (data_.Data) {
+ CSSMFree(data_.Data);
+ data_.Data = NULL;
+ }
+}
+
} // namespace base
diff --git a/base/crypto/cssm_init.h b/base/crypto/cssm_init.h
index 5644d7e..b51a3b5 100644
--- a/base/crypto/cssm_init.h
+++ b/base/crypto/cssm_init.h
@@ -8,7 +8,7 @@
#include <Security/cssm.h>
-#include "base/scoped_ptr.h"
+#include "base/basictypes.h"
namespace base {
@@ -22,12 +22,22 @@ void EnsureCSSMInit();
// Returns the shared CSP handle used by CSSM functions.
CSSM_CSP_HANDLE GetSharedCSPHandle();
+// Returns the shared CL handle used by CSSM functions.
+CSSM_CL_HANDLE GetSharedCLHandle();
+
+// Returns the shared TP handle used by CSSM functions.
+CSSM_TP_HANDLE GetSharedTPHandle();
+
// Set of pointers to memory function wrappers that are required for CSSM
extern const CSSM_API_MEMORY_FUNCS kCssmMemoryFunctions;
// Utility function to log an error message including the error name.
void LogCSSMError(const char *function_name, CSSM_RETURN err);
+// Utility functions to allocate and release CSSM memory.
+void* CSSMMalloc(CSSM_SIZE size);
+void CSSMFree(void* ptr);
+
// The OS X certificate and key management wrappers over CSSM are not
// thread-safe. In particular, code that accesses the CSSM database is
// problematic.
@@ -35,6 +45,25 @@ void LogCSSMError(const char *function_name, CSSM_RETURN err);
// http://developer.apple.com/mac/library/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html
Lock& GetMacSecurityServicesLock();
+// Wrapper class for CSSM_DATA type. This should only be used when using the
+// CL/TP/CSP handles from above, since that's the only time we're guaranteed (or
+// supposed to be guaranteed) that our memory management functions will be used.
+// Apple's Sec* APIs manage their own memory so it shouldn't be used for those.
+// The constructor initializes data_ to zero and the destructor releases the
+// data properly.
+class ScopedCSSMData {
+ public:
+ ScopedCSSMData();
+ ~ScopedCSSMData();
+ operator CSSM_DATA*() { return &data_; }
+ CSSM_DATA* operator ->() { return &data_; }
+
+ private:
+ CSSM_DATA data_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedCSSMData);
+};
+
} // namespace base
#endif // BASE_CRYPTO_CSSM_INIT_H_
diff --git a/base/crypto/rsa_private_key.cc b/base/crypto/rsa_private_key.cc
index 2ab0c14..024f741 100644
--- a/base/crypto/rsa_private_key.cc
+++ b/base/crypto/rsa_private_key.cc
@@ -89,19 +89,12 @@ bool PrivateKeyInfoCodec::Export(std::vector<uint8>* output) {
bool PrivateKeyInfoCodec::ExportPublicKeyInfo(std::vector<uint8>* output) {
// Create a sequence with the modulus (n) and public exponent (e).
- std::list<uint8> content;
- PrependInteger(&public_exponent_[0],
- static_cast<int>(public_exponent_.size()),
- &content);
- PrependInteger(&modulus_[0], static_cast<int>(modulus_.size()), &content);
- PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content);
-
- // Copy the sequence with n and e into a buffer.
std::vector<uint8> bit_string;
- for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i)
- bit_string.push_back(*i);
- content.clear();
+ if (!ExportPublicKey(&bit_string))
+ return false;
+
// Add the sequence as the contents of a bit string.
+ std::list<uint8> content;
PrependBitString(&bit_string[0], static_cast<int>(bit_string.size()),
&content);
@@ -120,6 +113,23 @@ bool PrivateKeyInfoCodec::ExportPublicKeyInfo(std::vector<uint8>* output) {
return true;
}
+bool PrivateKeyInfoCodec::ExportPublicKey(std::vector<uint8>* output) {
+ // Create a sequence with the modulus (n) and public exponent (e).
+ std::list<uint8> content;
+ PrependInteger(&public_exponent_[0],
+ static_cast<int>(public_exponent_.size()),
+ &content);
+ PrependInteger(&modulus_[0], static_cast<int>(modulus_.size()), &content);
+ PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content);
+
+ // Copy everything into the output.
+ output->reserve(content.size());
+ for (std::list<uint8>::iterator i = content.begin(); i != content.end(); ++i)
+ output->push_back(*i);
+
+ return true;
+}
+
bool PrivateKeyInfoCodec::Import(const std::vector<uint8>& input) {
if (input.empty()) {
return false;
diff --git a/base/crypto/rsa_private_key.h b/base/crypto/rsa_private_key.h
index 9b8b4fd..5357adc 100644
--- a/base/crypto/rsa_private_key.h
+++ b/base/crypto/rsa_private_key.h
@@ -64,6 +64,10 @@ class PrivateKeyInfoCodec {
// of the PublicKeyInfo structure to |output|.
bool ExportPublicKeyInfo(std::vector<uint8>* output);
+ // Exports the contents of the integer components to the ASN.1 DER encoding
+ // of the RSAPublicKey structure to |output|.
+ bool ExportPublicKey(std::vector<uint8>* output);
+
// Parses the ASN.1 DER encoding of the PrivateKeyInfo structure in |input|
// and populates the integer components with |big_endian_| byte-significance.
// IMPORTANT NOTE: This is currently *not* security-approved for importing
@@ -215,6 +219,7 @@ class RSAPrivateKey {
HCRYPTKEY key() { return key_; }
#elif defined(OS_MACOSX)
CSSM_KEY_PTR key() { return &key_; }
+ CSSM_KEY_PTR public_key() { return &public_key_; }
#endif
// Exports the private key to a PKCS #1 PrivateKey block.
@@ -257,6 +262,7 @@ class RSAPrivateKey {
ScopedHCRYPTKEY key_;
#elif defined(OS_MACOSX)
CSSM_KEY key_;
+ CSSM_KEY public_key_;
#endif
DISALLOW_COPY_AND_ASSIGN(RSAPrivateKey);
diff --git a/base/crypto/rsa_private_key_mac.cc b/base/crypto/rsa_private_key_mac.cc
index e46e93e..ede8014 100644
--- a/base/crypto/rsa_private_key_mac.cc
+++ b/base/crypto/rsa_private_key_mac.cc
@@ -26,14 +26,12 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
return NULL;
}
- CSSM_KEY public_key;
- memset(&public_key, 0, sizeof(CSSM_KEY));
CSSM_DATA label = { 9,
const_cast<uint8*>(reinterpret_cast<const uint8*>("temp_key")) };
crtn = CSSM_GenerateKeyPair(cc_handle,
CSSM_KEYUSE_VERIFY,
CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label,
- &public_key, CSSM_KEYUSE_SIGN,
+ result->public_key(), CSSM_KEYUSE_SIGN,
CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label, NULL,
result->key());
CSSM_DeleteContext(cc_handle);
@@ -42,9 +40,6 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
return NULL;
}
- // Public key is not needed.
- CSSM_FreeKey(GetSharedCSPHandle(), NULL, &public_key, CSSM_FALSE);
-
return result.release();
}
@@ -106,6 +101,46 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
return NULL;
}
+ // Extract a public key from the private key.
+ // Apple doesn't accept CSSM_KEYBLOB_RAW_FORMAT_X509 as a valid key
+ // format when attempting to generate certs, so use PKCS1 instead.
+ PrivateKeyInfoCodec codec(true);
+ std::vector<uint8> private_key_data;
+ private_key_data.assign(key.KeyData.Data,
+ key.KeyData.Data + key.KeyData.Length);
+ if (!codec.Import(private_key_data)) {
+ return NULL;
+ }
+ std::vector<uint8> public_key_data;
+ if (!codec.ExportPublicKey(&public_key_data)) {
+ return NULL;
+ }
+
+ CSSM_KEY* public_key = result->public_key();
+ size_t size = public_key_data.size();
+ public_key->KeyData.Data = reinterpret_cast<uint8*>(CSSMMalloc(size));
+ if (!public_key->KeyData.Data) {
+ NOTREACHED() << "CSSMMalloc failed";
+ return NULL;
+ }
+ memcpy(public_key->KeyData.Data, &public_key_data.front(), size);
+ public_key->KeyData.Length = size;
+ public_key->KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
+ public_key->KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
+ public_key->KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
+ public_key->KeyHeader.AlgorithmId = CSSM_ALGID_RSA;
+ public_key->KeyHeader.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
+ public_key->KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
+ public_key->KeyHeader.KeyUsage = CSSM_KEYUSE_ANY;
+
+ crtn = CSSM_QueryKeySizeInBits(
+ base::GetSharedCSPHandle(), NULL, public_key, &key_size);
+ if (crtn) {
+ DLOG(ERROR) << "CSSM_QueryKeySizeInBits failed " << crtn;
+ return NULL;
+ }
+ public_key->KeyHeader.LogicalKeySizeInBits = key_size.LogicalKeySizeInBits;
+
return result.release();
}
@@ -125,6 +160,7 @@ RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
RSAPrivateKey::RSAPrivateKey() {
memset(&key_, 0, sizeof(key_));
+ memset(&public_key_, 0, sizeof(public_key_));
EnsureCSSMInit();
}
@@ -133,6 +169,9 @@ RSAPrivateKey::~RSAPrivateKey() {
if (key_.KeyData.Data) {
CSSM_FreeKey(GetSharedCSPHandle(), NULL, &key_, CSSM_FALSE);
}
+ if (public_key_.KeyData.Data) {
+ CSSM_FreeKey(GetSharedCSPHandle(), NULL, &public_key_, CSSM_FALSE);
+ }
}
bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) {
diff --git a/base/crypto/signature_creator_mac.cc b/base/crypto/signature_creator_mac.cc
index d10d54c..1001c64 100644
--- a/base/crypto/signature_creator_mac.cc
+++ b/base/crypto/signature_creator_mac.cc
@@ -59,19 +59,15 @@ bool SignatureCreator::Update(const uint8* data_part, int data_part_len) {
}
bool SignatureCreator::Final(std::vector<uint8>* signature) {
- CSSM_DATA sig;
- memset(&sig, 0, sizeof(CSSM_DATA)); // Allow CSSM allocate memory;
- CSSM_RETURN crtn = CSSM_SignDataFinal(sig_handle_, &sig);
+ ScopedCSSMData sig;
+ CSSM_RETURN crtn = CSSM_SignDataFinal(sig_handle_, sig);
if (crtn) {
NOTREACHED();
return false;
}
- signature->assign(sig.Data, sig.Data + sig.Length);
- kCssmMemoryFunctions.free_func(sig.Data, NULL); // Release data alloc'd
- // by CSSM
-
+ signature->assign(sig->Data, sig->Data + sig->Length);
return true;
}
diff --git a/net/DEPS b/net/DEPS
index 49f0344..d4488e77 100644
--- a/net/DEPS
+++ b/net/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+third_party/libevent",
+ "+third_party/nss",
"+third_party/zlib",
"+sdch/open_vcdiff",
]
diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc
index 7c5cc64..3cc1e08 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 <vector>
+
+#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,99 @@ void AddCertificatesFromBytes(const char* data, size_t length,
}
}
+struct CSSMOIDString {
+ const CSSM_OID* oid_;
+ std::string string_;
+};
+
+typedef std::vector<CSSMOIDString> CSSMOIDStringVector;
+
+bool CERTNameToCSSMOIDVector(CERTName* name, CSSMOIDStringVector* out_values) {
+ 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;
+ }
+ CSSMOIDString oidString;
+ 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);
+ oidString.oid_ = kOIDs[oid].cssm_OID_;
+ oidString.string_ = value;
+ out_values->push_back(oidString);
+ 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_;
+};
+
+class ScopedEncodedCertResults {
+ public:
+ explicit ScopedEncodedCertResults(CSSM_TP_RESULT_SET* results)
+ : results_(results) { }
+ ~ScopedEncodedCertResults() {
+ if (results_) {
+ CSSM_ENCODED_CERT* encCert =
+ reinterpret_cast<CSSM_ENCODED_CERT*>(results_->Results);
+ for (uint32 i = 0; i < results_->NumberOfResults; i++) {
+ base::CSSMFree(encCert[i].CertBlob.Data);
+ }
+ }
+ base::CSSMFree(results_->Results);
+ base::CSSMFree(results_);
+ }
+
+private:
+ CSSM_TP_RESULT_SET* results_;
+};
+
} // namespace
void X509Certificate::Initialize() {
@@ -406,8 +505,138 @@ X509Certificate* X509Certificate::CreateSelfSigned(
const std::string& subject,
uint32 serial_number,
base::TimeDelta valid_duration) {
- // TODO(port): Implement.
- return NULL;
+ DCHECK(key);
+ DCHECK(!subject.empty());
+
+ if (valid_duration.InSeconds() > UINT32_MAX) {
+ LOG(ERROR) << "valid_duration too big" << valid_duration.InSeconds();
+ valid_duration = base::TimeDelta::FromSeconds(UINT32_MAX);
+ }
+
+ // 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();
+
+ CSSMOIDStringVector subject_name_oids;
+ ScopedCertName subject_name(
+ CERT_AsciiToName(const_cast<char*>(subject.c_str())));
+ if (!CERTNameToCSSMOIDVector(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(CSSMOIDStringVector::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->oid_;
+ cssm_subject_name.string = iter->string_.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.cspHand = base::GetSharedCSPHandle();
+ certReq.clHand = base::GetSharedCLHandle();
+ // See comment about serial numbers above.
+ certReq.serialNumber = serial_number & 0x7fffffff;
+ certReq.numSubjectNames = cssm_subject_names.size();
+ certReq.subjectNames = &cssm_subject_names[0];
+ certReq.numIssuerNames = 0; // Root.
+ certReq.issuerNames = NULL;
+ certReq.issuerNameX509 = NULL;
+ certReq.certPublicKey = key->public_key();
+ certReq.issuerPrivateKey = key->key();
+ // These are the Apple defaults.
+ certReq.signatureAlg = CSSM_ALGID_SHA1WithRSA;
+ certReq.signatureOid = CSSMOID_SHA1WithRSA;
+ certReq.notBefore = 0;
+ certReq.notAfter = static_cast<uint32>(valid_duration.InSeconds());
+ certReq.numExtensions = 0;
+ certReq.extensions = NULL;
+ certReq.challengeString = 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();
+ CSSM_DATA refId;
+ memset(&refId, 0, sizeof(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;
+ CSSM_TP_RESULT_SET *resultSet = NULL;
+ crtn = CSSM_TP_RetrieveCredResult(tp_handle, &refId, NULL, &estTime,
+ &confirmRequired, &resultSet);
+ ScopedEncodedCertResults scopedResults(resultSet);
+ base::CSSMFree(refId.Data);
+ if (crtn) {
+ DLOG(ERROR) << "CSSM_TP_RetrieveCredResult failed " << crtn;
+ return NULL;
+ }
+
+ if (confirmRequired) {
+ // Potential leak here of resultSet. |confirmRequired| should never be
+ // true.
+ DLOG(ERROR) << "CSSM_TP_RetrieveCredResult required confirmation";
+ return NULL;
+ }
+
+ if (resultSet->NumberOfResults != 1) {
+ DLOG(ERROR) << "Unexpected number of results: "
+ << resultSet->NumberOfResults;
+ return NULL;
+ }
+
+ CSSM_ENCODED_CERT* encCert =
+ reinterpret_cast<CSSM_ENCODED_CERT*>(resultSet->Results);
+ base::mac::ScopedCFTypeRef<SecCertificateRef> scoped_cert;
+ 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);
+
+ return CreateFromHandle(
+ scoped_cert, X509Certificate::SOURCE_LONE_CERT_IMPORT,
+ X509Certificate::OSCertHandles());
}
void X509Certificate::Persist(Pickle* pickle) {
@@ -934,6 +1163,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 +1177,6 @@ CFArrayRef X509Certificate::CreateClientCertificateChain() const {
cert_chain,
CFRangeMake(1, chain_count - 1));
}
- CFRelease(cert_chain);
}
return chain.release();
diff --git a/net/base/x509_certificate_unittest.cc b/net/base/x509_certificate_unittest.cc
index 7bd17fb..54af784 100644
--- a/net/base/x509_certificate_unittest.cc
+++ b/net/base/x509_certificate_unittest.cc
@@ -659,7 +659,7 @@ TEST(X509CertificateTest, IsIssuedBy) {
}
#endif // defined(OS_MACOSX)
-#if defined(USE_NSS) || defined(OS_WIN)
+#if defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX)
// This test creates a self-signed cert from a private key and then verify the
// content of the certificate.
TEST(X509CertificateTest, CreateSelfSigned) {
@@ -671,6 +671,102 @@ TEST(X509CertificateTest, CreateSelfSigned) {
EXPECT_EQ("subject", cert->subject().GetDisplayName());
EXPECT_FALSE(cert->HasExpired());
+
+ const uint8 private_key_info[] = {
+ 0x30, 0x82, 0x02, 0x78, 0x02, 0x01, 0x00, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
+ 0x02, 0x62, 0x30, 0x82, 0x02, 0x5e, 0x02, 0x01,
+ 0x00, 0x02, 0x81, 0x81, 0x00, 0xb8, 0x7f, 0x2b,
+ 0x20, 0xdc, 0x7c, 0x9b, 0x0c, 0xdc, 0x51, 0x61,
+ 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08,
+ 0x55, 0x84, 0xd5, 0x3a, 0xbf, 0x2b, 0xa4, 0x64,
+ 0x85, 0x7b, 0x0c, 0x04, 0x13, 0x3f, 0x8d, 0xf4,
+ 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a,
+ 0xb0, 0x40, 0x53, 0x3a, 0xd7, 0x66, 0x09, 0x0f,
+ 0x9e, 0x36, 0x74, 0x30, 0xda, 0x8a, 0x31, 0x4f,
+ 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17,
+ 0xde, 0x4e, 0xb9, 0x57, 0x5e, 0x7e, 0x0a, 0xe5,
+ 0xb2, 0x65, 0x7a, 0x89, 0x4e, 0xb6, 0x47, 0xff,
+ 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85,
+ 0x84, 0x32, 0x33, 0xf3, 0x17, 0x49, 0xbf, 0xe9,
+ 0x96, 0xd0, 0xd6, 0x14, 0x6f, 0x13, 0x8d, 0xc5,
+ 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18,
+ 0x53, 0x56, 0xa6, 0x83, 0xa2, 0xce, 0x93, 0x93,
+ 0xe7, 0x1f, 0x0f, 0xe6, 0x0f, 0x02, 0x03, 0x01,
+ 0x00, 0x01, 0x02, 0x81, 0x80, 0x03, 0x61, 0x89,
+ 0x37, 0xcb, 0xf2, 0x98, 0xa0, 0xce, 0xb4, 0xcb,
+ 0x16, 0x13, 0xf0, 0xe6, 0xaf, 0x5c, 0xc5, 0xa7,
+ 0x69, 0x71, 0xca, 0xba, 0x8d, 0xe0, 0x4d, 0xdd,
+ 0xed, 0xb8, 0x48, 0x8b, 0x16, 0x93, 0x36, 0x95,
+ 0xc2, 0x91, 0x40, 0x65, 0x17, 0xbd, 0x7f, 0xd6,
+ 0xad, 0x9e, 0x30, 0x28, 0x46, 0xe4, 0x3e, 0xcc,
+ 0x43, 0x78, 0xf9, 0xfe, 0x1f, 0x33, 0x23, 0x1e,
+ 0x31, 0x12, 0x9d, 0x3c, 0xa7, 0x08, 0x82, 0x7b,
+ 0x7d, 0x25, 0x4e, 0x5e, 0x19, 0xa8, 0x9b, 0xed,
+ 0x86, 0xb2, 0xcb, 0x3c, 0xfe, 0x4e, 0xa1, 0xfa,
+ 0x62, 0x87, 0x3a, 0x17, 0xf7, 0x60, 0xec, 0x38,
+ 0x29, 0xe8, 0x4f, 0x34, 0x9f, 0x76, 0x9d, 0xee,
+ 0xa3, 0xf6, 0x85, 0x6b, 0x84, 0x43, 0xc9, 0x1e,
+ 0x01, 0xff, 0xfd, 0xd0, 0x29, 0x4c, 0xfa, 0x8e,
+ 0x57, 0x0c, 0xc0, 0x71, 0xa5, 0xbb, 0x88, 0x46,
+ 0x29, 0x5c, 0xc0, 0x4f, 0x01, 0x02, 0x41, 0x00,
+ 0xf5, 0x83, 0xa4, 0x64, 0x4a, 0xf2, 0xdd, 0x8c,
+ 0x2c, 0xed, 0xa8, 0xd5, 0x60, 0x5a, 0xe4, 0xc7,
+ 0xcc, 0x61, 0xcd, 0x38, 0x42, 0x20, 0xd3, 0x82,
+ 0x18, 0xf2, 0x35, 0x00, 0x72, 0x2d, 0xf7, 0x89,
+ 0x80, 0x67, 0xb5, 0x93, 0x05, 0x5f, 0xdd, 0x42,
+ 0xba, 0x16, 0x1a, 0xea, 0x15, 0xc6, 0xf0, 0xb8,
+ 0x8c, 0xbc, 0xbf, 0x54, 0x9e, 0xf1, 0xc1, 0xb2,
+ 0xb3, 0x8b, 0xb6, 0x26, 0x02, 0x30, 0xc4, 0x81,
+ 0x02, 0x41, 0x00, 0xc0, 0x60, 0x62, 0x80, 0xe1,
+ 0x22, 0x78, 0xf6, 0x9d, 0x83, 0x18, 0xeb, 0x72,
+ 0x45, 0xd7, 0xc8, 0x01, 0x7f, 0xa9, 0xca, 0x8f,
+ 0x7d, 0xd6, 0xb8, 0x31, 0x2b, 0x84, 0x7f, 0x62,
+ 0xd9, 0xa9, 0x22, 0x17, 0x7d, 0x06, 0x35, 0x6c,
+ 0xf3, 0xc1, 0x94, 0x17, 0x85, 0x5a, 0xaf, 0x9c,
+ 0x5c, 0x09, 0x3c, 0xcf, 0x2f, 0x44, 0x9d, 0xb6,
+ 0x52, 0x68, 0x5f, 0xf9, 0x59, 0xc8, 0x84, 0x2b,
+ 0x39, 0x22, 0x8f, 0x02, 0x41, 0x00, 0xb2, 0x04,
+ 0xe2, 0x0e, 0x56, 0xca, 0x03, 0x1a, 0xc0, 0xf9,
+ 0x12, 0x92, 0xa5, 0x6b, 0x42, 0xb8, 0x1c, 0xda,
+ 0x4d, 0x93, 0x9d, 0x5f, 0x6f, 0xfd, 0xc5, 0x58,
+ 0xda, 0x55, 0x98, 0x74, 0xfc, 0x28, 0x17, 0x93,
+ 0x1b, 0x75, 0x9f, 0x50, 0x03, 0x7f, 0x7e, 0xae,
+ 0xc8, 0x95, 0x33, 0x75, 0x2c, 0xd6, 0xa4, 0x35,
+ 0xb8, 0x06, 0x03, 0xba, 0x08, 0x59, 0x2b, 0x17,
+ 0x02, 0xdc, 0x4c, 0x7a, 0x50, 0x01, 0x02, 0x41,
+ 0x00, 0x9d, 0xdb, 0x39, 0x59, 0x09, 0xe4, 0x30,
+ 0xa0, 0x24, 0xf5, 0xdb, 0x2f, 0xf0, 0x2f, 0xf1,
+ 0x75, 0x74, 0x0d, 0x5e, 0xb5, 0x11, 0x73, 0xb0,
+ 0x0a, 0xaa, 0x86, 0x4c, 0x0d, 0xff, 0x7e, 0x1d,
+ 0xb4, 0x14, 0xd4, 0x09, 0x91, 0x33, 0x5a, 0xfd,
+ 0xa0, 0x58, 0x80, 0x9b, 0xbe, 0x78, 0x2e, 0x69,
+ 0x82, 0x15, 0x7c, 0x72, 0xf0, 0x7b, 0x18, 0x39,
+ 0xff, 0x6e, 0xeb, 0xc6, 0x86, 0xf5, 0xb4, 0xc7,
+ 0x6f, 0x02, 0x41, 0x00, 0x8d, 0x1a, 0x37, 0x0f,
+ 0x76, 0xc4, 0x82, 0xfa, 0x5c, 0xc3, 0x79, 0x35,
+ 0x3e, 0x70, 0x8a, 0xbf, 0x27, 0x49, 0xb0, 0x99,
+ 0x63, 0xcb, 0x77, 0x5f, 0xa8, 0x82, 0x65, 0xf6,
+ 0x03, 0x52, 0x51, 0xf1, 0xae, 0x2e, 0x05, 0xb3,
+ 0xc6, 0xa4, 0x92, 0xd1, 0xce, 0x6c, 0x72, 0xfb,
+ 0x21, 0xb3, 0x02, 0x87, 0xe4, 0xfd, 0x61, 0xca,
+ 0x00, 0x42, 0x19, 0xf0, 0xda, 0x5a, 0x53, 0xe3,
+ 0xb1, 0xc5, 0x15, 0xf3
+ };
+
+ std::vector<uint8> input;
+ input.resize(sizeof(private_key_info));
+ memcpy(&input.front(), private_key_info, sizeof(private_key_info));
+
+ private_key.reset(base::RSAPrivateKey::CreateFromPrivateKeyInfo(input));
+ ASSERT_TRUE(private_key.get());
+
+ cert = net::X509Certificate::CreateSelfSigned(
+ private_key.get(), "CN=subject", 1, base::TimeDelta::FromDays(1));
+
+ EXPECT_EQ("subject", cert->subject().GetDisplayName());
+ EXPECT_FALSE(cert->HasExpired());
}
TEST(X509CertificateTest, GetDEREncoded) {