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

Side by Side Diff: net/quic/crypto/proof_verifier_openssl.cc

Issue 17385010: OpenSSL/NSS implementation of ProofVerfifier. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: added known answer test from wtc Created 7 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
OLDNEW
(Empty)
1 // Copyright 2013 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/quic/crypto/proof_verifier_openssl.h"
6
7 #include <openssl/ec.h>
8 #include <openssl/evp.h>
9 #include <openssl/rsa.h>
10 #include <openssl/x509.h>
11 #include <openssl/x509v3.h>
12
13 #include "base/logging.h"
14 #include "crypto/openssl_util.h"
15 #include "net/quic/crypto/crypto_protocol.h"
16
17 using base::StringPiece;
18 using std::string;
19 using std::vector;
20
21 namespace {
22
23 void EvpMdCtxCleanUp(EVP_MD_CTX *ctx) {
24 (void)EVP_MD_CTX_cleanup(ctx);
25 }
26
27 // sk_X509_free is a function-style macro, so can't be used as a template
28 // param directly.
29 void sk_X509_free_fn(STACK_OF(X509)* st) {
30 sk_X509_free(st);
31 }
32
33 } // namespace anonymous
34
35 namespace net {
36
37 ProofVerifierOpenSSL::ProofVerifierOpenSSL(const string& root_ca_filename) {
38 store_ = X509_STORE_new();
wtc 2013/06/19 19:44:36 We need to initialize OpenSSL. I suggest we add a
ramant (doing other things) 2013/06/19 19:58:20 Done.
39 X509_LOOKUP* lookup = X509_STORE_add_lookup(store_, X509_LOOKUP_file());
40 if (!X509_LOOKUP_load_file(lookup, root_ca_filename.c_str(),
41 X509_FILETYPE_PEM)) {
42 LOG(WARNING) << "Failed to load root CA file: " << root_ca_filename;
43 }
44 }
45
46 ProofVerifierOpenSSL::~ProofVerifierOpenSSL() { X509_STORE_free(store_); }
47
48 bool ProofVerifierOpenSSL::VerifyProof(const string& hostname,
49 const string& server_config,
50 const vector<string>& certs,
51 const string& signature,
52 string* error_details) const {
53 crypto::ScopedOpenSSL<X509, X509_free> leaf(VerifyChain(certs));
54 if (!leaf.get()) {
55 *error_details = "Failed to verify certificate chain";
56 return false;
57 }
58 if (!VerifySignature(server_config, signature, leaf.get())) {
59 *error_details = "Failed to verify signature of server config";
60 return false;
61 }
62 if (!VerifyLeafForHost(leaf.get(), hostname)) {
63 *error_details = "Leaf certificate doesn't match hostname";
64 return false;
65 }
66
67 return true;
68 }
69
70 static X509* ParseDERCertificate(const string& der_bytes) {
71 const uint8* data;
72 const uint8* orig_data;
73 orig_data = data = reinterpret_cast<const uint8*>(der_bytes.data());
74 crypto::ScopedOpenSSL<X509, X509_free> cert(
75 d2i_X509(NULL, &data, der_bytes.size()));
76 if (!cert.get()) {
77 LOG(WARNING) << "d2i_X509";
78 return NULL;
79 }
80 if (data - orig_data != static_cast<unsigned int>(der_bytes.size())) {
81 // Trailing garbage.
82 LOG(WARNING) << "Trailing garbage";
83 return NULL;
84 }
85 return cert.release();
86 }
87
88 X509* ProofVerifierOpenSSL::VerifyChain(const vector<string>& certs) const {
89 if (certs.empty()) {
90 LOG(WARNING) << "certs are empty";
91 return NULL;
92 }
93
94 // TODO(agl): use scoped_ptr_openssl_x509_stack_pop_free from //util/sig once
95 // it has landed.
96 crypto::ScopedOpenSSL<STACK_OF(X509), sk_X509_free_fn> intermediates(
97 sk_X509_new_null());
98 if (!intermediates.get()) {
99 LOG(WARNING) << "Out of memory";
100 return NULL;
101 }
102 for (size_t i = 1; i < certs.size(); i++) {
103 X509* cert = ParseDERCertificate(certs[i]);
104 if (!cert) {
105 LOG(WARNING) << "ParseDERCertificate NULL";
106 return NULL;
107 }
108 sk_X509_push(intermediates.get(), cert);
109 }
110
111 crypto::ScopedOpenSSL<X509, X509_free> leaf(ParseDERCertificate(certs[0]));
112 if (!leaf.get()) {
113 LOG(WARNING) << "leaf is NULL";
114 return NULL;
115 }
116
117 crypto::ScopedOpenSSL<X509_STORE_CTX, X509_STORE_CTX_free> ctx(
118 X509_STORE_CTX_new());
119 if (!X509_STORE_CTX_init(ctx.get(), store_, leaf.get(),
120 intermediates.get())) {
121 LOG(WARNING) << "X509_STORE_CTX_init ";
122 return NULL;
123 }
124 if (X509_verify_cert(ctx.get()) <= 0) {
125 LOG(WARNING) << "X509_verify_cert";
126 const int n = X509_STORE_CTX_get_error(ctx.get());
127 const int depth = X509_STORE_CTX_get_error_depth(ctx.get());
128 LOG(WARNING) << "Certificate verification error at depth "
129 << depth << ": " << X509_verify_cert_error_string(n);
130 // TODO(rtenneti): We are getting X509_V_ERR_CERT_SIGNATURE_FAILURE.
131 // return NULL;
132 }
133 return leaf.release();
134 }
135
136 // static
137 bool ProofVerifierOpenSSL::VerifySignature(const string& signed_data,
138 const string& signature,
139 X509* cert) {
140 crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> pkey(X509_get_pubkey(cert));
141
142 EVP_MD_CTX md_ctx;
143 crypto::ScopedOpenSSL<EVP_MD_CTX, EvpMdCtxCleanUp> scoped_md_ctx(&md_ctx);
144 EVP_MD_CTX_init(&md_ctx);
145 EVP_PKEY_CTX* ctx;
146 if (1 != EVP_DigestVerifyInit(&md_ctx, &ctx, EVP_sha256(),
147 NULL /* no engine */, pkey.get())) {
148 LOG(WARNING) << "EVP_DigestVerifyInit";
149 return false;
150 }
151 if (EVP_PKEY_id(pkey.get()) == EVP_PKEY_RSA) {
152 if (1 != EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING)) {
153 LOG(WARNING) << "EVP_PKEY_CTX_set_rsa_padding";
154 return false;
155 }
156 }
157 if (1 != EVP_DigestVerifyUpdate(&md_ctx, kProofSignatureLabel,
158 sizeof(kProofSignatureLabel))) {
159 LOG(WARNING) << "EVP_DigestVerifyUpdate";
160 return false;
161 }
162 if (1 != EVP_DigestVerifyUpdate(&md_ctx, signed_data.data(),
163 signed_data.size())) {
164 LOG(WARNING) << "EVP_DigestVerifyUpdate";
165 return false;
166 }
167 if (1 != EVP_DigestVerifyFinal(
168 &md_ctx, const_cast<uint8*>(
169 reinterpret_cast<const uint8*>(signature.data())),
170 signature.size())) {
171 LOG(WARNING) << "EVP_DigestVerifyFinal";
172 return false;
173 }
174 return true;
175 }
176
177 // static
178 bool ProofVerifierOpenSSL::VerifyLeafForHost(X509* cert,
179 const string& hostname) {
180 // Note: this is a very simple matching function that just checks for an
181 // exact match in the list of SANs.
182 crypto::ScopedOpenSSL<GENERAL_NAMES, GENERAL_NAMES_free> gens(
183 reinterpret_cast<GENERAL_NAMES*>(
184 X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL)));
185 if (gens.get() == NULL) {
186 return false;
187 }
188
189 for (int i = 0; i < sk_GENERAL_NAME_num(gens.get()); i++) {
190 const GENERAL_NAME* name = sk_GENERAL_NAME_value(gens.get(), i);
191 if (name->type == GEN_DNS) {
192 StringPiece dnsname(reinterpret_cast<char*>(name->d.dNSName->data),
193 name->d.dNSName->length);
194 if (dnsname == hostname) {
195 return true;
196 }
197 }
198 }
199
200 return false;
201 }
202
203 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698