diff options
author | rsleevi@chromium.org <rsleevi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-22 02:31:04 +0000 |
---|---|---|
committer | rsleevi@chromium.org <rsleevi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-22 02:31:04 +0000 |
commit | e5a3eef63bed48a362ea5aa06b88559f7ad34d11 (patch) | |
tree | 137e336deffa52503326bfd77faa276523d2036e /net/base/x509_certificate_mac.cc | |
parent | 7349c6b146c267b7f634d518296f631642ef7095 (diff) | |
download | chromium_src-e5a3eef63bed48a362ea5aa06b88559f7ad34d11.zip chromium_src-e5a3eef63bed48a362ea5aa06b88559f7ad34d11.tar.gz chromium_src-e5a3eef63bed48a362ea5aa06b88559f7ad34d11.tar.bz2 |
Add support for parsing certificate formats other than raw, DER-encoded certificates - specifically formats that represent collections of certificates. The certificate format can now be specified as an explicit format, or as a bit-mask of formats that are acceptable/expected, with the first parsable format winning.
This is one half of a commit to address BUG #37142, with the second half involving connecting this through the X509UserCertHandler and the actual UI.
R=wtc
BUG=37142
TEST=X509CertificateParseTest* and PEMTokenizerTest.*
Review URL: http://codereview.chromium.org/2819018
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@53298 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base/x509_certificate_mac.cc')
-rw-r--r-- | net/base/x509_certificate_mac.cc | 80 |
1 files changed, 78 insertions, 2 deletions
diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc index ed46adc..1b464f9 100644 --- a/net/base/x509_certificate_mac.cc +++ b/net/base/x509_certificate_mac.cc @@ -8,9 +8,9 @@ #include <Security/Security.h> #include <time.h> -#include "base/scoped_cftyperef.h" #include "base/logging.h" #include "base/pickle.h" +#include "base/scoped_cftyperef.h" #include "base/sys_string_conversions.h" #include "net/base/cert_status_flags.h" #include "net/base/cert_verify_result.h" @@ -372,6 +372,44 @@ bool ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage* usage, return false; } +// Parses |data| of length |length|, attempting to decode it as the specified +// |format|. If |data| is in the specified format, any certificates contained +// within are stored into |output|. +void AddCertificatesFromBytes(const char* data, size_t length, + SecExternalFormat format, + X509Certificate::OSCertHandles* output) { + SecExternalFormat input_format = format; + scoped_cftyperef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy( + kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), + length, kCFAllocatorNull)); + + CFArrayRef items = NULL; + OSStatus status = SecKeychainItemImport(local_data, NULL, &input_format, + NULL, 0, NULL, NULL, &items); + if (status) { + DLOG(WARNING) << status << " Unable to import items from data of length " + << length; + return; + } + + scoped_cftyperef<CFArrayRef> scoped_items(items); + CFTypeID cert_type_id = SecCertificateGetTypeID(); + + for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) { + SecKeychainItemRef item = reinterpret_cast<SecKeychainItemRef>( + const_cast<void*>(CFArrayGetValueAtIndex(items, i))); + + // While inputFormat implies only certificates will be imported, if/when + // other formats (eg: PKCS#12) are supported, this may also include + // private keys or other items types, so filter appropriately. + if (CFGetTypeID(item) == cert_type_id) { + SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(item); + CFRetain(cert); + output->push_back(cert); + } + } +} + } // namespace void X509Certificate::Initialize() { @@ -669,15 +707,53 @@ X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( OSCertHandle cert_handle = NULL; OSStatus status = SecCertificateCreateFromData(&cert_data, CSSM_CERT_X_509v3, - CSSM_CERT_ENCODING_BER, + CSSM_CERT_ENCODING_DER, &cert_handle); if (status) return NULL; + // SecCertificateCreateFromData() unfortunately will not return any + // errors, as long as simply all pointers are present. The actual decoding + // of the certificate does not happen until an API that requires a CDSA + // handle is called. While SecCertificateGetCLHandle is the most likely + // candidate, as it initializes the parsing, it does not check whether the + // parsing was successful. Instead, SecCertificateGetSubject is used + // (supported since 10.3), as a means to double-check that the parsed + // certificate is valid. + const CSSM_X509_NAME* sanity_check = NULL; + status = SecCertificateGetSubject(cert_handle, &sanity_check); + if (status || !sanity_check) { + CFRelease(cert_handle); + return NULL; + } + return cert_handle; } // static +X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( + const char* data, int length, Format format) { + OSCertHandles results; + + switch (format) { + case FORMAT_SINGLE_CERTIFICATE: { + OSCertHandle handle = CreateOSCertHandleFromBytes(data, length); + if (handle) + results.push_back(handle); + break; + } + case FORMAT_PKCS7: + AddCertificatesFromBytes(data, length, kSecFormatPKCS7, &results); + break; + default: + NOTREACHED() << "Certificate format " << format << " unimplemented"; + break; + } + + return results; +} + +// static X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( OSCertHandle handle) { if (!handle) |