Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: net/base/cert_database_win.cc

Issue 2668005: Bring the handling of <keygen> and support for the application/x-x509-user-ce... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Whitespace/style Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/base/cert_database_nss.cc ('k') | net/base/keygen_handler.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/base/cert_database.h" 5 #include "net/base/cert_database.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <wincrypt.h> 8 #include <wincrypt.h>
9 #pragma comment(lib, "crypt32.lib") 9 #pragma comment(lib, "crypt32.lib")
10 10
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/scoped_ptr.h"
12 #include "base/string_util.h" 13 #include "base/string_util.h"
14 #include "base/time.h"
15 #include "base/crypto/scoped_capi_types.h"
13 #include "net/base/keygen_handler.h" 16 #include "net/base/keygen_handler.h"
14 #include "net/base/net_errors.h" 17 #include "net/base/net_errors.h"
15 #include "net/base/x509_certificate.h" 18 #include "net/base/x509_certificate.h"
16 19
17 namespace net { 20 namespace net {
18 21
19 namespace { 22 namespace {
20 23
21 // Returns an encoded version of SubjectPublicKeyInfo from |cert| that is 24 typedef base::ScopedCAPIHandle<PCCERT_CHAIN_CONTEXT,
22 // compatible with KeygenHandler::Cache. If the cert cannot be converted, an 25 base::CAPIDestroyerVOID<PCCERT_CHAIN_CONTEXT,
23 // empty string is returned. 26 CertFreeCertificateChain> >
24 std::string GetSubjectPublicKeyInfo(const X509Certificate* cert) { 27 ScopedPCCERT_CHAIN_CONTEXT;
25 DCHECK(cert); 28 typedef base::ScopedCAPIHandle<HCERTSTORE,
29 base::CAPIDestroyerWithFlags<HCERTSTORE, CertCloseStore, 0> >
30 ScopedHCERTSTORE;
26 31
27 std::string result; 32 // From an arbitrary, unordered list of certificate, attempt to import every
28 if (!cert->os_cert_handle() || !cert->os_cert_handle()->pCertInfo) 33 // certificate that:
29 return result; 34 // 1) Is a CA
35 // 2) Results in a valid certificate chain
36 void ImportValidIntermediates(
37 const X509Certificate::OSCertHandles& intermediates) {
30 38
31 BOOL ok; 39 // First, create a local in memory store. The handles in intermediates may
32 DWORD size = 0; 40 // be from one or more stores, or not even be in a formal store (eg: when
33 PCERT_PUBLIC_KEY_INFO key_info = 41 // decoded from a byte sequence by X509Certificate), and thus may not be
34 &(cert->os_cert_handle()->pCertInfo->SubjectPublicKeyInfo); 42 // picked up by the default HCERTCHAINENGINE when it's attempting to build
35 ok = CryptEncodeObject(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, key_info, 43 ScopedHCERTSTORE temp_store(
36 NULL, &size); 44 CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL,
37 if (!ok) 45 CERT_STORE_CREATE_NEW_FLAG, NULL));
38 return result; 46 if (temp_store == NULL)
47 return;
39 48
40 ok = CryptEncodeObject(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, key_info, 49 // Add links to all of the existing contexts into the temp store, so
41 reinterpret_cast<BYTE*>(WriteInto(&result, size + 1)), 50 // that they will be available to chain building.
42 &size); 51 for (X509Certificate::OSCertHandles::const_iterator it =
43 if (!ok) { 52 intermediates.begin(); it != intermediates.end(); ++it) {
44 result.clear(); 53 BOOL added = CertAddCertificateLinkToStore(
45 return result; 54 temp_store, *it, CERT_STORE_ADD_USE_EXISTING, NULL);
46 } 55 }
47 56
48 // Per MSDN, the resultant structure may be smaller than the original size 57 std::vector<PCCERT_CONTEXT> to_add;
49 // supplied, so shrink to the actual size output. 58 FILETIME now = base::Time::Now().ToFileTime();
50 result.resize(size); 59 CERT_CHAIN_PARA chain_params;
60 memset(&chain_params, 0, sizeof(chain_params));
61 chain_params.cbSize = sizeof(chain_params);
51 62
52 return result; 63 // For every certificate, attempt to build a chain to an existing trust
53 } 64 // root, where each certificate is minimally valid to be used as a CA
65 // certificate (measured by adherance to basicConstraints restrictions,
66 // if any, not by key usage)
67 size_t offset = 0;
68 for (X509Certificate::OSCertHandles::const_iterator it =
69 intermediates.begin(); it != intermediates.end(); ++it, ++offset) {
70 ScopedPCCERT_CHAIN_CONTEXT chain_context;
71 if (!CertGetCertificateChain(NULL, *it, &now, temp_store, &chain_params,
72 CERT_CHAIN_CACHE_END_CERT |
73 CERT_CHAIN_DISABLE_AUTH_ROOT_AUTO_UPDATE,
74 NULL, chain_context.receive())) {
75 DPLOG(WARNING) << "Unable to get the certificate chain for "
76 << "intermediate " << offset << ". Skipping import of "
77 << "this certificate.";
78 continue;
79 }
54 80
55 // Returns true if |cert| was successfully modified to reference |location| to 81 CERT_CHAIN_POLICY_PARA chain_policy_params;
56 // obtain the associated private key. 82 memset(&chain_policy_params, 0, sizeof(chain_policy_params));
57 bool LinkCertToPrivateKey(X509Certificate* cert, 83 chain_policy_params.cbSize = sizeof(chain_policy_params);
58 KeygenHandler::KeyLocation location) { 84 chain_policy_params.dwFlags =
59 DCHECK(cert); 85 BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_CA_FLAG;
60 86
61 CRYPT_KEY_PROV_INFO prov_info = { 0 }; 87 CERT_CHAIN_POLICY_STATUS chain_policy_status;
62 prov_info.pwszContainerName = 88 memset(&chain_policy_status, 0, sizeof(chain_policy_status));
63 const_cast<LPWSTR>(location.container_name.c_str()); 89 chain_policy_status.cbSize = sizeof(chain_policy_status);
64 prov_info.pwszProvName =
65 const_cast<LPWSTR>(location.provider_name.c_str());
66 90
67 // Implicit by it being from KeygenHandler, which only supports RSA keys. 91 // TODO(rsleevi): In the event of bridge/federated chains, where
68 prov_info.dwProvType = PROV_RSA_FULL; 92 // chain_context contains more than one SIMPLE_CHAINS, check what
69 prov_info.dwKeySpec = AT_KEYEXCHANGE; 93 // the result will be if the chain context is:
94 // cChain = 2
95 // rgpChain[0] = Valid chain
96 // rgpChain[1] = Invalid chain
97 if (!CertVerifyCertificateChainPolicy(
98 CERT_CHAIN_POLICY_BASIC_CONSTRAINTS, chain_context,
99 &chain_policy_params, &chain_policy_status)) {
100 DPLOG(WARNING) << "Unable to get validate the certificate chain for "
101 << "intermediate " << offset << ". Skipping import of "
102 << "this certificate.";
103 continue;
104 }
70 105
71 BOOL ok = CertSetCertificateContextProperty(cert->os_cert_handle(), 106 if (chain_policy_status.dwError != 0) {
72 CERT_KEY_PROV_INFO_PROP_ID, 0, 107 DLOG(WARNING) << "Chain for intermediate " << offset << " returned: "
73 &prov_info); 108 << std::endl << " Error: " << chain_policy_status.dwError
74 return ok != FALSE; 109 << std::endl << " Chain Index: "
110 << chain_policy_status.lChainIndex
111 << std::endl << " Element Index: "
112 << chain_policy_status.lElementIndex;
113 continue;
114 }
115
116 // With CryptoAPI, there may be multiple chains for a given certificate,
117 // such as the case with bridged CAs. For each chain, iterate through the
118 // certificates that make up the chain. If the certificate was one of the
119 // supplied intermediates, then it is appropriate to add to the
120 // intermediate list.
121 for (DWORD i = 0; i < chain_context.get()->cChain; ++i) {
122 for (DWORD j = 0; j < chain_context.get()->rgpChain[i]->cElement; ++j) {
123 PCCERT_CONTEXT cert_in_temp_store = CertFindCertificateInStore(
124 temp_store.get(), X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
125 CERT_FIND_EXISTING,
126 chain_context.get()->rgpChain[i]->rgpElement[j], NULL);
127 if (cert_in_temp_store != NULL)
128 to_add.push_back(cert_in_temp_store);
129 }
130 }
131 }
132
133 // After sifting through all of |intermediates|, add any certificates that
134 // passed the checks.
135 if (!to_add.empty()) {
136 ScopedHCERTSTORE intermediate_db(CertOpenSystemStore(NULL, L"CA"));
137 if (intermediate_db) {
138 for (std::vector<PCCERT_CONTEXT>::iterator it = to_add.begin();
139 it != to_add.end(); ++it) {
140 CertAddCertificateContextToStore(intermediate_db, *it,
141 CERT_STORE_ADD_USE_EXISTING, NULL);
142 }
143 }
144 }
145
146 for (std::vector<PCCERT_CONTEXT>::iterator it = to_add.begin();
147 it != to_add.end(); ++it) {
148 BOOL freed = CertFreeCertificateContext(*it);
149 DCHECK(freed);
150 }
75 } 151 }
76 152
77 } // namespace 153 } // namespace
78 154
79 CertDatabase::CertDatabase() { 155 CertDatabase::CertDatabase() {
80 } 156 }
81 157
82 int CertDatabase::CheckUserCert(X509Certificate* cert) { 158 int CertDatabase::CheckUserCert(X509Certificate* cert) {
83 if (!cert) 159 if (!cert)
84 return ERR_CERT_INVALID; 160 return ERR_CERT_INVALID;
85 if (cert->HasExpired()) 161 if (cert->HasExpired())
86 return ERR_CERT_DATE_INVALID; 162 return ERR_CERT_DATE_INVALID;
87 163
88 std::string encoded_info = GetSubjectPublicKeyInfo(cert); 164 BOOL found = CryptFindCertificateKeyProvInfo(cert->os_cert_handle(),
89 KeygenHandler::Cache* cache = KeygenHandler::Cache::GetInstance(); 165 0, NULL);
90 KeygenHandler::KeyLocation location; 166 if (!found)
91
92 if (encoded_info.empty() || !cache->Find(encoded_info, &location) ||
93 !LinkCertToPrivateKey(cert, location))
94 return ERR_NO_PRIVATE_KEY_FOR_CERT; 167 return ERR_NO_PRIVATE_KEY_FOR_CERT;
95 168
96 return OK; 169 return OK;
97 } 170 }
98 171
99 int CertDatabase::AddUserCert(X509Certificate* cert) { 172 int CertDatabase::AddUserCert(X509Certificate* cert) {
100 // TODO(rsleevi): Would it be more appropriate to have the CertDatabase take 173 // TODO(rsleevi): Would it be more appropriate to have the CertDatabase take
101 // construction parameters (Keychain filepath on Mac OS X, PKCS #11 slot on 174 // construction parameters (Keychain filepath on Mac OS X, PKCS #11 slot on
102 // NSS, and Store Type / Path) here? For now, certs will be stashed into the 175 // NSS, and Store Type / Path) here? For now, certs will be stashed into the
103 // user's personal store, which will not automatically mark them as trusted, 176 // user's personal store, which will not automatically mark them as trusted,
104 // but will allow them to be used for client auth. 177 // but will allow them to be used for client auth.
105 HCERTSTORE cert_db = CertOpenSystemStore(NULL, L"MY"); 178 ScopedHCERTSTORE cert_db(CertOpenSystemStore(NULL, L"MY"));
106 if (!cert_db) 179 if (!cert_db)
107 return ERR_ADD_USER_CERT_FAILED; 180 return ERR_ADD_USER_CERT_FAILED;
108 181
109 BOOL added = CertAddCertificateContextToStore(cert_db, 182 BOOL added = CertAddCertificateContextToStore(cert_db,
110 cert->os_cert_handle(), 183 cert->os_cert_handle(),
111 CERT_STORE_ADD_USE_EXISTING, 184 CERT_STORE_ADD_USE_EXISTING,
112 NULL); 185 NULL);
113 186
114 CertCloseStore(cert_db, 0); 187 ImportValidIntermediates(cert->GetIntermediateCertificates());
115 188
116 if (!added) 189 if (!added)
117 return ERR_ADD_USER_CERT_FAILED; 190 return ERR_ADD_USER_CERT_FAILED;
118 191
119 return OK; 192 return OK;
120 } 193 }
121 194
122 } // namespace net 195 } // namespace net
OLDNEW
« no previous file with comments | « net/base/cert_database_nss.cc ('k') | net/base/keygen_handler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698