OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/cert_verify_proc_openssl.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "base/logging.h" | |
11 #include "base/sha1.h" | |
12 #include "crypto/openssl_util.h" | |
13 #include "crypto/sha2.h" | |
14 #include "net/base/net_errors.h" | |
15 #include "net/cert/asn1_util.h" | |
16 #include "net/cert/cert_status_flags.h" | |
17 #include "net/cert/cert_verifier.h" | |
18 #include "net/cert/cert_verify_result.h" | |
19 #include "net/cert/test_root_certs.h" | |
20 #include "net/cert/x509_certificate.h" | |
21 #include "third_party/boringssl/src/include/openssl/x509v3.h" | |
22 | |
23 namespace net { | |
24 | |
25 namespace { | |
26 | |
27 // Maps X509_STORE_CTX_get_error() return values to our cert status flags. | |
28 CertStatus MapCertErrorToCertStatus(int err) { | |
29 switch (err) { | |
30 case X509_V_ERR_SUBJECT_ISSUER_MISMATCH: | |
31 return CERT_STATUS_COMMON_NAME_INVALID; | |
32 case X509_V_ERR_CERT_NOT_YET_VALID: | |
33 case X509_V_ERR_CERT_HAS_EXPIRED: | |
34 case X509_V_ERR_CRL_NOT_YET_VALID: | |
35 case X509_V_ERR_CRL_HAS_EXPIRED: | |
36 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: | |
37 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: | |
38 case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: | |
39 case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: | |
40 return CERT_STATUS_DATE_INVALID; | |
41 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: | |
42 case X509_V_ERR_UNABLE_TO_GET_CRL: | |
43 case X509_V_ERR_INVALID_CA: | |
44 case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: | |
45 case X509_V_ERR_INVALID_NON_CA: | |
46 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: | |
47 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: | |
48 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: | |
49 return CERT_STATUS_AUTHORITY_INVALID; | |
50 #if 0 | |
51 // TODO(bulach): what should we map to these status? | |
52 return CERT_STATUS_NO_REVOCATION_MECHANISM; | |
53 return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION; | |
54 #endif | |
55 case X509_V_ERR_CERT_REVOKED: | |
56 return CERT_STATUS_REVOKED; | |
57 // All these status are mapped to CERT_STATUS_INVALID. | |
58 case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: | |
59 case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: | |
60 case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: | |
61 case X509_V_ERR_CERT_SIGNATURE_FAILURE: | |
62 case X509_V_ERR_CRL_SIGNATURE_FAILURE: | |
63 case X509_V_ERR_OUT_OF_MEM: | |
64 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: | |
65 case X509_V_ERR_CERT_CHAIN_TOO_LONG: | |
66 case X509_V_ERR_PATH_LENGTH_EXCEEDED: | |
67 case X509_V_ERR_INVALID_PURPOSE: | |
68 case X509_V_ERR_CERT_UNTRUSTED: | |
69 case X509_V_ERR_CERT_REJECTED: | |
70 case X509_V_ERR_AKID_SKID_MISMATCH: | |
71 case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: | |
72 case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: | |
73 case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: | |
74 case X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: | |
75 case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: | |
76 case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: | |
77 case X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: | |
78 case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: | |
79 case X509_V_ERR_INVALID_EXTENSION: | |
80 case X509_V_ERR_INVALID_POLICY_EXTENSION: | |
81 case X509_V_ERR_NO_EXPLICIT_POLICY: | |
82 case X509_V_ERR_UNNESTED_RESOURCE: | |
83 case X509_V_ERR_APPLICATION_VERIFICATION: | |
84 return CERT_STATUS_INVALID; | |
85 default: | |
86 NOTREACHED() << "Invalid X509 err " << err; | |
87 return CERT_STATUS_INVALID; | |
88 } | |
89 } | |
90 | |
91 struct ShallowX509StackDeleter { | |
92 void operator()(STACK_OF(X509) * st) const { sk_X509_free(st); } | |
93 }; | |
94 | |
95 void GetCertChainInfo(X509_STORE_CTX* store_ctx, | |
96 CertVerifyResult* verify_result) { | |
97 STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(store_ctx); | |
98 X509* verified_cert = NULL; | |
99 std::vector<X509*> verified_chain; | |
100 for (size_t i = 0; i < sk_X509_num(chain); ++i) { | |
101 X509* cert = sk_X509_value(chain, i); | |
102 if (i == 0) { | |
103 verified_cert = cert; | |
104 } else { | |
105 verified_chain.push_back(cert); | |
106 } | |
107 } | |
108 | |
109 // Set verify_result->verified_cert and | |
110 // verify_result->is_issued_by_known_root. | |
111 if (verified_cert) { | |
112 scoped_refptr<X509Certificate> verified_cert_with_chain = | |
113 X509Certificate::CreateFromHandle(verified_cert, verified_chain); | |
114 if (verified_cert_with_chain) | |
115 verify_result->verified_cert = std::move(verified_cert_with_chain); | |
116 else | |
117 verify_result->cert_status |= CERT_STATUS_INVALID; | |
118 | |
119 // For OpenSSL builds, only certificates used for unit tests are treated | |
120 // as not issued by known roots. The only way to determine whether a | |
121 // certificate is issued by a known root using OpenSSL is to examine | |
122 // distro-and-release specific hardcoded lists. | |
123 verify_result->is_issued_by_known_root = true; | |
124 if (TestRootCerts::HasInstance()) { | |
125 X509* root = NULL; | |
126 if (verified_chain.empty()) { | |
127 root = verified_cert; | |
128 } else { | |
129 root = verified_chain.back(); | |
130 } | |
131 TestRootCerts* root_certs = TestRootCerts::GetInstance(); | |
132 if (root_certs->Contains(root)) | |
133 verify_result->is_issued_by_known_root = false; | |
134 } | |
135 } | |
136 } | |
137 | |
138 void AppendPublicKeyHashes(X509_STORE_CTX* store_ctx, | |
139 HashValueVector* hashes) { | |
140 STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(store_ctx); | |
141 for (size_t i = 0; i < sk_X509_num(chain); ++i) { | |
142 X509* cert = sk_X509_value(chain, i); | |
143 | |
144 std::string der_data; | |
145 if (!X509Certificate::GetDEREncoded(cert, &der_data)) | |
146 continue; | |
147 | |
148 base::StringPiece der_bytes(der_data); | |
149 base::StringPiece spki_bytes; | |
150 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) | |
151 continue; | |
152 | |
153 HashValue sha1(HASH_VALUE_SHA1); | |
154 base::SHA1HashBytes(reinterpret_cast<const uint8_t*>(spki_bytes.data()), | |
155 spki_bytes.size(), sha1.data()); | |
156 hashes->push_back(sha1); | |
157 | |
158 HashValue sha256(HASH_VALUE_SHA256); | |
159 crypto::SHA256HashString(spki_bytes, sha256.data(), crypto::kSHA256Length); | |
160 hashes->push_back(sha256); | |
161 } | |
162 } | |
163 | |
164 } // namespace | |
165 | |
166 CertVerifyProcOpenSSL::CertVerifyProcOpenSSL() {} | |
167 | |
168 CertVerifyProcOpenSSL::~CertVerifyProcOpenSSL() {} | |
169 | |
170 bool CertVerifyProcOpenSSL::SupportsAdditionalTrustAnchors() const { | |
171 return false; | |
172 } | |
173 | |
174 bool CertVerifyProcOpenSSL::SupportsOCSPStapling() const { | |
175 return false; | |
176 } | |
177 | |
178 int CertVerifyProcOpenSSL::VerifyInternal( | |
179 X509Certificate* cert, | |
180 const std::string& hostname, | |
181 const std::string& ocsp_response, | |
182 int flags, | |
183 CRLSet* crl_set, | |
184 const CertificateList& additional_trust_anchors, | |
185 CertVerifyResult* verify_result) { | |
186 crypto::EnsureOpenSSLInit(); | |
187 | |
188 bssl::UniquePtr<X509_STORE_CTX> ctx(X509_STORE_CTX_new()); | |
189 | |
190 std::unique_ptr<STACK_OF(X509), ShallowX509StackDeleter> intermediates( | |
191 sk_X509_new_null()); | |
192 if (!intermediates.get()) | |
193 return ERR_OUT_OF_MEMORY; | |
194 | |
195 const X509Certificate::OSCertHandles& os_intermediates = | |
196 cert->GetIntermediateCertificates(); | |
197 for (X509Certificate::OSCertHandles::const_iterator it = | |
198 os_intermediates.begin(); it != os_intermediates.end(); ++it) { | |
199 if (!sk_X509_push(intermediates.get(), *it)) | |
200 return ERR_OUT_OF_MEMORY; | |
201 } | |
202 if (X509_STORE_CTX_init(ctx.get(), X509Certificate::cert_store(), | |
203 cert->os_cert_handle(), intermediates.get()) != 1) { | |
204 NOTREACHED(); | |
205 return ERR_FAILED; | |
206 } | |
207 | |
208 if (X509_verify_cert(ctx.get()) != 1) { | |
209 int x509_error = X509_STORE_CTX_get_error(ctx.get()); | |
210 CertStatus cert_status = MapCertErrorToCertStatus(x509_error); | |
211 LOG(ERROR) << "X509 Verification error " | |
212 << X509_verify_cert_error_string(x509_error) | |
213 << " : " << x509_error | |
214 << " : " << X509_STORE_CTX_get_error_depth(ctx.get()) | |
215 << " : " << cert_status; | |
216 verify_result->cert_status |= cert_status; | |
217 } | |
218 | |
219 GetCertChainInfo(ctx.get(), verify_result); | |
220 AppendPublicKeyHashes(ctx.get(), &verify_result->public_key_hashes); | |
221 | |
222 if (IsCertStatusError(verify_result->cert_status)) | |
223 return MapCertStatusToNetError(verify_result->cert_status); | |
224 | |
225 return OK; | |
226 } | |
227 | |
228 } // namespace net | |
OLD | NEW |