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