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

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

Issue 276037: Provides a certificate for SSL client authentication on NSS sockets.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Remove extern from chrome_switches.cc Created 11 years, 2 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_nss.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) 2006-2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2009 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 // This file includes code GetDefaultCertNickname(), derived from 5 // This file includes code GetDefaultCertNickname(), derived from
6 // nsNSSCertificate::defaultServerNickName() 6 // nsNSSCertificate::defaultServerNickName()
7 // in mozilla/security/manager/ssl/src/nsNSSCertificate.cpp 7 // in mozilla/security/manager/ssl/src/nsNSSCertificate.cpp
8 // and SSLClientSocketNSS::DoVerifyCertComplete() derived from 8 // and SSLClientSocketNSS::DoVerifyCertComplete() derived from
9 // AuthCertificateCallback() in 9 // AuthCertificateCallback() in
10 // mozilla/security/manager/ssl/src/nsNSSCallbacks.cpp. 10 // mozilla/security/manager/ssl/src/nsNSSCallbacks.cpp.
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 * decision by deleting the provisions above and replace them with the notice 44 * decision by deleting the provisions above and replace them with the notice
45 * and other provisions required by the GPL or the LGPL. If you do not delete 45 * and other provisions required by the GPL or the LGPL. If you do not delete
46 * the provisions above, a recipient may use your version of this file under 46 * the provisions above, a recipient may use your version of this file under
47 * the terms of any one of the MPL, the GPL or the LGPL. 47 * the terms of any one of the MPL, the GPL or the LGPL.
48 * 48 *
49 * ***** END LICENSE BLOCK ***** */ 49 * ***** END LICENSE BLOCK ***** */
50 50
51 #include "net/socket/ssl_client_socket_nss.h" 51 #include "net/socket/ssl_client_socket_nss.h"
52 52
53 #include <certdb.h> 53 #include <certdb.h>
54 #include <keyhi.h>
54 #include <nspr.h> 55 #include <nspr.h>
55 #include <nss.h> 56 #include <nss.h>
56 #include <secerr.h> 57 #include <secerr.h>
57 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424 58 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424
58 // until NSS 3.12.2 comes out and we update to it. 59 // until NSS 3.12.2 comes out and we update to it.
59 #define Lock FOO_NSS_Lock 60 #define Lock FOO_NSS_Lock
60 #include <ssl.h> 61 #include <ssl.h>
61 #include <sslerr.h> 62 #include <sslerr.h>
62 #include <pk11pub.h> 63 #include <pk11pub.h>
63 #undef Lock 64 #undef Lock
64 65
65 #include "base/compiler_specific.h" 66 #include "base/compiler_specific.h"
66 #include "base/logging.h" 67 #include "base/logging.h"
67 #include "base/nss_init.h" 68 #include "base/nss_init.h"
68 #include "base/string_util.h" 69 #include "base/string_util.h"
69 #include "net/base/cert_verifier.h" 70 #include "net/base/cert_verifier.h"
70 #include "net/base/io_buffer.h" 71 #include "net/base/io_buffer.h"
71 #include "net/base/net_errors.h" 72 #include "net/base/net_errors.h"
73 #include "net/base/ssl_cert_request_info.h"
72 #include "net/base/ssl_info.h" 74 #include "net/base/ssl_info.h"
73 #include "net/ocsp/nss_ocsp.h" 75 #include "net/ocsp/nss_ocsp.h"
74 76
75 static const int kRecvBufferSize = 4096; 77 static const int kRecvBufferSize = 4096;
76 78
77 namespace net { 79 namespace net {
78 80
79 // State machines are easier to debug if you log state transitions. 81 // State machines are easier to debug if you log state transitions.
80 // Enable these if you want to see what's going on. 82 // Enable these if you want to see what's going on.
81 #if 1 83 #if 1
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 return ERR_CERT_INVALID; 159 return ERR_CERT_INVALID;
158 case SSL_ERROR_REVOKED_CERT_ALERT: 160 case SSL_ERROR_REVOKED_CERT_ALERT:
159 case SEC_ERROR_REVOKED_CERTIFICATE: 161 case SEC_ERROR_REVOKED_CERTIFICATE:
160 case SEC_ERROR_REVOKED_KEY: 162 case SEC_ERROR_REVOKED_KEY:
161 return ERR_CERT_REVOKED; 163 return ERR_CERT_REVOKED;
162 case SEC_ERROR_CA_CERT_INVALID: 164 case SEC_ERROR_CA_CERT_INVALID:
163 case SEC_ERROR_UNKNOWN_ISSUER: 165 case SEC_ERROR_UNKNOWN_ISSUER:
164 case SEC_ERROR_UNTRUSTED_CERT: 166 case SEC_ERROR_UNTRUSTED_CERT:
165 case SEC_ERROR_UNTRUSTED_ISSUER: 167 case SEC_ERROR_UNTRUSTED_ISSUER:
166 return ERR_CERT_AUTHORITY_INVALID; 168 return ERR_CERT_AUTHORITY_INVALID;
169 case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
170 return ERR_SSL_PROTOCOL_ERROR;
167 171
168 default: { 172 default: {
169 if (IS_SSL_ERROR(err)) { 173 if (IS_SSL_ERROR(err)) {
170 LOG(WARNING) << "Unknown SSL error " << err << 174 LOG(WARNING) << "Unknown SSL error " << err <<
171 " mapped to net::ERR_SSL_PROTOCOL_ERROR"; 175 " mapped to net::ERR_SSL_PROTOCOL_ERROR";
172 return ERR_SSL_PROTOCOL_ERROR; 176 return ERR_SSL_PROTOCOL_ERROR;
173 } 177 }
174 if (IS_SEC_ERROR(err)) { 178 if (IS_SEC_ERROR(err)) {
175 // TODO(port): Probably not the best mapping 179 // TODO(port): Probably not the best mapping
176 LOG(WARNING) << "Unknown SEC error " << err << 180 LOG(WARNING) << "Unknown SEC error " << err <<
(...skipping 21 matching lines...) Expand all
198 transport_recv_busy_(false), 202 transport_recv_busy_(false),
199 handshake_io_callback_(this, &SSLClientSocketNSS::OnHandshakeIOComplete), 203 handshake_io_callback_(this, &SSLClientSocketNSS::OnHandshakeIOComplete),
200 transport_(transport_socket), 204 transport_(transport_socket),
201 hostname_(hostname), 205 hostname_(hostname),
202 ssl_config_(ssl_config), 206 ssl_config_(ssl_config),
203 user_connect_callback_(NULL), 207 user_connect_callback_(NULL),
204 user_read_callback_(NULL), 208 user_read_callback_(NULL),
205 user_write_callback_(NULL), 209 user_write_callback_(NULL),
206 user_read_buf_len_(0), 210 user_read_buf_len_(0),
207 user_write_buf_len_(0), 211 user_write_buf_len_(0),
212 client_auth_ca_names_(NULL),
213 client_auth_cert_needed_(false),
208 completed_handshake_(false), 214 completed_handshake_(false),
209 next_handshake_state_(STATE_NONE), 215 next_handshake_state_(STATE_NONE),
210 nss_fd_(NULL), 216 nss_fd_(NULL),
211 nss_bufs_(NULL) { 217 nss_bufs_(NULL) {
212 EnterFunction(""); 218 EnterFunction("");
213 } 219 }
214 220
215 SSLClientSocketNSS::~SSLClientSocketNSS() { 221 SSLClientSocketNSS::~SSLClientSocketNSS() {
216 EnterFunction(""); 222 EnterFunction("");
217 Disconnect(); 223 Disconnect();
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 #endif 317 #endif
312 318
313 rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); 319 rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
314 if (rv != SECSuccess) 320 if (rv != SECSuccess)
315 return ERR_UNEXPECTED; 321 return ERR_UNEXPECTED;
316 322
317 rv = SSL_AuthCertificateHook(nss_fd_, OwnAuthCertHandler, this); 323 rv = SSL_AuthCertificateHook(nss_fd_, OwnAuthCertHandler, this);
318 if (rv != SECSuccess) 324 if (rv != SECSuccess)
319 return ERR_UNEXPECTED; 325 return ERR_UNEXPECTED;
320 326
327 rv = SSL_GetClientAuthDataHook(nss_fd_, ClientAuthHandler, this);
328 if (rv != SECSuccess)
329 return ERR_UNEXPECTED;
330
321 rv = SSL_HandshakeCallback(nss_fd_, HandshakeCallback, this); 331 rv = SSL_HandshakeCallback(nss_fd_, HandshakeCallback, this);
322 if (rv != SECSuccess) 332 if (rv != SECSuccess)
323 return ERR_UNEXPECTED; 333 return ERR_UNEXPECTED;
324 334
325 // Tell SSL the hostname we're trying to connect to. 335 // Tell SSL the hostname we're trying to connect to.
326 SSL_SetURL(nss_fd_, hostname_.c_str()); 336 SSL_SetURL(nss_fd_, hostname_.c_str());
327 337
328 // Tell SSL we're a client; needed if not letting NSPR do socket I/O 338 // Tell SSL we're a client; needed if not letting NSPR do socket I/O
329 SSL_ResetHandshake(nss_fd_, 0); 339 SSL_ResetHandshake(nss_fd_, 0);
330 340
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 user_read_callback_ = NULL; 376 user_read_callback_ = NULL;
367 user_write_callback_ = NULL; 377 user_write_callback_ = NULL;
368 user_read_buf_ = NULL; 378 user_read_buf_ = NULL;
369 user_read_buf_len_ = 0; 379 user_read_buf_len_ = 0;
370 user_write_buf_ = NULL; 380 user_write_buf_ = NULL;
371 user_write_buf_len_ = 0; 381 user_write_buf_len_ = 0;
372 server_cert_ = NULL; 382 server_cert_ = NULL;
373 server_cert_verify_result_.Reset(); 383 server_cert_verify_result_.Reset();
374 completed_handshake_ = false; 384 completed_handshake_ = false;
375 nss_bufs_ = NULL; 385 nss_bufs_ = NULL;
386 if (client_auth_ca_names_) {
387 CERT_FreeDistNames(client_auth_ca_names_);
388 client_auth_ca_names_ = NULL;
389 }
390 client_auth_cert_needed_ = false;
376 391
377 LeaveFunction(""); 392 LeaveFunction("");
378 } 393 }
379 394
380 bool SSLClientSocketNSS::IsConnected() const { 395 bool SSLClientSocketNSS::IsConnected() const {
381 // Ideally, we should also check if we have received the close_notify alert 396 // Ideally, we should also check if we have received the close_notify alert
382 // message from the server, and return false in that case. We're not doing 397 // message from the server, and return false in that case. We're not doing
383 // that, so this function may return a false positive. Since the upper 398 // that, so this function may return a false positive. Since the upper
384 // layer (HttpNetworkTransaction) needs to handle a persistent connection 399 // layer (HttpNetworkTransaction) needs to handle a persistent connection
385 // closed by the server when we send a request anyway, a false positive in 400 // closed by the server when we send a request anyway, a false positive in
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
501 UpdateServerCert(); 516 UpdateServerCert();
502 } 517 }
503 ssl_info->cert_status = server_cert_verify_result_.cert_status; 518 ssl_info->cert_status = server_cert_verify_result_.cert_status;
504 DCHECK(server_cert_ != NULL); 519 DCHECK(server_cert_ != NULL);
505 ssl_info->cert = server_cert_; 520 ssl_info->cert = server_cert_;
506 LeaveFunction(""); 521 LeaveFunction("");
507 } 522 }
508 523
509 void SSLClientSocketNSS::GetSSLCertRequestInfo( 524 void SSLClientSocketNSS::GetSSLCertRequestInfo(
510 SSLCertRequestInfo* cert_request_info) { 525 SSLCertRequestInfo* cert_request_info) {
511 // TODO(wtc): implement this. 526 EnterFunction("");
527 cert_request_info->host_and_port = hostname_;
528 cert_request_info->client_certs.clear();
529
530 void* wincx = SSL_RevealPinArg(nss_fd_);
531
532 CERTCertNicknames* names = CERT_GetCertNicknames(
533 CERT_GetDefaultCertDB(), SEC_CERT_NICKNAMES_USER, wincx);
534
535 if (names) {
536 for (int i = 0; i < names->numnicknames; ++i) {
537 CERTCertificate* cert = CERT_FindUserCertByUsage(
538 CERT_GetDefaultCertDB(), names->nicknames[i],
539 certUsageSSLClient, PR_FALSE, wincx);
540 if (!cert)
541 continue;
542 // Only check unexpired certs.
543 if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) ==
544 secCertTimeValid &&
545 NSS_CmpCertChainWCANames(cert, client_auth_ca_names_) ==
546 SECSuccess) {
547 SECKEYPrivateKey* privkey = PK11_FindKeyByAnyCert(cert, wincx);
548 if (privkey) {
549 X509Certificate* x509_cert = X509Certificate::CreateFromHandle(
550 cert, X509Certificate::SOURCE_LONE_CERT_IMPORT);
551 cert_request_info->client_certs.push_back(x509_cert);
552 SECKEY_DestroyPrivateKey(privkey);
553 continue;
554 }
555 }
556 CERT_DestroyCertificate(cert);
557 }
558 CERT_FreeNicknames(names);
559 }
560 LeaveFunction(cert_request_info->client_certs.size());
512 } 561 }
513 562
514 void SSLClientSocketNSS::DoReadCallback(int rv) { 563 void SSLClientSocketNSS::DoReadCallback(int rv) {
515 EnterFunction(rv); 564 EnterFunction(rv);
516 DCHECK(rv != ERR_IO_PENDING); 565 DCHECK(rv != ERR_IO_PENDING);
517 DCHECK(user_read_callback_); 566 DCHECK(user_read_callback_);
518 567
519 // Since Run may result in Read being called, clear |user_read_callback_| 568 // Since Run may result in Read being called, clear |user_read_callback_|
520 // up front. 569 // up front.
521 CompletionCallback* c = user_read_callback_; 570 CompletionCallback* c = user_read_callback_;
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
814 // in full handshake mode or in resumption handshake mode. 863 // in full handshake mode or in resumption handshake mode.
815 SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg, 864 SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg,
816 PRFileDesc* socket, 865 PRFileDesc* socket,
817 PRBool checksig, 866 PRBool checksig,
818 PRBool is_server) { 867 PRBool is_server) {
819 // Tell NSS to not verify the certificate. 868 // Tell NSS to not verify the certificate.
820 return SECSuccess; 869 return SECSuccess;
821 } 870 }
822 871
823 // static 872 // static
873 // NSS calls this if a client certificate is needed.
874 // Based on Mozilla's NSS_GetClientAuthData.
875 SECStatus SSLClientSocketNSS::ClientAuthHandler(
876 void* arg,
877 PRFileDesc* socket,
878 CERTDistNames* ca_names,
879 CERTCertificate** result_certificate,
880 SECKEYPrivateKey** result_private_key) {
881 SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg);
882
883 that->client_auth_cert_needed_ = !that->ssl_config_.send_client_cert;
884
885 // Second pass: a client certificate should have been selected.
886 if (that->ssl_config_.send_client_cert) {
887 if (that->ssl_config_.client_cert) {
888 void* wincx = SSL_RevealPinArg(socket);
889 CERTCertificate* cert = CERT_DupCertificate(
890 that->ssl_config_.client_cert->os_cert_handle());
891 SECKEYPrivateKey* privkey = PK11_FindKeyByAnyCert(cert, wincx);
892 if (privkey) {
893 // TODO(jsorianopastor): We should wait for server certificate
894 // verification before sending our credentials. See
895 // http://crbug.com/13934.
896 *result_certificate = cert;
897 *result_private_key = privkey;
898 return SECSuccess;
899 }
900 LOG(WARNING) << "Client cert found without private key";
901 }
902 // Send no client certificate.
903 return SECFailure;
904 }
905
906 PRArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
907 CERTDistNames* ca_names_copy = PORT_ArenaZNew(arena, CERTDistNames);
908
909 ca_names_copy->arena = arena;
910 ca_names_copy->head = NULL;
911 ca_names_copy->nnames = ca_names->nnames;
912 ca_names_copy->names = PORT_ArenaZNewArray(arena, SECItem,
913 ca_names->nnames);
914 for (int i = 0; i < ca_names->nnames; ++i)
915 SECITEM_CopyItem(arena, &ca_names_copy->names[i], &ca_names->names[i]);
916
917 that->client_auth_ca_names_ = ca_names_copy;
918 return SECFailure;
919 }
920
921 // static
824 // NSS calls this when handshake is completed. 922 // NSS calls this when handshake is completed.
825 // After the SSL handshake is finished, use CertVerifier to verify 923 // After the SSL handshake is finished, use CertVerifier to verify
826 // the saved server certificate. 924 // the saved server certificate.
827 void SSLClientSocketNSS::HandshakeCallback(PRFileDesc* socket, 925 void SSLClientSocketNSS::HandshakeCallback(PRFileDesc* socket,
828 void* arg) { 926 void* arg) {
829 SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg); 927 SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg);
830 928
831 that->UpdateServerCert(); 929 that->UpdateServerCert();
832 } 930 }
833 931
834 int SSLClientSocketNSS::DoHandshake() { 932 int SSLClientSocketNSS::DoHandshake() {
835 EnterFunction(""); 933 EnterFunction("");
836 int net_error = net::OK; 934 int net_error = net::OK;
837 int rv = SSL_ForceHandshake(nss_fd_); 935 SECStatus rv = SSL_ForceHandshake(nss_fd_);
838 936
839 if (rv == SECSuccess) { 937 if (client_auth_cert_needed_) {
938 net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
939 // If the handshake already succeeded (because the server requests but
940 // doesn't require a client cert), we need to invalidate the SSL session
941 // so that we won't try to resume the non-client-authenticated session in
942 // the next handshake. This will cause the server to ask for a client
943 // cert again.
944 if (rv == SECSuccess && SSL_InvalidateSession(nss_fd_) != SECSuccess) {
945 LOG(WARNING) << "Couldn't invalidate SSL session: " << PR_GetError();
946 }
947 } else if (rv == SECSuccess) {
840 // SSL handshake is completed. Let's verify the certificate. 948 // SSL handshake is completed. Let's verify the certificate.
841 GotoState(STATE_VERIFY_CERT); 949 GotoState(STATE_VERIFY_CERT);
842 // Done! 950 // Done!
843 } else { 951 } else {
844 PRErrorCode prerr = PR_GetError(); 952 PRErrorCode prerr = PR_GetError();
845 953
846 // If the server closed on us, it is a protocol error. 954 // If the server closed on us, it is a protocol error.
847 // Some TLS-intolerant servers do this when we request TLS. 955 // Some TLS-intolerant servers do this when we request TLS.
848 if (prerr == PR_END_OF_FILE_ERROR) { 956 if (prerr == PR_END_OF_FILE_ERROR) {
849 net_error = ERR_SSL_PROTOCOL_ERROR; 957 net_error = ERR_SSL_PROTOCOL_ERROR;
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
939 // Exit DoHandshakeLoop and return the result to the caller to Connect. 1047 // Exit DoHandshakeLoop and return the result to the caller to Connect.
940 DCHECK(next_handshake_state_ == STATE_NONE); 1048 DCHECK(next_handshake_state_ == STATE_NONE);
941 return result; 1049 return result;
942 } 1050 }
943 1051
944 int SSLClientSocketNSS::DoPayloadRead() { 1052 int SSLClientSocketNSS::DoPayloadRead() {
945 EnterFunction(user_read_buf_len_); 1053 EnterFunction(user_read_buf_len_);
946 DCHECK(user_read_buf_); 1054 DCHECK(user_read_buf_);
947 DCHECK(user_read_buf_len_ > 0); 1055 DCHECK(user_read_buf_len_ > 0);
948 int rv = PR_Read(nss_fd_, user_read_buf_->data(), user_read_buf_len_); 1056 int rv = PR_Read(nss_fd_, user_read_buf_->data(), user_read_buf_len_);
1057 if (client_auth_cert_needed_) {
1058 // We don't need to invalidate the non-client-authenticated SSL session
1059 // because the server will renegotiate anyway.
1060 LeaveFunction("");
1061 return ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
1062 }
949 if (rv >= 0) { 1063 if (rv >= 0) {
950 LogData(user_read_buf_->data(), rv); 1064 LogData(user_read_buf_->data(), rv);
951 LeaveFunction(""); 1065 LeaveFunction("");
952 return rv; 1066 return rv;
953 } 1067 }
954 PRErrorCode prerr = PR_GetError(); 1068 PRErrorCode prerr = PR_GetError();
955 if (prerr == PR_WOULD_BLOCK_ERROR) { 1069 if (prerr == PR_WOULD_BLOCK_ERROR) {
956 LeaveFunction(""); 1070 LeaveFunction("");
957 return ERR_IO_PENDING; 1071 return ERR_IO_PENDING;
958 } 1072 }
(...skipping 12 matching lines...) Expand all
971 } 1085 }
972 PRErrorCode prerr = PR_GetError(); 1086 PRErrorCode prerr = PR_GetError();
973 if (prerr == PR_WOULD_BLOCK_ERROR) { 1087 if (prerr == PR_WOULD_BLOCK_ERROR) {
974 return ERR_IO_PENDING; 1088 return ERR_IO_PENDING;
975 } 1089 }
976 LeaveFunction(""); 1090 LeaveFunction("");
977 return NetErrorFromNSPRError(prerr); 1091 return NetErrorFromNSPRError(prerr);
978 } 1092 }
979 1093
980 } // namespace net 1094 } // namespace net
OLDNEW
« no previous file with comments | « net/socket/ssl_client_socket_nss.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698