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

Unified Diff: net/socket/ssl_client_socket_nss.cc

Issue 220009: Provides a certificate for SSL client authentication on NSS sockets.... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/socket/ssl_client_socket_nss.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/socket/ssl_client_socket_nss.cc
===================================================================
--- net/socket/ssl_client_socket_nss.cc (revisiĆ³n: 28534)
+++ net/socket/ssl_client_socket_nss.cc (copia de trabajo)
@@ -51,6 +51,7 @@
#include "net/socket/ssl_client_socket_nss.h"
#include <certdb.h>
+#include <key.h>
#include <nspr.h>
#include <nss.h>
#include <secerr.h>
@@ -69,6 +70,7 @@
#include "net/base/cert_verifier.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/base/ssl_cert_request_info.h"
#include "net/base/ssl_info.h"
#include "net/ocsp/nss_ocsp.h"
@@ -200,6 +202,8 @@
user_connect_callback_(NULL),
user_callback_(NULL),
user_buf_len_(0),
+ client_auth_ca_names_(NULL),
+ client_auth_cert_needed_(false),
completed_handshake_(false),
next_state_(STATE_NONE),
nss_fd_(NULL),
@@ -311,6 +315,10 @@
if (rv != SECSuccess)
return ERR_UNEXPECTED;
+ rv = SSL_GetClientAuthDataHook(nss_fd_, ClientAuthHandler, this);
+ if (rv != SECSuccess)
+ return ERR_UNEXPECTED;
+
rv = SSL_HandshakeCallback(nss_fd_, HandshakeCallback, this);
if (rv != SECSuccess)
return ERR_UNEXPECTED;
@@ -363,6 +371,8 @@
server_cert_verify_result_.Reset();
completed_handshake_ = false;
nss_bufs_ = NULL;
+ client_auth_ca_names_ = NULL;
Jaime Soriano 2009/10/13 11:13:39 If client_auth_ca_names_ is freed here with CERT_F
+ client_auth_cert_needed_ = false;
LeaveFunction("");
}
@@ -488,7 +498,52 @@
void SSLClientSocketNSS::GetSSLCertRequestInfo(
SSLCertRequestInfo* cert_request_info) {
- // TODO(wtc): implement this.
+ CERTCertNicknames *names;
+ void *wincx = NULL;
+ CERTCertificate* cert = NULL;
+ X509Certificate* x509_cert = NULL;
+ SECKEYPrivateKey* privkey = NULL;
+ EnterFunction("");
+
+ cert_request_info->host_and_port = hostname_;
+ cert_request_info->client_certs.clear();
+
+ wincx = SSL_RevealPinArg(nss_fd_);
+
+ names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(),
+ SEC_CERT_NICKNAMES_USER, wincx);
+
+ if (names != NULL) {
+ for (int i = 0; i < names->numnicknames; i++) {
+ cert = CERT_FindUserCertByUsage(
+ CERT_GetDefaultCertDB(),
+ names->nicknames[i],
+ certUsageSSLClient,
+ PR_FALSE,
+ wincx);
+ if (!cert)
+ continue;
+ // Only check unexpired certs
+ if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) !=
+ secCertTimeValid ) {
+ CERT_DestroyCertificate(cert);
+ continue;
+ }
+ if (NSS_CmpCertChainWCANames(cert, client_auth_ca_names_) == SECSuccess) {
+ privkey = PK11_FindKeyByAnyCert(cert, wincx);
+ if (privkey) {
+ x509_cert = X509Certificate::CreateFromHandle(
+ cert, X509Certificate::SOURCE_LONE_CERT_IMPORT);
+ cert_request_info->client_certs.push_back(x509_cert);
+ SECKEY_DestroyPrivateKey(privkey);
+ continue;
+ }
+ }
+ CERT_DestroyCertificate(cert);
+ }
+ CERT_FreeNicknames(names);
+ }
+ LeaveFunction(cert_request_info->client_certs.size());
}
void SSLClientSocketNSS::DoCallback(int rv) {
@@ -691,6 +746,63 @@
}
// static
+// NSS calls this if a client certificate is needed.
+// Based on Mozilla's NSS_GetClientAuthData
+SECStatus SSLClientSocketNSS::ClientAuthHandler(
+ void* arg,
+ PRFileDesc* socket,
+ CERTDistNames* ca_names,
+ CERTCertificate** result_certificate,
+ SECKEYPrivateKey** result_private_key) {
+ SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg);
+ CERTCertificate* cert = NULL;
+ SECKEYPrivateKey* privkey = NULL;
+ PRArenaPool* arena = NULL;
+ CERTDistNames* ca_names_copy = NULL;
+ void *wincx = NULL;
+
+ wincx = SSL_RevealPinArg(socket);
+
+ that->client_auth_cert_needed_ = !that->ssl_config_.send_client_cert;
+
+ // Second pass, a client certificate should have been selected
+ if (that->ssl_config_.send_client_cert) {
+ if (that->ssl_config_.client_cert) {
+ cert = CERT_DupCertificate(
+ that->ssl_config_.client_cert->os_cert_handle());
+ if (cert) {
+ privkey = PK11_FindKeyByAnyCert(cert, wincx);
+ if (privkey) {
+ // TODO(jsorianopastor): We should wait for server certificate
+ // verification before sending our credentials.
+ // (http://code.google.com/p/chromium/issues/detail?id=13934)
+ result_certificate[0] = cert;
+ result_private_key[0] = privkey;
+ return SECSuccess;
+ } else {
+ LOG(WARNING) << "Client cert found without private key";
+ }
+ } else {
+ LOG(WARNING) << "Invalid client cert to send";
+ }
+ }
+ // If not, client authentication failed
+ return SECFailure;
+ }
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ ca_names_copy = PORT_ArenaZNew(arena, CERTDistNames);
+
+ ca_names_copy->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ ca_names_copy->head = NULL;
+ ca_names_copy->nnames = ca_names->nnames;
+ ca_names_copy->names = SECITEM_ArenaDupItem(arena, ca_names->names);
+
+ that->client_auth_ca_names_ = ca_names_copy;
Jaime Soriano 2009/10/13 11:13:39 I'm not sure if this is the correct way to duplica
+ return SECFailure;
+}
+
+// static
// NSS calls this when handshake is completed.
// After the SSL handshake is finished, use CertVerifier to verify
// the saved server certificate.
@@ -707,9 +819,16 @@
int rv = SSL_ForceHandshake(nss_fd_);
if (rv == SECSuccess) {
- // SSL handshake is completed. Let's verify the certificate.
- GotoState(STATE_VERIFY_CERT);
- // Done!
+ if (client_auth_cert_needed_) {
+ net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
+ if (SECSuccess != SSL_ReHandshake(nss_fd_, PR_TRUE)) {
Jaime Soriano 2009/10/13 11:13:39 I tried to remove this, but then it didn't request
+ LOG(WARNING) << "Couldn't restart handshake: " << PR_GetError();
+ }
+ } else {
+ // SSL handshake is completed. Let's verify the certificate.
+ GotoState(STATE_VERIFY_CERT);
+ // Done!
+ }
} else {
PRErrorCode prerr = PR_GetError();
« 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