| Index: runtime/bin/secure_socket.cc
|
| diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
|
| index 671b1a9bafc1a64da61893a5d536e5f8a2f3ed9f..c1953d5df56def2090d6b9386415b84449bde9bb 100644
|
| --- a/runtime/bin/secure_socket.cc
|
| +++ b/runtime/bin/secure_socket.cc
|
| @@ -143,6 +143,20 @@ void FUNCTION_NAME(SecureSocket_RegisterHandshakeCompleteCallback)(
|
| }
|
|
|
|
|
| +void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)(
|
| + Dart_NativeArguments args) {
|
| + Dart_EnterScope();
|
| + Dart_Handle callback =
|
| + ThrowIfError(Dart_GetNativeArgument(args, 1));
|
| + if (!Dart_IsClosure(callback) && !Dart_IsNull(callback)) {
|
| + Dart_ThrowException(DartUtils::NewDartArgumentError(
|
| + "Illegal argument to RegisterBadCertificateCallback"));
|
| + }
|
| + GetFilter(args)->RegisterBadCertificateCallback(callback);
|
| + Dart_ExitScope();
|
| +}
|
| +
|
| +
|
| void FUNCTION_NAME(SecureSocket_ProcessBuffer)(Dart_NativeArguments args) {
|
| Dart_EnterScope();
|
| Dart_Handle buffer_id_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
|
| @@ -205,6 +219,44 @@ 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;
|
| + 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_Handle date_class =
|
| + DartUtils::GetDartClass(DartUtils::kCoreLibURL, "Date");
|
| + Dart_Handle from_milliseconds =
|
| + DartUtils::NewString("fromMillisecondsSinceEpoch");
|
| +
|
| + Dart_Handle start_validity_date =
|
| + Dart_New(date_class, from_milliseconds, 1, &start_validity_int);
|
| + Dart_Handle end_validity_date =
|
| + Dart_New(date_class, from_milliseconds, 1, &end_validity_int);
|
| +
|
| + Dart_Handle x509_class =
|
| + DartUtils::GetDartClass(DartUtils::kIOLibURL, "X509Certificate");
|
| + Dart_Handle arguments[] = { subject_name_object,
|
| + 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;
|
| +}
|
| +
|
| +
|
| void SSLFilter::Init(Dart_Handle dart_this) {
|
| string_start_ = ThrowIfError(
|
| Dart_NewPersistentHandle(DartUtils::NewString("start")));
|
| @@ -252,6 +304,14 @@ void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) {
|
| }
|
|
|
|
|
| +void SSLFilter::RegisterBadCertificateCallback(Dart_Handle complete) {
|
| + if (NULL != bad_certificate_callback_) {
|
| + Dart_DeletePersistentHandle(bad_certificate_callback_);
|
| + }
|
| + bad_certificate_callback_ = ThrowIfError(Dart_NewPersistentHandle(complete));
|
| +}
|
| +
|
| +
|
| void SSLFilter::InitializeLibrary(const char* certificate_database,
|
| const char* password,
|
| bool use_builtin_root_certificates) {
|
| @@ -301,6 +361,7 @@ void SSLFilter::InitializeLibrary(const char* certificate_database,
|
| }
|
| }
|
|
|
| +
|
| char* PasswordCallback(PK11SlotInfo* slot, PRBool retry, void* arg) {
|
| if (!retry) {
|
| return PL_strdup(static_cast<char*>(arg)); // Freed by NSS internals.
|
| @@ -308,6 +369,33 @@ char* PasswordCallback(PK11SlotInfo* slot, PRBool retry, void* arg) {
|
| return NULL;
|
| }
|
|
|
| +
|
| +SECStatus BadCertificateCallback(void* filter, PRFileDesc* fd) {
|
| + return static_cast<SSLFilter*>(filter)->HandleBadCertificate(fd);
|
| +}
|
| +
|
| +
|
| +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);
|
| + return accept ? SECSuccess : SECFailure;
|
| +}
|
| +
|
| +
|
| void SSLFilter::Connect(const char* host_name,
|
| int port,
|
| bool is_server,
|
| @@ -358,7 +446,12 @@ void SSLFilter::Connect(const char* host_name,
|
| }
|
| }
|
|
|
| - PRBool as_server = is_server ? PR_TRUE : PR_FALSE; // Convert bool to PRBool.
|
| + // Install bad certificate callback, and pass 'this' to it if it is called.
|
| + status = SSL_BadCertHook(filter_,
|
| + BadCertificateCallback,
|
| + static_cast<void*>(this));
|
| +
|
| + PRBool as_server = is_server ? PR_TRUE : PR_FALSE;
|
| status = SSL_ResetHandshake(filter_, as_server);
|
| if (status != SECSuccess) {
|
| ThrowPRException("Unsuccessful SSL_ResetHandshake call");
|
|
|