summaryrefslogtreecommitdiffstats
path: root/net/base/x509_certificate_mac.cc
diff options
context:
space:
mode:
authorrsleevi@chromium.org <rsleevi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-22 02:31:04 +0000
committerrsleevi@chromium.org <rsleevi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-22 02:31:04 +0000
commite5a3eef63bed48a362ea5aa06b88559f7ad34d11 (patch)
tree137e336deffa52503326bfd77faa276523d2036e /net/base/x509_certificate_mac.cc
parent7349c6b146c267b7f634d518296f631642ef7095 (diff)
downloadchromium_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.cc80
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)