Index: net/base/x509_certificate_win.cc |
=================================================================== |
--- net/base/x509_certificate_win.cc (revision 49024) |
+++ net/base/x509_certificate_win.cc (working copy) |
@@ -434,6 +434,99 @@ |
} |
} |
+X509Certificate::OSCertHandle HandleFromBytes(const BYTE* data, DWORD length) { |
+ X509Certificate::OSCertHandle cert_handle = NULL; |
+ |
+ if (!CertAddEncodedCertificateToStore( |
+ NULL, // the cert won't be persisted in any cert store |
+ X509_ASN_ENCODING, |
+ reinterpret_cast<const BYTE*>(data), length, |
+ CERT_STORE_ADD_USE_EXISTING, |
+ &cert_handle)) |
+ return NULL; |
+ |
+ return cert_handle; |
+} |
+ |
+void AddCertsFromStore(HCERTSTORE store, |
+ X509Certificate::OSCertHandles* results) { |
+ PCCERT_CONTEXT cur_cert = NULL; |
+ |
+ while ((cur_cert = CertEnumCertificatesInStore(store, cur_cert)) != NULL) { |
+ PCCERT_CONTEXT to_add = NULL; |
+ if (CertAddCertificateContextToStore( |
+ NULL, // The cert won't be persisted in any cert store. This breaks |
+ // any association the context currently has to |store|, which |
+ // allows us the caller to safely close |store| without |
+ // releasing the cert handles. |
+ cur_cert, |
+ CERT_STORE_ADD_USE_EXISTING, |
+ &to_add) && to_add != NULL) { |
+ // When processing stores generated from PKCS#7/PKCS#12 files, it |
+ // appears that the order returned is the inverse of the order that it |
+ // appeared in the file. |
+ // TODO(rsleevi): Ensure this order is consistent across all flavours of |
+ // Windows. |
+ results->insert(results->begin(), to_add); |
+ } |
+ } |
+} |
+ |
+X509Certificate::OSCertHandles ParsePKCS7(const char* data, size_t length) { |
+ X509Certificate::OSCertHandles results; |
+ CERT_BLOB data_blob; |
+ data_blob.cbData = length; |
+ data_blob.pbData = reinterpret_cast<BYTE*>(const_cast<char*>(data)); |
+ |
+ HCERTSTORE out_store = NULL; |
+ |
+ DWORD expected_types = CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | |
+ CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED | |
+ CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED; |
+ |
+ if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &data_blob, expected_types, |
+ CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL, |
+ &out_store, NULL, NULL) || out_store == NULL) { |
+ return results; |
+ } |
+ |
+ AddCertsFromStore(out_store, &results); |
+ CertCloseStore(out_store, CERT_CLOSE_STORE_CHECK_FLAG); |
+ |
+ return results; |
+} |
+ |
+X509Certificate::OSCertHandles ParseNetscapeSequence(const char* data, |
+ size_t length) { |
+ X509Certificate::OSCertHandles results; |
+ CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY* certs = NULL; |
+ DWORD certs_size = 0; |
+ |
+ CRYPT_DECODE_PARA decode_para; |
+ decode_para.cbSize = sizeof(decode_para); |
+ decode_para.pfnAlloc = MyCryptAlloc; |
+ decode_para.pfnFree = MyCryptFree; |
+ |
+ DWORD size = 0; |
+ BOOL rv = CryptDecodeObjectEx( |
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, |
+ PKCS_CONTENT_INFO_SEQUENCE_OF_ANY, |
+ reinterpret_cast<const BYTE*>(data), length, |
+ CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, |
+ &decode_para, &certs, &certs_size); |
+ if (rv) { |
+ scoped_ptr_malloc<CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY> scoped_certs(certs); |
+ for (DWORD i = 0; i < certs->cValue; ++i) { |
+ X509Certificate::OSCertHandle handle = |
+ HandleFromBytes(certs->rgValue[i].pbData, certs->rgValue[i].cbData); |
+ if (handle) |
+ results.push_back(handle); |
+ } |
+ } |
+ |
+ return results; |
+} |
+ |
} // namespace |
void X509Certificate::Initialize() { |
@@ -737,17 +830,34 @@ |
// static |
X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( |
- const char* data, int length) { |
- OSCertHandle cert_handle = NULL; |
- if (!CertAddEncodedCertificateToStore( |
- NULL, // the cert won't be persisted in any cert store |
- X509_ASN_ENCODING, |
- reinterpret_cast<const BYTE*>(data), length, |
- CERT_STORE_ADD_USE_EXISTING, |
- &cert_handle)) |
- return NULL; |
+ const char* data, size_t length) { |
+ return HandleFromBytes(reinterpret_cast<const BYTE*>(data), length); |
+} |
- return cert_handle; |
+// static |
+X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( |
+ const char *data, size_t length, CertificateFormat format) { |
+ OSCertHandles results; |
+ switch (format) { |
+ case FORMAT_DER: |
+ { |
+ OSCertHandle handle = CreateOSCertHandleFromBytes(data, length); |
+ if (handle != NULL) |
+ results.push_back(handle); |
+ } |
+ break; |
+ case FORMAT_PKCS7: |
+ results = ParsePKCS7(data, length); |
+ break; |
+ case FORMAT_LEGACY_NETSCAPE: |
+ results = ParseNetscapeSequence(data, length); |
+ break; |
+ default: |
+ NOTREACHED() << "Certificate format " << format << " unimplemented"; |
+ break; |
+ } |
+ |
+ return results; |
} |