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/base/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/sha2.h" | |
16 #include "net/base/asn1_util.h" | |
17 #include "net/base/cert_status_flags.h" | |
18 #include "net/base/cert_verifier.h" | |
19 #include "net/base/cert_verify_result.h" | |
20 #include "net/base/net_errors.h" | |
21 #include "net/base/x509_certificate.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 // sk_X509_free is a function-style macro, so can't be used as a template | |
92 // param directly. | |
93 void sk_X509_free_fn(STACK_OF(X509)* st) { | |
94 sk_X509_free(st); | |
95 } | |
96 | |
97 void GetCertChainInfo(X509_STORE_CTX* store_ctx, | |
98 CertVerifyResult* verify_result) { | |
99 STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(store_ctx); | |
100 X509* verified_cert = NULL; | |
101 std::vector<X509*> verified_chain; | |
102 for (int i = 0; i < sk_X509_num(chain); ++i) { | |
103 X509* cert = sk_X509_value(chain, i); | |
104 if (i == 0) { | |
105 verified_cert = cert; | |
106 } else { | |
107 verified_chain.push_back(cert); | |
108 } | |
109 | |
110 // Only check the algorithm status for certificates that are not in the | |
111 // trust store. | |
112 if (i < store_ctx->last_untrusted) { | |
113 int sig_alg = OBJ_obj2nid(cert->sig_alg->algorithm); | |
114 if (sig_alg == NID_md2WithRSAEncryption) { | |
115 verify_result->has_md2 = true; | |
116 if (i != 0) | |
117 verify_result->has_md2_ca = true; | |
118 } else if (sig_alg == NID_md4WithRSAEncryption) { | |
119 verify_result->has_md4 = true; | |
120 } else if (sig_alg == NID_md5WithRSAEncryption) { | |
121 verify_result->has_md5 = true; | |
122 if (i != 0) | |
123 verify_result->has_md5_ca = true; | |
124 } | |
125 } | |
126 } | |
127 | |
128 if (verified_cert) { | |
129 verify_result->verified_cert = | |
130 X509Certificate::CreateFromHandle(verified_cert, verified_chain); | |
131 } | |
132 } | |
133 | |
134 void AppendPublicKeyHashes(X509_STORE_CTX* store_ctx, | |
135 HashValueVector* hashes) { | |
136 STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(store_ctx); | |
137 for (int i = 0; i < sk_X509_num(chain); ++i) { | |
138 X509* cert = sk_X509_value(chain, i); | |
139 | |
140 std::string der_data; | |
141 if (!X509Certificate::GetDEREncoded(cert, &der_data)) | |
142 continue; | |
143 | |
144 base::StringPiece der_bytes(der_data); | |
145 base::StringPiece spki_bytes; | |
146 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) | |
147 continue; | |
148 | |
149 HashValue sha1(HASH_VALUE_SHA1); | |
150 base::SHA1HashBytes(reinterpret_cast<const uint8*>(spki_bytes.data()), | |
151 spki_bytes.size(), sha1.data()); | |
152 hashes->push_back(sha1); | |
153 | |
154 HashValue sha256(HASH_VALUE_SHA256); | |
155 crypto::SHA256HashString(spki_bytes, sha1.data(), crypto::kSHA256Length); | |
156 hashes->push_back(sha256); | |
157 } | |
158 } | |
159 | |
160 } // namespace | |
161 | |
162 CertVerifyProcOpenSSL::CertVerifyProcOpenSSL() {} | |
163 | |
164 CertVerifyProcOpenSSL::~CertVerifyProcOpenSSL() {} | |
165 | |
166 bool CertVerifyProcOpenSSL::SupportsAdditionalTrustAnchors() const { | |
167 return false; | |
168 } | |
169 | |
170 int CertVerifyProcOpenSSL::VerifyInternal( | |
171 X509Certificate* cert, | |
172 const std::string& hostname, | |
173 int flags, | |
174 CRLSet* crl_set, | |
175 const CertificateList& additional_trust_anchors, | |
176 CertVerifyResult* verify_result) { | |
177 crypto::EnsureOpenSSLInit(); | |
178 | |
179 if (!cert->VerifyNameMatch(hostname)) | |
180 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | |
181 | |
182 crypto::ScopedOpenSSL<X509_STORE_CTX, X509_STORE_CTX_free> ctx( | |
183 X509_STORE_CTX_new()); | |
184 | |
185 crypto::ScopedOpenSSL<STACK_OF(X509), sk_X509_free_fn> intermediates( | |
186 sk_X509_new_null()); | |
187 if (!intermediates.get()) | |
188 return ERR_OUT_OF_MEMORY; | |
189 | |
190 const X509Certificate::OSCertHandles& os_intermediates = | |
191 cert->GetIntermediateCertificates(); | |
192 for (X509Certificate::OSCertHandles::const_iterator it = | |
193 os_intermediates.begin(); it != os_intermediates.end(); ++it) { | |
194 if (!sk_X509_push(intermediates.get(), *it)) | |
195 return ERR_OUT_OF_MEMORY; | |
196 } | |
197 if (X509_STORE_CTX_init(ctx.get(), X509Certificate::cert_store(), | |
198 cert->os_cert_handle(), intermediates.get()) != 1) { | |
199 NOTREACHED(); | |
200 return ERR_FAILED; | |
201 } | |
202 | |
203 if (X509_verify_cert(ctx.get()) != 1) { | |
204 int x509_error = X509_STORE_CTX_get_error(ctx.get()); | |
205 CertStatus cert_status = MapCertErrorToCertStatus(x509_error); | |
206 LOG(ERROR) << "X509 Verification error " | |
207 << X509_verify_cert_error_string(x509_error) | |
208 << " : " << x509_error | |
209 << " : " << X509_STORE_CTX_get_error_depth(ctx.get()) | |
210 << " : " << cert_status; | |
211 verify_result->cert_status |= cert_status; | |
212 } | |
213 | |
214 GetCertChainInfo(ctx.get(), verify_result); | |
215 AppendPublicKeyHashes(ctx.get(), &verify_result->public_key_hashes); | |
216 if (IsCertStatusError(verify_result->cert_status)) | |
217 return MapCertStatusToNetError(verify_result->cert_status); | |
218 | |
219 // Currently we only ues OpenSSL's default root CA paths, so treat all | |
220 // correctly verified certs as being from a known root. | |
221 // TODO(joth): if the motivations described in | |
222 // http://src.chromium.org/viewvc/chrome?view=rev&revision=80778 become an | |
223 // issue on OpenSSL builds, we will need to embed a hardcoded list of well | |
224 // known root CAs, as per the _mac and _win versions. | |
225 verify_result->is_issued_by_known_root = true; | |
226 | |
227 return OK; | |
228 } | |
229 | |
230 } // namespace net | |
OLD | NEW |