| Index: net/socket/ssl_client_socket_nss.cc
|
| ===================================================================
|
| --- net/socket/ssl_client_socket_nss.cc (revision 41189)
|
| +++ net/socket/ssl_client_socket_nss.cc (working copy)
|
| @@ -540,9 +540,9 @@
|
|
|
| int rv = DoReadLoop(OK);
|
|
|
| - if (rv == ERR_IO_PENDING)
|
| + if (rv == ERR_IO_PENDING) {
|
| user_read_callback_ = callback;
|
| - else {
|
| + } else {
|
| user_read_buf_ = NULL;
|
| user_read_buf_len_ = 0;
|
| }
|
| @@ -565,9 +565,9 @@
|
|
|
| int rv = DoWriteLoop(OK);
|
|
|
| - if (rv == ERR_IO_PENDING)
|
| + if (rv == ERR_IO_PENDING) {
|
| user_write_callback_ = callback;
|
| - else {
|
| + } else {
|
| user_write_buf_ = NULL;
|
| user_write_buf_len_ = 0;
|
| }
|
| @@ -698,7 +698,7 @@
|
| void SSLClientSocketNSS::GetSSLCertRequestInfo(
|
| SSLCertRequestInfo* cert_request_info) {
|
| EnterFunction("");
|
| - cert_request_info->host_and_port = hostname_;
|
| + cert_request_info->host_and_port = hostname_; // TODO(wtc): no port!
|
| cert_request_info->client_certs = client_certs_;
|
| LeaveFunction(cert_request_info->client_certs.size());
|
| }
|
| @@ -1094,15 +1094,86 @@
|
| CERTDistNames* ca_names,
|
| CERTCertificate** result_certificate,
|
| SECKEYPrivateKey** result_private_key) {
|
| -#if defined(OS_WIN)
|
| - // Not implemented. Send no client certificate.
|
| - PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
|
| - return SECFailure;
|
| -#else
|
| SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg);
|
|
|
| that->client_auth_cert_needed_ = !that->ssl_config_.send_client_cert;
|
|
|
| +#if defined(OS_WIN)
|
| + if (that->ssl_config_.send_client_cert) {
|
| + // TODO(wtc): SSLClientSocketNSS can't do SSL client authentication using
|
| + // CryptoAPI yet (http://crbug.com/37560), so client_cert must be NULL.
|
| + DCHECK(!that->ssl_config_.client_cert);
|
| + // Send no client certificate.
|
| + return SECFailure;
|
| + }
|
| +
|
| + that->client_certs_.clear();
|
| +
|
| + std::vector<CERT_NAME_BLOB> issuer_list(ca_names->nnames);
|
| + for (int i = 0; i < ca_names->nnames; ++i) {
|
| + issuer_list[i].cbData = ca_names->names[i].len;
|
| + issuer_list[i].pbData = ca_names->names[i].data;
|
| + }
|
| +
|
| + // Client certificates of the user are in the "MY" system certificate store.
|
| + HCERTSTORE my_cert_store = CertOpenSystemStore(NULL, L"MY");
|
| + if (!my_cert_store) {
|
| + LOG(ERROR) << "Could not open the \"MY\" system certificate store: "
|
| + << GetLastError();
|
| + return SECFailure;
|
| + }
|
| +
|
| + // Enumerate the client certificates.
|
| + CERT_CHAIN_FIND_BY_ISSUER_PARA find_by_issuer_para;
|
| + memset(&find_by_issuer_para, 0, sizeof(find_by_issuer_para));
|
| + find_by_issuer_para.cbSize = sizeof(find_by_issuer_para);
|
| + find_by_issuer_para.pszUsageIdentifier = szOID_PKIX_KP_CLIENT_AUTH;
|
| + find_by_issuer_para.cIssuer = ca_names->nnames;
|
| + find_by_issuer_para.rgIssuer = ca_names->nnames ? &issuer_list[0] : NULL;
|
| +
|
| + PCCERT_CHAIN_CONTEXT chain_context = NULL;
|
| +
|
| + for (;;) {
|
| + // Find a certificate chain.
|
| + chain_context = CertFindChainInStore(my_cert_store,
|
| + X509_ASN_ENCODING,
|
| + 0,
|
| + CERT_CHAIN_FIND_BY_ISSUER,
|
| + &find_by_issuer_para,
|
| + chain_context);
|
| + if (!chain_context) {
|
| + DWORD err = GetLastError();
|
| + if (err != CRYPT_E_NOT_FOUND)
|
| + DLOG(ERROR) << "CertFindChainInStore failed: " << err;
|
| + break;
|
| + }
|
| +
|
| + // Get the leaf certificate.
|
| + PCCERT_CONTEXT cert_context =
|
| + chain_context->rgpChain[0]->rgpElement[0]->pCertContext;
|
| + // Copy it to our own certificate store, so that we can close the "MY"
|
| + // certificate store before returning from this function.
|
| + PCCERT_CONTEXT cert_context2;
|
| + BOOL ok = CertAddCertificateContextToStore(cert_store_, cert_context,
|
| + CERT_STORE_ADD_USE_EXISTING,
|
| + &cert_context2);
|
| + if (!ok) {
|
| + NOTREACHED();
|
| + continue;
|
| + }
|
| + scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
|
| + cert_context2, X509Certificate::SOURCE_LONE_CERT_IMPORT,
|
| + net::X509Certificate::OSCertHandles());
|
| + that->client_certs_.push_back(cert);
|
| + }
|
| +
|
| + BOOL ok = CertCloseStore(my_cert_store, CERT_CLOSE_STORE_CHECK_FLAG);
|
| + DCHECK(ok);
|
| +
|
| + // Tell NSS to suspend the client authentication. We will then abort the
|
| + // handshake by returning ERR_SSL_CLIENT_AUTH_CERT_NEEDED.
|
| + return SECWouldBlock;
|
| +#else
|
| CERTCertificate* cert = NULL;
|
| SECKEYPrivateKey* privkey = NULL;
|
| void* wincx = SSL_RevealPinArg(socket);
|
| @@ -1304,7 +1375,7 @@
|
| int SSLClientSocketNSS::DoPayloadRead() {
|
| EnterFunction(user_read_buf_len_);
|
| DCHECK(user_read_buf_);
|
| - DCHECK(user_read_buf_len_ > 0);
|
| + DCHECK_GT(user_read_buf_len_, 0);
|
| int rv = PR_Read(nss_fd_, user_read_buf_->data(), user_read_buf_len_);
|
| if (client_auth_cert_needed_) {
|
| // We don't need to invalidate the non-client-authenticated SSL session
|
|
|