Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/cert/x509_util_win.h" | |
| 6 | |
| 7 #include "crypto/scoped_capi_types.h" | |
| 8 #include "crypto/sha2.h" | |
| 9 #include "net/cert/x509_certificate.h" | |
| 10 #include "net/net_features.h" | |
| 11 #include "third_party/boringssl/src/include/openssl/pool.h" | |
| 12 | |
| 13 namespace net { | |
| 14 | |
| 15 namespace x509_util { | |
| 16 | |
| 17 namespace { | |
| 18 | |
| 19 typedef crypto::ScopedCAPIHandle< | |
| 20 HCERTSTORE, | |
| 21 crypto::CAPIDestroyerWithFlags<HCERTSTORE, CertCloseStore, 0>> | |
|
davidben
2017/06/15 23:55:18
Nit: using
mattm
2017/06/16 21:39:31
Done.
| |
| 22 ScopedHCERTSTORE; | |
| 23 | |
| 24 } // namespace | |
| 25 | |
| 26 scoped_refptr<X509Certificate> CreateX509CertificateFromCertContexts( | |
| 27 PCCERT_CONTEXT os_cert, | |
| 28 const std::vector<PCCERT_CONTEXT>& os_chain) { | |
| 29 #if BUILDFLAG(USE_BYTE_CERTS) | |
| 30 if (!os_cert || !os_cert->pbCertEncoded || !os_cert->cbCertEncoded) | |
| 31 return nullptr; | |
| 32 bssl::UniquePtr<CRYPTO_BUFFER> cert_handle( | |
| 33 X509Certificate::CreateOSCertHandleFromBytes( | |
| 34 reinterpret_cast<const char*>(os_cert->pbCertEncoded), | |
| 35 os_cert->cbCertEncoded)); | |
| 36 if (!cert_handle) | |
| 37 return nullptr; | |
| 38 std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; | |
| 39 X509Certificate::OSCertHandles intermediates_raw; | |
| 40 for (PCCERT_CONTEXT os_intermediate : os_chain) { | |
| 41 if (!os_intermediate || !os_intermediate->pbCertEncoded || | |
| 42 !os_intermediate->cbCertEncoded) | |
| 43 return nullptr; | |
| 44 bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle( | |
| 45 X509Certificate::CreateOSCertHandleFromBytes( | |
| 46 reinterpret_cast<const char*>(os_intermediate->pbCertEncoded), | |
| 47 os_intermediate->cbCertEncoded)); | |
| 48 if (!intermediate_cert_handle) | |
| 49 return nullptr; | |
| 50 intermediates_raw.push_back(intermediate_cert_handle.get()); | |
| 51 intermediates.push_back(std::move(intermediate_cert_handle)); | |
| 52 } | |
| 53 scoped_refptr<X509Certificate> result( | |
| 54 X509Certificate::CreateFromHandle(cert_handle.get(), intermediates_raw)); | |
| 55 return result; | |
| 56 #else | |
| 57 return X509Certificate::CreateFromHandle(os_cert, os_chain); | |
| 58 #endif | |
| 59 } | |
| 60 | |
| 61 ScopedPCCERT_CONTEXT CreateCertContextWithChain(const X509Certificate* cert) { | |
| 62 // Create an in-memory certificate store to hold the certificate and its | |
| 63 // intermediate certificates. The store will be referenced in the returned | |
| 64 // PCCERT_CONTEXT, and will not be freed until the PCCERT_CONTEXT is freed. | |
| 65 ScopedHCERTSTORE store( | |
| 66 CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, | |
| 67 CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, NULL)); | |
| 68 if (!store.get()) | |
| 69 return nullptr; | |
| 70 | |
| 71 PCCERT_CONTEXT primary_cert = nullptr; | |
| 72 | |
| 73 #if BUILDFLAG(USE_BYTE_CERTS) | |
| 74 BOOL ok = CertAddEncodedCertificateToStore( | |
| 75 store.get(), X509_ASN_ENCODING, | |
| 76 reinterpret_cast<const BYTE*>(CRYPTO_BUFFER_data(cert->os_cert_handle())), | |
|
davidben
2017/06/15 23:55:18
Optional: It's probably safe to assume this cast i
mattm
2017/06/16 21:39:31
Done.
| |
| 77 base::checked_cast<DWORD>(CRYPTO_BUFFER_len(cert->os_cert_handle())), | |
| 78 CERT_STORE_ADD_ALWAYS, &primary_cert); | |
| 79 if (!ok || !primary_cert) | |
| 80 return nullptr; | |
| 81 ScopedPCCERT_CONTEXT scoped_primary_cert(primary_cert); | |
| 82 | |
| 83 for (X509Certificate::OSCertHandle intermediate : | |
| 84 cert->GetIntermediateCertificates()) { | |
| 85 ok = CertAddEncodedCertificateToStore( | |
| 86 store.get(), X509_ASN_ENCODING, | |
| 87 reinterpret_cast<const BYTE*>(CRYPTO_BUFFER_data(intermediate)), | |
| 88 base::checked_cast<DWORD>(CRYPTO_BUFFER_len(intermediate)), | |
| 89 CERT_STORE_ADD_ALWAYS, NULL); | |
| 90 if (!ok) | |
| 91 return nullptr; | |
| 92 } | |
| 93 #else | |
| 94 PCCERT_CONTEXT os_cert_handle = cert->os_cert_handle(); | |
| 95 const std::vector<PCCERT_CONTEXT>& intermediate_ca_certs = | |
| 96 cert->GetIntermediateCertificates(); | |
| 97 | |
| 98 // NOTE: This preserves all of the properties of |os_cert_handle| except | |
| 99 // for CERT_KEY_PROV_HANDLE_PROP_ID and CERT_KEY_CONTEXT_PROP_ID - the two | |
| 100 // properties that hold access to already-opened private keys. If a handle | |
| 101 // has already been unlocked (eg: PIN prompt), then the first time that the | |
| 102 // identity is used for client auth, it may prompt the user again. | |
| 103 BOOL ok = CertAddCertificateContextToStore( | |
| 104 store.get(), os_cert_handle, CERT_STORE_ADD_ALWAYS, &primary_cert); | |
| 105 if (!ok || !primary_cert) | |
| 106 return nullptr; | |
| 107 ScopedPCCERT_CONTEXT scoped_primary_cert(primary_cert); | |
| 108 | |
| 109 for (size_t i = 0; i < intermediate_ca_certs.size(); ++i) { | |
|
davidben
2017/06/15 23:55:18
Nit:
for (PCCERT_CONTEXT intermediate : intermedia
mattm
2017/06/16 21:39:31
Done.
| |
| 110 CertAddCertificateContextToStore(store.get(), intermediate_ca_certs[i], | |
| 111 CERT_STORE_ADD_ALWAYS, NULL); | |
| 112 } | |
| 113 #endif | |
| 114 | |
| 115 // Note: |store| is explicitly not released, as the call to CertCloseStore() | |
| 116 // when |store| goes out of scope will not actually free the store. Instead, | |
| 117 // the store will be freed when |primary_cert| is freed. | |
|
davidben
2017/06/15 23:55:18
This comment confuses me a little. It reads like y
mattm
2017/06/16 21:39:31
Done.
| |
| 118 return scoped_primary_cert; | |
| 119 } | |
| 120 | |
| 121 SHA256HashValue CalculateFingerprint256(PCCERT_CONTEXT cert) { | |
| 122 DCHECK(NULL != cert->pbCertEncoded); | |
| 123 DCHECK_NE(0u, cert->cbCertEncoded); | |
| 124 | |
| 125 SHA256HashValue sha256; | |
| 126 size_t sha256_size = sizeof(sha256.data); | |
|
davidben
2017/06/15 23:55:18
Nit: Any reason to stash this into a variable? You
mattm
2017/06/16 21:39:31
Done.
| |
| 127 | |
| 128 // Use crypto::SHA256HashString for two reasons: | |
| 129 // * < Windows Vista does not have universal SHA-256 support. | |
| 130 // * More efficient on Windows > Vista (less overhead since non-default CSP | |
| 131 // is not needed). | |
| 132 base::StringPiece der_cert(reinterpret_cast<const char*>(cert->pbCertEncoded), | |
| 133 cert->cbCertEncoded); | |
| 134 crypto::SHA256HashString(der_cert, sha256.data, sha256_size); | |
| 135 return sha256; | |
| 136 } | |
| 137 | |
| 138 bool IsSelfSigned(PCCERT_CONTEXT cert_handle) { | |
| 139 bool valid_signature = !!CryptVerifyCertificateSignatureEx( | |
| 140 NULL, X509_ASN_ENCODING, CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, | |
| 141 reinterpret_cast<void*>(const_cast<PCERT_CONTEXT>(cert_handle)), | |
| 142 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, | |
| 143 reinterpret_cast<void*>(const_cast<PCERT_CONTEXT>(cert_handle)), 0, NULL); | |
| 144 if (!valid_signature) | |
| 145 return false; | |
| 146 return !!CertCompareCertificateName(X509_ASN_ENCODING, | |
| 147 &cert_handle->pCertInfo->Subject, | |
| 148 &cert_handle->pCertInfo->Issuer); | |
| 149 } | |
| 150 | |
| 151 } // namespace x509_util | |
| 152 | |
| 153 } // namespace net | |
| OLD | NEW |