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

Unified Diff: runtime/bin/secure_socket.cc

Issue 11467004: Enable client certificates in SecureSocket and SecureServerSocket (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments Created 8 years 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 | « runtime/bin/secure_socket.h ('k') | runtime/bin/secure_socket_patch.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/bin/secure_socket.cc
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index 44158b524b3f011da520907ac2d19e5b32944c62..c3786837cd671fb70e236113e6f39a7a3b6e6aaa 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -73,43 +73,40 @@ void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle host_name_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
Dart_Handle port_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
- Dart_Handle is_server_object = ThrowIfError(Dart_GetNativeArgument(args, 3));
+ bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
Dart_Handle certificate_name_object =
ThrowIfError(Dart_GetNativeArgument(args, 4));
+ bool request_client_certificate =
+ DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5));
+ bool require_client_certificate =
+ DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 6));
+ bool send_client_certificate =
+ DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 7));
const char* host_name = NULL;
// TODO(whesse): Is truncating a Dart string containing \0 what we want?
ThrowIfError(Dart_StringToCString(host_name_object, &host_name));
int64_t port;
- if (!DartUtils::GetInt64Value(port_object, &port) ||
- port < 0 || port > 65535) {
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Illegal port parameter in _SSLFilter.connect"));
- }
-
- if (!Dart_IsBoolean(is_server_object)) {
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Illegal is_server parameter in _SSLFilter.connect"));
+ if (!DartUtils::GetInt64Value(port_object, &port)) {
+ FATAL("The range of port_object was checked in Dart - it cannot fail here");
}
- bool is_server = DartUtils::GetBooleanValue(is_server_object);
const char* certificate_name = NULL;
- // If this is a server connection, get the certificate to connect with.
- // TODO(whesse): Use this parameter for a client certificate as well.
- if (is_server) {
- if (!Dart_IsString(certificate_name_object)) {
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Non-String certificate parameter in _SSLFilter.connect"));
- }
+ if (Dart_IsString(certificate_name_object)) {
ThrowIfError(Dart_StringToCString(certificate_name_object,
&certificate_name));
}
+ // If this is a server connection, it must have a certificate to connect with.
+ ASSERT(!is_server || certificate_name != NULL);
GetFilter(args)->Connect(host_name,
- static_cast<int>(port),
- is_server,
- certificate_name);
+ static_cast<int>(port),
+ is_server,
+ certificate_name,
+ request_client_certificate,
+ require_client_certificate,
+ send_client_certificate);
Dart_ExitScope();
}
@@ -221,17 +218,30 @@ void FUNCTION_NAME(SecureSocket_InitializeLibrary)
}
-static bool CallBadCertificateCallback(Dart_Handle callback,
- const char* subject_name,
- const char* issuer_name,
- int64_t start_validity,
- int64_t end_validity) {
- if (callback == NULL || Dart_IsNull(callback)) return false;
+void FUNCTION_NAME(SecureSocket_PeerCertificate)
+ (Dart_NativeArguments args) {
Dart_EnterScope();
- Dart_Handle subject_name_object = DartUtils::NewString(subject_name);
- Dart_Handle issuer_name_object = DartUtils::NewString(issuer_name);
- Dart_Handle start_validity_int = Dart_NewInteger(start_validity);
- Dart_Handle end_validity_int = Dart_NewInteger(end_validity);
+ Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate());
+ Dart_ExitScope();
+}
+
+
+static Dart_Handle X509FromCertificate(CERTCertificate* certificate) {
+ PRTime start_validity;
+ PRTime end_validity;
+ SECStatus status =
+ CERT_GetCertTimes(certificate, &start_validity, &end_validity);
+ if (status != SECSuccess) {
+ ThrowPRException("Cannot get validity times from certificate");
+ }
+ int64_t start_epoch_ms = start_validity / PR_USEC_PER_MSEC;
+ int64_t end_epoch_ms = end_validity / PR_USEC_PER_MSEC;
+ Dart_Handle subject_name_object =
+ DartUtils::NewString(certificate->subjectName);
+ Dart_Handle issuer_name_object =
+ DartUtils::NewString(certificate->issuerName);
+ Dart_Handle start_epoch_ms_int = Dart_NewInteger(start_epoch_ms);
+ Dart_Handle end_epoch_ms_int = Dart_NewInteger(end_epoch_ms);
Dart_Handle date_class =
DartUtils::GetDartClass(DartUtils::kCoreLibURL, "Date");
@@ -239,9 +249,9 @@ static bool CallBadCertificateCallback(Dart_Handle callback,
DartUtils::NewString("fromMillisecondsSinceEpoch");
Dart_Handle start_validity_date =
- Dart_New(date_class, from_milliseconds, 1, &start_validity_int);
+ Dart_New(date_class, from_milliseconds, 1, &start_epoch_ms_int);
Dart_Handle end_validity_date =
- Dart_New(date_class, from_milliseconds, 1, &end_validity_int);
+ Dart_New(date_class, from_milliseconds, 1, &end_epoch_ms_int);
Dart_Handle x509_class =
DartUtils::GetDartClass(DartUtils::kIOLibURL, "X509Certificate");
@@ -249,13 +259,7 @@ static bool CallBadCertificateCallback(Dart_Handle callback,
issuer_name_object,
start_validity_date,
end_validity_date };
- Dart_Handle certificate = Dart_New(x509_class, Dart_Null(), 4, arguments);
-
- Dart_Handle result =
- ThrowIfError(Dart_InvokeClosure(callback, 1, &certificate));
- bool c_result = Dart_IsBoolean(result) && DartUtils::GetBooleanValue(result);
- Dart_ExitScope();
- return c_result;
+ return Dart_New(x509_class, Dart_Null(), 4, arguments);
}
@@ -341,21 +345,21 @@ void SSLFilter::InitializeLibrary(const char* certificate_database,
SECMOD_DB,
init_flags);
if (status != SECSuccess) {
- ThrowPRException("Unsuccessful NSS_Init call.");
+ ThrowPRException("Failed NSS_Init call.");
}
status = NSS_SetDomesticPolicy();
if (status != SECSuccess) {
- ThrowPRException("Unsuccessful NSS_SetDomesticPolicy call.");
+ ThrowPRException("Failed NSS_SetDomesticPolicy call.");
}
// Enable TLS, as well as SSL3 and SSL2.
status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE);
if (status != SECSuccess) {
- ThrowPRException("Unsuccessful SSL_OptionSetDefault enable TLS call.");
+ ThrowPRException("Failed SSL_OptionSetDefault enable TLS call.");
}
status = SSL_ConfigServerSessionIDCache(0, 0, 0, NULL);
if (status != SECSuccess) {
- ThrowPRException("Unsuccessful SSL_ConfigServerSessionIDCache call.");
+ ThrowPRException("Failed SSL_ConfigServerSessionIDCache call.");
}
} else {
@@ -373,36 +377,36 @@ char* PasswordCallback(PK11SlotInfo* slot, PRBool retry, void* arg) {
SECStatus BadCertificateCallback(void* filter, PRFileDesc* fd) {
- return static_cast<SSLFilter*>(filter)->HandleBadCertificate(fd);
+ SSLFilter* ssl_filter = static_cast<SSLFilter*>(filter);
+ Dart_Handle callback = ssl_filter->bad_certificate_callback();
+ if (callback == NULL || Dart_IsNull(callback)) return SECFailure;
+
+ Dart_EnterScope();
+ Dart_Handle x509_object = ssl_filter->PeerCertificate();
+ Dart_Handle result =
+ ThrowIfError(Dart_InvokeClosure(callback, 1, &x509_object));
+ bool c_result = Dart_IsBoolean(result) && DartUtils::GetBooleanValue(result);
+ Dart_ExitScope();
+ return c_result ? SECSuccess : SECFailure;
}
-SECStatus SSLFilter::HandleBadCertificate(PRFileDesc* fd) {
- ASSERT(fd == filter_);
- CERTCertificate* certificate = SSL_PeerCertificate(fd);
- PRTime start_validity;
- PRTime end_validity;
- SECStatus status =
- CERT_GetCertTimes(certificate, &start_validity, &end_validity);
- if (status != SECSuccess) {
- ThrowPRException("Cannot get validity times from certificate");
- }
- int64_t start_epoch_ms = start_validity / PR_USEC_PER_MSEC;
- int64_t end_epoch_ms = end_validity / PR_USEC_PER_MSEC;
- bool accept = CallBadCertificateCallback(bad_certificate_callback_,
- certificate->subjectName,
- certificate->issuerName,
- start_epoch_ms,
- end_epoch_ms);
+Dart_Handle SSLFilter::PeerCertificate() {
+ CERTCertificate* certificate = SSL_PeerCertificate(filter_);
+ if (certificate == NULL) return Dart_Null();
+ Dart_Handle x509_object = X509FromCertificate(certificate);
CERT_DestroyCertificate(certificate);
- return accept ? SECSuccess : SECFailure;
+ return x509_object;
}
void SSLFilter::Connect(const char* host_name,
int port,
bool is_server,
- const char* certificate_name) {
+ const char* certificate_name,
+ bool request_client_certificate,
+ bool require_client_certificate,
+ bool send_client_certificate) {
is_server_ = is_server;
if (in_handshake_) {
ThrowException("Connect called while already in handshake state.");
@@ -410,7 +414,7 @@ void SSLFilter::Connect(const char* host_name,
filter_ = SSL_ImportFD(NULL, filter_);
if (filter_ == NULL) {
- ThrowPRException("Unsuccessful SSL_ImportFD call");
+ ThrowPRException("Failed SSL_ImportFD call");
}
SECStatus status;
@@ -420,6 +424,8 @@ void SSLFilter::Connect(const char* host_name,
if (certificate_database == NULL) {
ThrowPRException("Certificate database cannot be loaded");
}
+ // TODO(whesse): Switch to a function that looks up certs by nickname,
+ // so that server and client uses of certificateName agree.
CERTCertificate* certificate = CERT_FindCertByNameString(
certificate_database,
const_cast<char*>(certificate_name));
@@ -434,7 +440,7 @@ void SSLFilter::Connect(const char* host_name,
if (PR_GetError() == -8177) {
ThrowPRException("Certificate database password incorrect");
} else {
- ThrowPRException("Unsuccessful PK11_FindKeyByAnyCert call."
+ ThrowPRException("Failed PK11_FindKeyByAnyCert call."
" Cannot find private key for certificate");
}
}
@@ -444,11 +450,23 @@ void SSLFilter::Connect(const char* host_name,
CERT_DestroyCertificate(certificate);
SECKEY_DestroyPrivateKey(key);
if (status != SECSuccess) {
- ThrowPRException("Unsuccessful SSL_ConfigSecureServer call");
+ ThrowPRException("Failed SSL_ConfigSecureServer call");
+ }
+
+ if (request_client_certificate) {
+ status = SSL_OptionSet(filter_, SSL_REQUEST_CERTIFICATE, PR_TRUE);
+ if (status != SECSuccess) {
+ ThrowPRException("Failed SSL_OptionSet(REQUEST_CERTIFICATE) call");
+ }
+ PRBool require_cert = require_client_certificate ? PR_TRUE : PR_FALSE;
+ status = SSL_OptionSet(filter_, SSL_REQUIRE_CERTIFICATE, require_cert);
+ if (status != SECSuccess) {
+ ThrowPRException("Failed SSL_OptionSet(REQUIRE_CERTIFICATE) call");
+ }
}
} else { // Client.
if (SSL_SetURL(filter_, host_name) == -1) {
- ThrowPRException("Unsuccessful SetURL call");
+ ThrowPRException("Failed SetURL call");
}
// This disables the SSL session cache for client connections.
@@ -458,6 +476,16 @@ void SSLFilter::Connect(const char* host_name,
if (status != SECSuccess) {
ThrowPRException("Failed SSL_OptionSet(NO_CACHE) call");
}
+
+ if (send_client_certificate) {
+ status = SSL_GetClientAuthDataHook(
+ filter_,
+ NSS_GetClientAuthData,
+ static_cast<void*>(const_cast<char*>(certificate_name)));
+ if (status != SECSuccess) {
+ ThrowPRException("Failed SSL_GetClientAuthDataHook call");
+ }
+ }
}
// Install bad certificate callback, and pass 'this' to it if it is called.
@@ -468,7 +496,7 @@ void SSLFilter::Connect(const char* host_name,
PRBool as_server = is_server ? PR_TRUE : PR_FALSE;
status = SSL_ResetHandshake(filter_, as_server);
if (status != SECSuccess) {
- ThrowPRException("Unsuccessful SSL_ResetHandshake call");
+ ThrowPRException("Failed SSL_ResetHandshake call");
}
// SetPeerAddress
@@ -478,12 +506,12 @@ void SSLFilter::Connect(const char* host_name,
PRStatus rv = PR_GetHostByName(host_name, host_entry_buffer,
PR_NETDB_BUF_SIZE, &host_entry);
if (rv != PR_SUCCESS) {
- ThrowPRException("Unsuccessful PR_GetHostByName call");
+ ThrowPRException("Failed PR_GetHostByName call");
}
int index = PR_EnumerateHostEnt(0, &host_entry, port, &host_address);
if (index == -1 || index == 0) {
- ThrowPRException("Unsuccessful PR_EnumerateHostEnt call");
+ ThrowPRException("Failed PR_EnumerateHostEnt call");
}
memio_SetPeerName(filter_, &host_address);
}
« no previous file with comments | « runtime/bin/secure_socket.h ('k') | runtime/bin/secure_socket_patch.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698