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

Side by Side Diff: net/socket/ssl_client_socket_openssl.cc

Issue 441823002: Support intermediate certificates for OpenSSL client auth. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: sleevi comments Created 6 years, 4 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/socket/ssl_client_socket_openssl.h ('k') | no next file » | 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) 2012 The Chromium Authors. All rights reserved. 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 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 // OpenSSL binding for SSLClientSocket. The class layout and general principle 5 // OpenSSL binding for SSLClientSocket. The class layout and general principle
6 // of operation is derived from SSLClientSocketNSS. 6 // of operation is derived from SSLClientSocketNSS.
7 7
8 #include "net/socket/ssl_client_socket_openssl.h" 8 #include "net/socket/ssl_client_socket_openssl.h"
9 9
10 #include <errno.h> 10 #include <errno.h>
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 #endif 50 #endif
51 51
52 // This constant can be any non-negative/non-zero value (eg: it does not 52 // This constant can be any non-negative/non-zero value (eg: it does not
53 // overlap with any value of the net::Error range, including net::OK). 53 // overlap with any value of the net::Error range, including net::OK).
54 const int kNoPendingReadResult = 1; 54 const int kNoPendingReadResult = 1;
55 55
56 // If a client doesn't have a list of protocols that it supports, but 56 // If a client doesn't have a list of protocols that it supports, but
57 // the server supports NPN, choosing "http/1.1" is the best answer. 57 // the server supports NPN, choosing "http/1.1" is the best answer.
58 const char kDefaultSupportedNPNProtocol[] = "http/1.1"; 58 const char kDefaultSupportedNPNProtocol[] = "http/1.1";
59 59
60 void FreeX509Stack(STACK_OF(X509)* ptr) {
61 sk_X509_pop_free(ptr, X509_free);
62 }
63
60 typedef crypto::ScopedOpenSSL<X509, X509_free>::Type ScopedX509; 64 typedef crypto::ScopedOpenSSL<X509, X509_free>::Type ScopedX509;
65 typedef crypto::ScopedOpenSSL<STACK_OF(X509), FreeX509Stack>::Type
66 ScopedX509Stack;
61 67
62 #if OPENSSL_VERSION_NUMBER < 0x1000103fL 68 #if OPENSSL_VERSION_NUMBER < 0x1000103fL
63 // This method doesn't seem to have made it into the OpenSSL headers. 69 // This method doesn't seem to have made it into the OpenSSL headers.
64 unsigned long SSL_CIPHER_get_id(const SSL_CIPHER* cipher) { return cipher->id; } 70 unsigned long SSL_CIPHER_get_id(const SSL_CIPHER* cipher) { return cipher->id; }
65 #endif 71 #endif
66 72
67 // Used for encoding the |connection_status| field of an SSLInfo object. 73 // Used for encoding the |connection_status| field of an SSLInfo object.
68 int EncodeSSLConnectionStatus(int cipher_suite, 74 int EncodeSSLConnectionStatus(int cipher_suite,
69 int compression, 75 int compression,
70 int version) { 76 int version) {
(...skipping 17 matching lines...) Expand all
88 return SSL_CONNECTION_VERSION_TLS1; 94 return SSL_CONNECTION_VERSION_TLS1;
89 case 0x0302: 95 case 0x0302:
90 return SSL_CONNECTION_VERSION_TLS1_1; 96 return SSL_CONNECTION_VERSION_TLS1_1;
91 case 0x0303: 97 case 0x0303:
92 return SSL_CONNECTION_VERSION_TLS1_2; 98 return SSL_CONNECTION_VERSION_TLS1_2;
93 default: 99 default:
94 return SSL_CONNECTION_VERSION_UNKNOWN; 100 return SSL_CONNECTION_VERSION_UNKNOWN;
95 } 101 }
96 } 102 }
97 103
98 void FreeX509Stack(STACK_OF(X509) * ptr) {
99 sk_X509_pop_free(ptr, X509_free);
100 }
101
102 ScopedX509 OSCertHandleToOpenSSL( 104 ScopedX509 OSCertHandleToOpenSSL(
103 X509Certificate::OSCertHandle os_handle) { 105 X509Certificate::OSCertHandle os_handle) {
104 #if defined(USE_OPENSSL_CERTS) 106 #if defined(USE_OPENSSL_CERTS)
105 return ScopedX509(X509Certificate::DupOSCertHandle(os_handle)); 107 return ScopedX509(X509Certificate::DupOSCertHandle(os_handle));
106 #else // !defined(USE_OPENSSL_CERTS) 108 #else // !defined(USE_OPENSSL_CERTS)
107 std::string der_encoded; 109 std::string der_encoded;
108 if (!X509Certificate::GetDEREncoded(os_handle, &der_encoded)) 110 if (!X509Certificate::GetDEREncoded(os_handle, &der_encoded))
109 return ScopedX509(); 111 return ScopedX509();
110 const uint8_t* bytes = reinterpret_cast<const uint8_t*>(der_encoded.data()); 112 const uint8_t* bytes = reinterpret_cast<const uint8_t*>(der_encoded.data());
111 return ScopedX509(d2i_X509(NULL, &bytes, der_encoded.size())); 113 return ScopedX509(d2i_X509(NULL, &bytes, der_encoded.size()));
112 #endif // defined(USE_OPENSSL_CERTS) 114 #endif // defined(USE_OPENSSL_CERTS)
113 } 115 }
114 116
117 ScopedX509Stack OSCertHandlesToOpenSSL(
118 const X509Certificate::OSCertHandles& os_handles) {
119 ScopedX509Stack stack(sk_X509_new_null());
120 for (size_t i = 0; i < os_handles.size(); i++) {
121 ScopedX509 x509 = OSCertHandleToOpenSSL(os_handles[i]);
122 if (!x509)
123 return ScopedX509Stack();
124 sk_X509_push(stack.get(), x509.release());
125 }
126 return stack.Pass();
127 }
128
115 } // namespace 129 } // namespace
116 130
117 class SSLClientSocketOpenSSL::SSLContext { 131 class SSLClientSocketOpenSSL::SSLContext {
118 public: 132 public:
119 static SSLContext* GetInstance() { return Singleton<SSLContext>::get(); } 133 static SSLContext* GetInstance() { return Singleton<SSLContext>::get(); }
120 SSL_CTX* ssl_ctx() { return ssl_ctx_.get(); } 134 SSL_CTX* ssl_ctx() { return ssl_ctx_.get(); }
121 SSLSessionCacheOpenSSL* session_cache() { return &session_cache_; } 135 SSLSessionCacheOpenSSL* session_cache() { return &session_cache_; }
122 136
123 SSLClientSocketOpenSSL* GetClientSocketFromSSL(const SSL* ssl) { 137 SSLClientSocketOpenSSL* GetClientSocketFromSSL(const SSL* ssl) {
124 DCHECK(ssl); 138 DCHECK(ssl);
(...skipping 10 matching lines...) Expand all
135 private: 149 private:
136 friend struct DefaultSingletonTraits<SSLContext>; 150 friend struct DefaultSingletonTraits<SSLContext>;
137 151
138 SSLContext() { 152 SSLContext() {
139 crypto::EnsureOpenSSLInit(); 153 crypto::EnsureOpenSSLInit();
140 ssl_socket_data_index_ = SSL_get_ex_new_index(0, 0, 0, 0, 0); 154 ssl_socket_data_index_ = SSL_get_ex_new_index(0, 0, 0, 0, 0);
141 DCHECK_NE(ssl_socket_data_index_, -1); 155 DCHECK_NE(ssl_socket_data_index_, -1);
142 ssl_ctx_.reset(SSL_CTX_new(SSLv23_client_method())); 156 ssl_ctx_.reset(SSL_CTX_new(SSLv23_client_method()));
143 session_cache_.Reset(ssl_ctx_.get(), kDefaultSessionCacheConfig); 157 session_cache_.Reset(ssl_ctx_.get(), kDefaultSessionCacheConfig);
144 SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), CertVerifyCallback, NULL); 158 SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), CertVerifyCallback, NULL);
145 SSL_CTX_set_client_cert_cb(ssl_ctx_.get(), ClientCertCallback); 159 SSL_CTX_set_cert_cb(ssl_ctx_.get(), ClientCertRequestCallback, NULL);
146 SSL_CTX_set_verify(ssl_ctx_.get(), SSL_VERIFY_PEER, NULL); 160 SSL_CTX_set_verify(ssl_ctx_.get(), SSL_VERIFY_PEER, NULL);
147 // TODO(kristianm): Only select this if ssl_config_.next_proto is not empty. 161 // TODO(kristianm): Only select this if ssl_config_.next_proto is not empty.
148 // It would be better if the callback were not a global setting, 162 // It would be better if the callback were not a global setting,
149 // but that is an OpenSSL issue. 163 // but that is an OpenSSL issue.
150 SSL_CTX_set_next_proto_select_cb(ssl_ctx_.get(), SelectNextProtoCallback, 164 SSL_CTX_set_next_proto_select_cb(ssl_ctx_.get(), SelectNextProtoCallback,
151 NULL); 165 NULL);
152 ssl_ctx_->tlsext_channel_id_enabled_new = 1; 166 ssl_ctx_->tlsext_channel_id_enabled_new = 1;
153 } 167 }
154 168
155 static std::string GetSessionCacheKey(const SSL* ssl) { 169 static std::string GetSessionCacheKey(const SSL* ssl) {
156 SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl); 170 SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl);
157 DCHECK(socket); 171 DCHECK(socket);
158 return socket->GetSessionCacheKey(); 172 return socket->GetSessionCacheKey();
159 } 173 }
160 174
161 static SSLSessionCacheOpenSSL::Config kDefaultSessionCacheConfig; 175 static SSLSessionCacheOpenSSL::Config kDefaultSessionCacheConfig;
162 176
163 static int ClientCertCallback(SSL* ssl, X509** x509, EVP_PKEY** pkey) { 177 static int ClientCertRequestCallback(SSL* ssl, void* arg) {
164 SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl); 178 SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl);
165 CHECK(socket); 179 CHECK(socket);
agl 2014/08/14 17:06:46 could probably be a DCHECK.
davidben 2014/08/14 17:50:07 Done. (*shrug* I suppose it'd crash immediately af
166 return socket->ClientCertRequestCallback(ssl, x509, pkey); 180 return socket->ClientCertRequestCallback(ssl);
167 } 181 }
168 182
169 static int CertVerifyCallback(X509_STORE_CTX *store_ctx, void *arg) { 183 static int CertVerifyCallback(X509_STORE_CTX *store_ctx, void *arg) {
170 SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data( 184 SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(
171 store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx())); 185 store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
172 SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl); 186 SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl);
173 CHECK(socket); 187 CHECK(socket);
174 188
175 return socket->CertVerifyCallback(store_ctx); 189 return socket->CertVerifyCallback(store_ctx);
176 } 190 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 } 233 }
220 234
221 X509* operator[](size_t index) const { 235 X509* operator[](size_t index) const {
222 DCHECK_LT(index, size()); 236 DCHECK_LT(index, size());
223 return sk_X509_value(openssl_chain_.get(), index); 237 return sk_X509_value(openssl_chain_.get(), index);
224 } 238 }
225 239
226 bool IsValid() { return os_chain_.get() && openssl_chain_.get(); } 240 bool IsValid() { return os_chain_.get() && openssl_chain_.get(); }
227 241
228 private: 242 private:
229 typedef crypto::ScopedOpenSSL<STACK_OF(X509), FreeX509Stack>::Type
230 ScopedX509Stack;
231
232 ScopedX509Stack openssl_chain_; 243 ScopedX509Stack openssl_chain_;
233 244
234 scoped_refptr<X509Certificate> os_chain_; 245 scoped_refptr<X509Certificate> os_chain_;
235 }; 246 };
236 247
237 SSLClientSocketOpenSSL::PeerCertificateChain& 248 SSLClientSocketOpenSSL::PeerCertificateChain&
238 SSLClientSocketOpenSSL::PeerCertificateChain::operator=( 249 SSLClientSocketOpenSSL::PeerCertificateChain::operator=(
239 const PeerCertificateChain& other) { 250 const PeerCertificateChain& other) {
240 if (this == &other) 251 if (this == &other)
241 return *this; 252 return *this;
(...skipping 1146 matching lines...) Expand 10 before | Expand all | Expand 10 after
1388 DCHECK(recv_buffer_.get()); 1399 DCHECK(recv_buffer_.get());
1389 int ret = BIO_write(transport_bio_, recv_buffer_->data(), result); 1400 int ret = BIO_write(transport_bio_, recv_buffer_->data(), result);
1390 // A write into a memory BIO should always succeed. 1401 // A write into a memory BIO should always succeed.
1391 DCHECK_EQ(result, ret); 1402 DCHECK_EQ(result, ret);
1392 } 1403 }
1393 recv_buffer_ = NULL; 1404 recv_buffer_ = NULL;
1394 transport_recv_busy_ = false; 1405 transport_recv_busy_ = false;
1395 return result; 1406 return result;
1396 } 1407 }
1397 1408
1398 int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl, 1409 int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl) {
1399 X509** x509,
1400 EVP_PKEY** pkey) {
1401 DVLOG(3) << "OpenSSL ClientCertRequestCallback called"; 1410 DVLOG(3) << "OpenSSL ClientCertRequestCallback called";
1402 DCHECK(ssl == ssl_); 1411 DCHECK(ssl == ssl_);
1403 DCHECK(*x509 == NULL); 1412
1404 DCHECK(*pkey == NULL); 1413 // Clear any currently configured certificates.
1414 SSL_certs_clear(ssl_);
1405 1415
1406 #if defined(OS_IOS) 1416 #if defined(OS_IOS)
1407 // TODO(droger): Support client auth on iOS. See http://crbug.com/145954). 1417 // TODO(droger): Support client auth on iOS. See http://crbug.com/145954).
1408 LOG(WARNING) << "Client auth is not supported"; 1418 LOG(WARNING) << "Client auth is not supported";
1409 #else // !defined(OS_IOS) 1419 #else // !defined(OS_IOS)
1410 if (!ssl_config_.send_client_cert) { 1420 if (!ssl_config_.send_client_cert) {
1411 // First pass: we know that a client certificate is needed, but we do not 1421 // First pass: we know that a client certificate is needed, but we do not
1412 // have one at hand. 1422 // have one at hand.
1413 client_auth_cert_needed_ = true; 1423 client_auth_cert_needed_ = true;
1414 STACK_OF(X509_NAME) *authorities = SSL_get_client_CA_list(ssl); 1424 STACK_OF(X509_NAME) *authorities = SSL_get_client_CA_list(ssl);
(...skipping 13 matching lines...) Expand all
1428 for (size_t i = 0; i < num_client_cert_types; i++) { 1438 for (size_t i = 0; i < num_client_cert_types; i++) {
1429 cert_key_types_.push_back( 1439 cert_key_types_.push_back(
1430 static_cast<SSLClientCertType>(client_cert_types[i])); 1440 static_cast<SSLClientCertType>(client_cert_types[i]));
1431 } 1441 }
1432 1442
1433 return -1; // Suspends handshake. 1443 return -1; // Suspends handshake.
1434 } 1444 }
1435 1445
1436 // Second pass: a client certificate should have been selected. 1446 // Second pass: a client certificate should have been selected.
1437 if (ssl_config_.client_cert.get()) { 1447 if (ssl_config_.client_cert.get()) {
1438 // TODO(davidben): Configure OpenSSL to also send the intermediates.
1439 ScopedX509 leaf_x509 = 1448 ScopedX509 leaf_x509 =
1440 OSCertHandleToOpenSSL(ssl_config_.client_cert->os_cert_handle()); 1449 OSCertHandleToOpenSSL(ssl_config_.client_cert->os_cert_handle());
1441 if (!leaf_x509) { 1450 if (!leaf_x509) {
1442 LOG(WARNING) << "Failed to import certificate"; 1451 LOG(WARNING) << "Failed to import certificate";
1443 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT); 1452 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT);
1444 return -1; 1453 return -1;
1445 } 1454 }
1446 1455
1456 ScopedX509Stack chain = OSCertHandlesToOpenSSL(
1457 ssl_config_.client_cert->GetIntermediateCertificates());
1458 if (!chain) {
1459 LOG(WARNING) << "Failed to import intermediate certificates";
1460 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT);
1461 return -1;
1462 }
1463
1447 // TODO(davidben): With Linux client auth support, this should be 1464 // TODO(davidben): With Linux client auth support, this should be
1448 // conditioned on OS_ANDROID and then, with https://crbug.com/394131, 1465 // conditioned on OS_ANDROID and then, with https://crbug.com/394131,
1449 // removed altogether. OpenSSLClientKeyStore is mostly an artifact of the 1466 // removed altogether. OpenSSLClientKeyStore is mostly an artifact of the
1450 // net/ client auth API lacking a private key handle. 1467 // net/ client auth API lacking a private key handle.
1451 #if defined(USE_OPENSSL_CERTS) 1468 #if defined(USE_OPENSSL_CERTS)
1452 crypto::ScopedEVP_PKEY privkey = 1469 crypto::ScopedEVP_PKEY privkey =
1453 OpenSSLClientKeyStore::GetInstance()->FetchClientCertPrivateKey( 1470 OpenSSLClientKeyStore::GetInstance()->FetchClientCertPrivateKey(
1454 ssl_config_.client_cert.get()); 1471 ssl_config_.client_cert.get());
1455 #else // !defined(USE_OPENSSL_CERTS) 1472 #else // !defined(USE_OPENSSL_CERTS)
1456 crypto::ScopedEVP_PKEY privkey = 1473 crypto::ScopedEVP_PKEY privkey =
1457 FetchClientCertPrivateKey(ssl_config_.client_cert.get()); 1474 FetchClientCertPrivateKey(ssl_config_.client_cert.get());
1458 #endif // defined(USE_OPENSSL_CERTS) 1475 #endif // defined(USE_OPENSSL_CERTS)
1459 if (!privkey) { 1476 if (!privkey) {
1460 // Could not find the private key. Fail the handshake and surface an 1477 // Could not find the private key. Fail the handshake and surface an
1461 // appropriate error to the caller. 1478 // appropriate error to the caller.
1462 LOG(WARNING) << "Client cert found without private key"; 1479 LOG(WARNING) << "Client cert found without private key";
1463 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY); 1480 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY);
1464 return -1; 1481 return -1;
1465 } 1482 }
1466 1483
1467 // TODO(joth): (copied from NSS) We should wait for server certificate 1484 if (!SSL_use_certificate(ssl_, leaf_x509.get()) ||
1468 // verification before sending our credentials. See http://crbug.com/13934 1485 !SSL_use_PrivateKey(ssl_, privkey.get()) ||
1469 *x509 = leaf_x509.release(); 1486 !SSL_set1_chain(ssl_, chain.get())) {
1470 *pkey = privkey.release(); 1487 LOG(WARNING) << "Failed to set client certificate";
1488 return -1;
1489 }
1471 return 1; 1490 return 1;
1472 } 1491 }
1473 #endif // defined(OS_IOS) 1492 #endif // defined(OS_IOS)
1474 1493
1475 // Send no client certificate. 1494 // Send no client certificate.
1476 return 0; 1495 return 1;
1477 } 1496 }
1478 1497
1479 int SSLClientSocketOpenSSL::CertVerifyCallback(X509_STORE_CTX* store_ctx) { 1498 int SSLClientSocketOpenSSL::CertVerifyCallback(X509_STORE_CTX* store_ctx) {
1480 if (!completed_handshake_) { 1499 if (!completed_handshake_) {
1481 // If the first handshake hasn't completed then we accept any certificates 1500 // If the first handshake hasn't completed then we accept any certificates
1482 // because we verify after the handshake. 1501 // because we verify after the handshake.
1483 return 1; 1502 return 1;
1484 } 1503 }
1485 1504
1486 CHECK(server_cert_.get()); 1505 CHECK(server_cert_.get());
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1589 return socket->MaybeReplayTransportError( 1608 return socket->MaybeReplayTransportError(
1590 bio, cmd, argp, argi, argl, retvalue); 1609 bio, cmd, argp, argi, argl, retvalue);
1591 } 1610 }
1592 1611
1593 scoped_refptr<X509Certificate> 1612 scoped_refptr<X509Certificate>
1594 SSLClientSocketOpenSSL::GetUnverifiedServerCertificateChain() const { 1613 SSLClientSocketOpenSSL::GetUnverifiedServerCertificateChain() const {
1595 return server_cert_; 1614 return server_cert_;
1596 } 1615 }
1597 1616
1598 } // namespace net 1617 } // namespace net
OLDNEW
« no previous file with comments | « net/socket/ssl_client_socket_openssl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698