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

Unified Diff: net/socket/ssl_server_socket_nss.cc

Issue 994743003: Support for client certs in ssl_server_socket. Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Passing this CL to RyanChung for further work. Created 5 years, 1 month 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_server_socket_nss.h ('k') | net/socket/ssl_server_socket_openssl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/socket/ssl_server_socket_nss.cc
diff --git a/net/socket/ssl_server_socket_nss.cc b/net/socket/ssl_server_socket_nss.cc
index 3ed4da199510e66d781dff74cc10e36b375fb92c..017838fda30eb9d30075a77cd07e901620230a90 100644
--- a/net/socket/ssl_server_socket_nss.cc
+++ b/net/socket/ssl_server_socket_nss.cc
@@ -37,8 +37,12 @@
#include "crypto/rsa_private_key.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/cert/cert_verifier.h"
+#include "net/cert/cert_verify_result.h"
#include "net/log/net_log.h"
#include "net/socket/nss_ssl_util.h"
+#include "net/ssl/ssl_connection_status_flags.h"
+#include "net/ssl/ssl_info.h"
// SSL plaintext fragments are shorter than 16KB. Although the record layer
// overhead is allowed to be 2K + 5 bytes, in practice the overhead is much
@@ -70,6 +74,8 @@ class NSSSSLServerInitSingleton {
}
};
+void DoNothingOnCompletion(int ignore) {}
+
static base::LazyInstance<NSSSSLServerInitSingleton>::Leaky
g_nss_ssl_server_init_singleton = LAZY_INSTANCE_INITIALIZER;
@@ -81,14 +87,14 @@ void EnableSSLServerSockets() {
scoped_ptr<SSLServerSocket> CreateSSLServerSocket(
scoped_ptr<StreamSocket> socket,
- X509Certificate* cert,
+ X509Certificate* certificate,
crypto::RSAPrivateKey* key,
const SSLServerConfig& ssl_config) {
DCHECK(g_nss_server_sockets_init) << "EnableSSLServerSockets() has not been"
<< " called yet!";
return scoped_ptr<SSLServerSocket>(
- new SSLServerSocketNSS(socket.Pass(), cert, key, ssl_config));
+ new SSLServerSocketNSS(socket.Pass(), certificate, key, ssl_config));
}
SSLServerSocketNSS::SSLServerSocketNSS(
@@ -106,7 +112,9 @@ SSLServerSocketNSS::SSLServerSocketNSS(
ssl_config_(ssl_config),
cert_(cert),
next_handshake_state_(STATE_NONE),
- completed_handshake_(false) {
+ completed_handshake_(false),
+ client_cert_ca_list_(),
+ client_cert_verifier_(NULL) {
// TODO(hclam): Need a better way to clone a key.
std::vector<uint8> key_bytes;
CHECK(key->ExportPrivateKey(&key_bytes));
@@ -155,6 +163,20 @@ int SSLServerSocketNSS::Handshake(const CompletionCallback& callback) {
return rv > OK ? OK : rv;
}
+void SSLServerSocketNSS::SetRequireClientCert(bool require_client_cert) {
+ ssl_config_.require_client_cert = require_client_cert;
+}
+
+void SSLServerSocketNSS::SetClientCertCAList(
+ const CertificateList& client_cert_ca_list) {
+ client_cert_ca_list_ = client_cert_ca_list;
+}
+
+void SSLServerSocketNSS::SetClientCertVerifier(
+ CertVerifier* client_cert_verifier) {
+ client_cert_verifier_ = client_cert_verifier;
+}
+
int SSLServerSocketNSS::ExportKeyingMaterial(const base::StringPiece& label,
bool has_context,
const base::StringPiece& context,
@@ -304,8 +326,32 @@ NextProto SSLServerSocketNSS::GetNegotiatedProtocol() const {
}
bool SSLServerSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
- NOTIMPLEMENTED();
- return false;
+ ssl_info->Reset();
+ if (!completed_handshake_) {
+ return false;
+ }
+ ExtractClientCert();
+ ssl_info->cert = client_cert_;
+ UpdateSSLConnectionStatus(nss_fd_, ssl_config_, &ssl_info->connection_status);
+ ssl_info->client_cert_sent = client_cert_.get() ? true : false;
+ PRUint16 cipher_suite =
+ SSLConnectionStatusToCipherSuite(ssl_info->connection_status);
+ SSLCipherSuiteInfo cipher_info;
+ SECStatus ok =
+ SSL_GetCipherSuiteInfo(cipher_suite, &cipher_info, sizeof(cipher_info));
+ if (ok == SECSuccess) {
+ ssl_info->security_bits = cipher_info.effectiveKeyBits;
+ } else {
+ ssl_info->security_bits = -1;
+ }
+ PRBool last_handshake_resumed;
+ SECStatus rv = SSL_HandshakeResumedSession(nss_fd_, &last_handshake_resumed);
+ if (rv == SECSuccess && last_handshake_resumed) {
+ ssl_info->handshake_type = SSLInfo::HANDSHAKE_RESUME;
+ } else {
+ ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
+ }
+ return true;
}
void SSLServerSocketNSS::GetConnectionAttempts(ConnectionAttempts* out) const {
@@ -338,15 +384,6 @@ int SSLServerSocketNSS::InitializeSSLOptions() {
int rv;
- if (ssl_config_.require_client_cert) {
- rv = SSL_OptionSet(nss_fd_, SSL_REQUEST_CERTIFICATE, PR_TRUE);
- if (rv != SECSuccess) {
- LogFailedNSSFunction(net_log_, "SSL_OptionSet",
- "SSL_REQUEST_CERTIFICATE");
- return ERR_UNEXPECTED;
- }
- }
-
rv = SSL_OptionSet(nss_fd_, SSL_SECURITY, PR_TRUE);
if (rv != SECSuccess) {
LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_SECURITY");
@@ -412,13 +449,15 @@ int SSLServerSocketNSS::InitializeSSLOptions() {
return ERR_UNEXPECTED;
}
- rv = SSL_OptionSet(nss_fd_, SSL_REQUEST_CERTIFICATE, PR_FALSE);
+ rv = SSL_OptionSet(nss_fd_, SSL_REQUEST_CERTIFICATE,
+ ssl_config_.require_client_cert ? PR_TRUE : PR_FALSE);
if (rv != SECSuccess) {
LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_REQUEST_CERTIFICATE");
return ERR_UNEXPECTED;
}
- rv = SSL_OptionSet(nss_fd_, SSL_REQUIRE_CERTIFICATE, PR_FALSE);
+ rv = SSL_OptionSet(nss_fd_, SSL_REQUIRE_CERTIFICATE,
+ ssl_config_.require_client_cert ? PR_TRUE : PR_FALSE);
if (rv != SECSuccess) {
LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_REQUIRE_CERTIFICATE");
return ERR_UNEXPECTED;
@@ -508,6 +547,27 @@ int SSLServerSocketNSS::InitializeSSLOptions() {
return ERR_UNEXPECTED;
}
+ // Set up the information needed for the CertificateRequest message
+ if (!client_cert_ca_list_.empty()) {
+ CERTCertList* certs = CERT_NewCertList();
+ if (!certs) {
+ LogFailedNSSFunction(net_log_, "CERT_NewCertList", "");
+ return ERR_UNEXPECTED;
+ }
+ for (CertificateList::const_iterator it = client_cert_ca_list_.begin();
+ it != client_cert_ca_list_.end(); ++it) {
+ CERT_AddCertToListTail(certs,
+ CERT_DupCertificate((*it)->os_cert_handle()));
+ }
+
+ rv = SSL_SetTrustAnchors(nss_fd_, certs);
+ CERT_DestroyCertList(certs);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_SetTrustAnchors", "");
+ return ERR_UNEXPECTED;
+ }
+ }
+
return OK;
}
@@ -822,7 +882,6 @@ void SSLServerSocketNSS::DoWriteCallback(int rv) {
// static
// NSS calls this if an incoming certificate needs to be verified.
-// Do nothing but return SECSuccess.
// This is called only in full handshake mode.
// Peer certificate is retrieved in HandshakeCallback() later, which is called
// in full handshake mode or in resumption handshake mode.
@@ -830,9 +889,27 @@ SECStatus SSLServerSocketNSS::OwnAuthCertHandler(void* arg,
PRFileDesc* socket,
PRBool checksig,
PRBool is_server) {
- // TODO(hclam): Implement.
- // Tell NSS to not verify the certificate.
- return SECSuccess;
+ if (!is_server)
+ return SECFailure;
+ SSLServerSocketNSS* self = reinterpret_cast<SSLServerSocketNSS*>(arg);
+ DCHECK(self);
+ if (!self->client_cert_verifier_)
+ return SECSuccess;
+ self->ExtractClientCert();
+ X509Certificate* cert = self->client_cert_.get();
+ if (!cert) {
+ PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0);
+ return SECFailure;
+ }
+ CertVerifyResult ignore_result;
+ scoped_ptr<CertVerifier::Request> ignore_async;
+ int res = self->client_cert_verifier_->Verify(
+ cert, std::string(), std::string(), 0, NULL, &ignore_result,
+ base::Bind(&DoNothingOnCompletion), &ignore_async, self->net_log_);
+ if (res != OK) {
+ PR_SetError(SSL_ERROR_BAD_CERTIFICATE, 0);
+ }
+ return res == OK ? SECSuccess : SECFailure;
}
// static
@@ -854,4 +931,24 @@ int SSLServerSocketNSS::Init() {
return OK;
}
+void SSLServerSocketNSS::ExtractClientCert() {
+ if (client_cert_.get())
+ return;
+ if (!completed_handshake_)
+ return;
+ CERTCertList* list = SSL_PeerCertificateChain(nss_fd_);
+ if (list == NULL)
+ return;
+ std::vector<base::StringPiece> certs;
+ for (CERTCertListNode* node = CERT_LIST_HEAD(list);
+ !CERT_LIST_END(node, list); node = CERT_LIST_NEXT(node)) {
+ SECItem& cert_der = node->cert->derCert;
+ base::StringPiece cert(reinterpret_cast<char*>(cert_der.data),
+ cert_der.len);
+ certs.push_back(cert);
+ }
+ client_cert_ = X509Certificate::CreateFromDERCertChain(certs);
+ CERT_DestroyCertList(list);
+}
+
} // namespace net
« no previous file with comments | « net/socket/ssl_server_socket_nss.h ('k') | net/socket/ssl_server_socket_openssl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698