Remove the certificate management methods from dart:io

Certificate management functions where added to dart:io in r25610 and
r26002. However these functions where mutating the NSS database for
the whole Dart process, and some functions where also persisting the
changes to the database.

This might cause issues when running multiple isolates as changes in
one isolate will affect other isolates and could lead to unexpected
results.

These functions are removed from dart:io for now.

BUG=http://dartbug.com/8227
TBR=ager@google.com

Review URL: https://codereview.chromium.org//22887014

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@26194 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
sgjesse@google.com 2013-08-15 14:55:53 +00:00
parent 305af7b5b0
commit affa849184
14 changed files with 78 additions and 813 deletions

View file

@ -51,12 +51,7 @@ namespace bin {
V(SecureSocket_RegisterBadCertificateCallback, 2) \
V(SecureSocket_RegisterHandshakeCompleteCallback, 2) \
V(SecureSocket_Renegotiate, 4) \
V(SecureSocket_InitializeLibrary, 4) \
V(SecureSocket_AddCertificate, 2) \
V(SecureSocket_ChangeTrust, 2) \
V(SecureSocket_ImportCertificatesWithPrivateKeys, 2) \
V(SecureSocket_GetCertificate, 1) \
V(SecureSocket_RemoveCertificate, 1) \
V(SecureSocket_InitializeLibrary, 3) \
V(SecureSocket_NewServicePort, 0) \
V(SecureSocket_FilterPointer, 1) \
V(ServerSocket_CreateBindListen, 5) \

View file

@ -17,7 +17,6 @@
'variables': {
# Added by Dart.
'nss_directory': '../../../third_party/nss',
'pkcs12_directory': '../../../third_party/nss_pkcs12',
'conditions': [
['OS=="ios"', {
'exclude_nss_root_certs%': 0,
@ -1069,19 +1068,6 @@
'<(nss_directory)/nss/lib/util/utilpars.h',
'<(nss_directory)/nss/lib/util/utilparst.h',
'<(nss_directory)/nss/lib/util/utilrename.h',
'<(pkcs12_directory)/p12creat.c',
'<(pkcs12_directory)/p12d.c',
'<(pkcs12_directory)/p12dec.c',
'<(pkcs12_directory)/p12e.c',
'<(pkcs12_directory)/p12.h',
'<(pkcs12_directory)/p12local.c',
'<(pkcs12_directory)/p12local.h',
'<(pkcs12_directory)/p12plcy.c',
'<(pkcs12_directory)/p12plcy.h',
'<(pkcs12_directory)/p12t.h',
'<(pkcs12_directory)/p12tmpl.c',
'<(pkcs12_directory)/pkcs12.h',
'<(pkcs12_directory)/pkcs12t.h',
],
'sources!': [
# mpi_arm.c is included by mpi_arm_mac.c.
@ -1147,7 +1133,6 @@
'<(nss_directory)/nss/lib/softoken',
'<(nss_directory)/nss/lib/ssl',
'<(nss_directory)/nss/lib/util',
'<(pkcs12_directory)',
],
'direct_dependent_settings': {
'defines': [
@ -1174,7 +1159,6 @@
'<(nss_directory)/nss/lib/smime',
'<(nss_directory)/nss/lib/softoken',
'<(nss_directory)/nss/lib/util',
'<(pkcs12_directory)',
],
},
'msvs_disabled_warnings': [4018, 4101, 4267, ],

View file

@ -10,12 +10,9 @@
#include <stdio.h>
#include <string.h>
#include <certdb.h>
#include <key.h>
#include <keyt.h>
#include <nss.h>
#include <p12.h>
#include <p12plcy.h>
#include <pk11pub.h>
#include <prerror.h>
#include <prinit.h>
@ -40,10 +37,10 @@ namespace bin {
bool SSLFilter::library_initialized_ = false;
// To protect library initialization.
dart::Mutex* SSLFilter::mutex = new dart::Mutex();
dart::Mutex* SSLFilter::mutex_ = new dart::Mutex();
// The password is needed when creating secure server sockets. It can
// be null if only secure client sockets are used.
char* SSLFilter::password_ = NULL;
const char* SSLFilter::password_ = NULL;
// Forward declaration.
static void ProcessFilter(Dart_Port dest_port_id,
@ -232,7 +229,7 @@ void FUNCTION_NAME(SecureSocket_InitializeLibrary)
&certificate_database));
} else if (!Dart_IsNull(certificate_database_object)) {
Dart_ThrowException(DartUtils::NewDartArgumentError(
"SecureSocket.initialize: database argument is not a String or null"));
"Non-String certificate directory argument to SetCertificateDatabase"));
}
// Leave certificate_database as NULL if no value was provided.
@ -247,7 +244,7 @@ void FUNCTION_NAME(SecureSocket_InitializeLibrary)
password = "";
} else {
Dart_ThrowException(DartUtils::NewDartArgumentError(
"SecureSocket.initialize: password argument is not a String or null"));
"Password argument to SetCertificateDatabase is not a String or null"));
}
Dart_Handle builtin_roots_object =
@ -258,322 +255,10 @@ void FUNCTION_NAME(SecureSocket_InitializeLibrary)
ThrowIfError(Dart_BooleanValue(builtin_roots_object, &builtin_roots));
} else {
Dart_ThrowException(DartUtils::NewDartArgumentError(
"SecureSocket.initialize: useBuiltinRoots argument is not a bool"));
"UseBuiltinRoots argument to SetCertificateDatabase is not a bool"));
}
Dart_Handle read_only_object =
ThrowIfError(Dart_GetNativeArgument(args, 3));
// Check that the type is boolean, and get the boolean value from it.
bool read_only = true;
if (Dart_IsBoolean(read_only_object)) {
ThrowIfError(Dart_BooleanValue(read_only_object, &read_only));
} else {
Dart_ThrowException(DartUtils::NewDartArgumentError(
"SecureSocket.initialize: readOnly argument is not a bool"));
}
SSLFilter::InitializeLibrary(
certificate_database, password, builtin_roots, read_only);
}
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("CertificateException",
"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_type =
DartUtils::GetDartType(DartUtils::kCoreLibURL, "DateTime");
Dart_Handle from_milliseconds =
DartUtils::NewString("fromMillisecondsSinceEpoch");
Dart_Handle start_validity_date =
Dart_New(date_type, from_milliseconds, 1, &start_epoch_ms_int);
Dart_Handle end_validity_date =
Dart_New(date_type, from_milliseconds, 1, &end_epoch_ms_int);
Dart_Handle x509_type =
DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate");
Dart_Handle arguments[] = { subject_name_object,
issuer_name_object,
start_validity_date,
end_validity_date };
return Dart_New(x509_type, Dart_Null(), 4, arguments);
}
char* PasswordCallback(PK11SlotInfo* slot, PRBool retry, void* arg) {
if (!retry) {
return PL_strdup(static_cast<char*>(arg)); // Freed by NSS internals.
}
return NULL;
}
void FUNCTION_NAME(SecureSocket_AddCertificate)
(Dart_NativeArguments args) {
Dart_Handle certificate_object =
ThrowIfError(Dart_GetNativeArgument(args, 0));
Dart_Handle trust_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
if (!Dart_IsList(certificate_object) || !Dart_IsString(trust_object)) {
Dart_ThrowException(DartUtils::NewDartArgumentError(
"Bad argument to SecureSocket.addCertificate"));
}
intptr_t length;
ThrowIfError(Dart_ListLength(certificate_object, &length));
uint8_t* certificate = reinterpret_cast<uint8_t*>(malloc(length + 1));
if (certificate == NULL) {
FATAL("Out of memory in SecureSocket.addCertificate");
}
ThrowIfError(Dart_ListGetAsBytes(
certificate_object, 0, certificate, length));
const char* trust_string;
ThrowIfError(Dart_StringToCString(trust_object,
&trust_string));
PK11SlotInfo* slot = PK11_GetInternalKeySlot();
SECStatus status = PK11_Authenticate(slot, PR_TRUE, SSLFilter::GetPassword());
PK11_FreeSlot(slot);
if (status == SECFailure) {
ThrowPRException("CertificateException",
"Could not authenticate to certificate database");
}
CERTCertificate* cert = CERT_DecodeCertFromPackage(
reinterpret_cast<char*>(certificate), length);
if (cert == NULL) {
ThrowPRException("CertificateException", "Certificate cannot be decoded");
}
CERTCertTrust trust;
status = CERT_DecodeTrustString(&trust, trust_string);
if (status != SECSuccess) {
ThrowPRException("CertificateException", "Trust string cannot be decoded");
}
{
MutexLocker locker(SSLFilter::mutex);
status = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, &trust);
}
if (status != SECSuccess) {
ThrowPRException("CertificateException", "Cannot set trust attributes");
}
Dart_SetReturnValue(args, X509FromCertificate(cert));
return;
}
/*
* Called by the PKCS#12 decoder if a certificate's nickname collides with
* the nickname of a different existing certificate in the database.
*/
SECItem* nickname_callback(SECItem *old_nickname,
PRBool *cancel,
void *arg) {
*cancel = PR_TRUE;
return NULL;
}
void FUNCTION_NAME(SecureSocket_ImportCertificatesWithPrivateKeys)
(Dart_NativeArguments args) {
Dart_Handle pk12_object = ThrowIfError(Dart_GetNativeArgument(args, 0));
if (!Dart_IsList(pk12_object)) {
Dart_ThrowException(DartUtils::NewDartArgumentError(
"SecureSocket.importPrivateCertificates: certificates is not a List"));
}
Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
if (!Dart_IsString(password_object)) {
Dart_ThrowException(DartUtils::NewDartArgumentError(
"SecureSocket.importPrivateCertificates: password is not a String"));
}
intptr_t length;
ThrowIfError(Dart_ListLength(pk12_object, &length));
uint8_t* pk12 = Dart_ScopeAllocate(length);
if (pk12 == NULL) {
FATAL("Out of memory in SecureSocket.importPrivateCertificates");
}
ThrowIfError(Dart_ListGetAsBytes(pk12_object, 0, pk12, length));
// A big-endian Unicode (UTF16) password.
intptr_t password_length;
ThrowIfError(Dart_StringLength(password_object, &password_length));
password_length++;
uint16_t* password = reinterpret_cast<uint16_t*>(
Dart_ScopeAllocate(sizeof(uint16_t) * password_length));
if (password == NULL) {
FATAL("Out of memory in SecureSocket.importPrivateCertificates");
}
intptr_t returned_length = password_length;
ThrowIfError(Dart_StringToUTF16(password_object, password, &returned_length));
ASSERT(password_length == returned_length + 1);
password[password_length - 1] = 0;
for (int i = 0; i < password_length; ++i) {
password[i] = Utils::HostToBigEndian16(password[i]);
}
SECItem p12_password;
p12_password.type = siBuffer;
p12_password.data = reinterpret_cast<unsigned char*>(password);
p12_password.len = sizeof(uint16_t) * password_length;
Dart_SetReturnValue(args, Dart_Null());
// Set the password callback for the certificate database we are importing to.
// The password for a slot is gotten from a callback, and it is freed by the
// caller of the callback. The argument to the callback comes from the wincx
// argument to a PK11 function.
PK11SlotInfo* slot = PK11_GetInternalKeySlot();
SECStatus status = PK11_Authenticate(slot, PR_TRUE, SSLFilter::GetPassword());
if (status == SECFailure) {
PK11_FreeSlot(slot);
ThrowPRException("CertificateException",
"Could not authenticate to certificate database");
}
SEC_PKCS12DecoderContext* context = SEC_PKCS12DecoderStart(
&p12_password,
slot,
SSLFilter::GetPassword(),
NULL,
NULL,
NULL,
NULL,
NULL);
PK11_FreeSlot(slot);
if (!context) {
FATAL("Unexpected error: SecureSocket.addPrivateCertificates DecoderStart");
}
bool success;
{
MutexLocker locker(SSLFilter::mutex);
success =
SECSuccess == SEC_PKCS12DecoderUpdate(context, pk12, length) &&
SECSuccess == SEC_PKCS12DecoderVerify(context) &&
SECSuccess == SEC_PKCS12DecoderValidateBags(context,
nickname_callback) &&
SECSuccess == SEC_PKCS12DecoderImportBags(context);
}
SEC_PKCS12DecoderFinish(context);
if (!success) {
ThrowPRException("CertificateException", "Could not import PKCS#12 file");
}
}
void FUNCTION_NAME(SecureSocket_ChangeTrust)(Dart_NativeArguments args) {
Dart_Handle nickname_object = ThrowIfError(Dart_GetNativeArgument(args, 0));
if (!Dart_IsString(nickname_object)) {
Dart_ThrowException(DartUtils::NewDartArgumentError(
"SecureSocket.changeTrust: nickname argument is not a String"));
}
const char* nickname;
ThrowIfError(Dart_StringToCString(nickname_object, &nickname));
Dart_Handle trust_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
if (!Dart_IsString(trust_object)) {
Dart_ThrowException(DartUtils::NewDartArgumentError(
"SecureSocket.changeTrust: trust argument is not a String"));
}
const char* trust_string;
ThrowIfError(Dart_StringToCString(trust_object, &trust_string));
PK11SlotInfo* slot = PK11_GetInternalKeySlot();
SECStatus status = PK11_Authenticate(slot, PR_TRUE, SSLFilter::GetPassword());
if (status == SECFailure) {
ThrowPRException("CertificateException",
"Could not authenticate to certificate database");
}
PK11_FreeSlot(slot);
CERTCertificate* certificate =
PK11_FindCertFromNickname(nickname, SSLFilter::GetPassword());
if (certificate == NULL) {
ThrowCertificateException("Cannot find certificate with nickname %s",
nickname);
}
CERTCertTrust trust;
if (SECSuccess != CERT_DecodeTrustString(&trust, trust_string)) {
CERT_DestroyCertificate(certificate);
ThrowPRException("CertificateException", "Trust string cannot be decoded");
}
{
MutexLocker locker(SSLFilter::mutex);
status = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), certificate, &trust);
}
if (status != SECSuccess) {
CERT_DestroyCertificate(certificate);
ThrowCertificateException("Cannot set trust on certificate %s", nickname);
}
Dart_SetReturnValue(args, X509FromCertificate(certificate));
CERT_DestroyCertificate(certificate);
}
void FUNCTION_NAME(SecureSocket_GetCertificate)(Dart_NativeArguments args) {
Dart_Handle nickname_object = ThrowIfError(Dart_GetNativeArgument(args, 0));
if (!Dart_IsString(nickname_object)) {
Dart_ThrowException(DartUtils::NewDartArgumentError(
"SecureSocket.getCertificate: nickname argument is not a String"));
}
const char* nickname;
ThrowIfError(Dart_StringToCString(nickname_object, &nickname));
CERTCertificate* certificate = PK11_FindCertFromNickname(
nickname, SSLFilter::GetPassword());
if (certificate != NULL) {
Dart_SetReturnValue(args, X509FromCertificate(certificate));
CERT_DestroyCertificate(certificate);
}
}
void FUNCTION_NAME(SecureSocket_RemoveCertificate)(Dart_NativeArguments args) {
Dart_Handle nickname_object =
ThrowIfError(Dart_GetNativeArgument(args, 0));
if (!Dart_IsString(nickname_object)) {
Dart_ThrowException(DartUtils::NewDartArgumentError(
"SecureSocket.removeCertificate: nickname is not a String"));
}
const char* nickname;
ThrowIfError(Dart_StringToCString(nickname_object, &nickname));
CERTCertificate* certificate =
PK11_FindCertFromNickname(nickname, SSLFilter::GetPassword());
if (certificate == NULL) {
ThrowCertificateException("Cannot find certificate with nickname %s",
nickname);
}
SECKEYPrivateKey* key =
PK11_FindKeyByAnyCert(certificate, SSLFilter::GetPassword());
// Free the copy returned from FindKeyByAnyCert.
SECKEY_DestroyPrivateKey(key);
SECStatus status;
{
MutexLocker locker(SSLFilter::mutex);
status = (key == NULL) ?
SEC_DeletePermCertificate(certificate) :
PK11_DeleteTokenCertAndKey(certificate, SSLFilter::GetPassword());
}
CERT_DestroyCertificate(certificate);
if (status != SECSuccess) {
ThrowCertificateException("Cannot remove certificate %s", nickname);
}
SSLFilter::InitializeLibrary(certificate_database, password, builtin_roots);
}
@ -723,9 +408,47 @@ bool SSLFilter::ProcessAllBuffers(int starts[kNumBuffers],
}
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("CertificateException",
"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_type =
DartUtils::GetDartType(DartUtils::kCoreLibURL, "DateTime");
Dart_Handle from_milliseconds =
DartUtils::NewString("fromMillisecondsSinceEpoch");
Dart_Handle start_validity_date =
Dart_New(date_type, from_milliseconds, 1, &start_epoch_ms_int);
Dart_Handle end_validity_date =
Dart_New(date_type, from_milliseconds, 1, &end_epoch_ms_int);
Dart_Handle x509_type =
DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate");
Dart_Handle arguments[] = { subject_name_object,
issuer_name_object,
start_validity_date,
end_validity_date };
return Dart_New(x509_type, Dart_Null(), 4, arguments);
}
void SSLFilter::Init(Dart_Handle dart_this) {
if (!library_initialized_) {
InitializeLibrary(NULL, "", true, true, false);
InitializeLibrary(NULL, "", true, false);
}
ASSERT(string_start_ == NULL);
string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start"));
@ -798,6 +521,14 @@ void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) {
}
char* PasswordCallback(PK11SlotInfo* slot, PRBool retry, void* arg) {
if (!retry) {
return PL_strdup(static_cast<char*>(arg)); // Freed by NSS internals.
}
return NULL;
}
static const char* builtin_roots_module =
#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID)
"name=\"Root Certs\" library=\"libnssckbi.so\"";
@ -814,9 +545,8 @@ static const char* builtin_roots_module =
void SSLFilter::InitializeLibrary(const char* certificate_database,
const char* password,
bool use_builtin_root_certificates,
bool read_only,
bool report_duplicate_initialization) {
MutexLocker locker(mutex);
MutexLocker locker(mutex_);
SECStatus status;
if (!library_initialized_) {
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
@ -824,7 +554,7 @@ void SSLFilter::InitializeLibrary(const char* certificate_database,
if (certificate_database == NULL || certificate_database[0] == '\0') {
status = NSS_NoDB_Init(NULL);
if (status != SECSuccess) {
mutex->Unlock(); // MutexLocker destructor not called when throwing.
mutex_->Unlock(); // MutexLocker destructor not called when throwing.
ThrowPRException("TlsException",
"Failed NSS_NoDB_Init call.");
}
@ -832,13 +562,13 @@ void SSLFilter::InitializeLibrary(const char* certificate_database,
SECMODModule* module = SECMOD_LoadUserModule(
const_cast<char*>(builtin_roots_module), NULL, PR_FALSE);
if (!module) {
mutex->Unlock(); // MutexLocker destructor not called when throwing.
mutex_->Unlock(); // MutexLocker destructor not called when throwing.
ThrowPRException("TlsException",
"Failed to load builtin root certificates.");
}
}
} else {
PRUint32 init_flags = read_only ? NSS_INIT_READONLY : 0;
PRUint32 init_flags = NSS_INIT_READONLY;
if (!use_builtin_root_certificates) {
init_flags |= NSS_INIT_NOMODDB;
}
@ -848,7 +578,7 @@ void SSLFilter::InitializeLibrary(const char* certificate_database,
SECMOD_DB,
init_flags);
if (status != SECSuccess) {
mutex->Unlock(); // MutexLocker destructor not called when throwing.
mutex_->Unlock(); // MutexLocker destructor not called when throwing.
ThrowPRException("TlsException",
"Failed NSS_Init call.");
}
@ -857,34 +587,28 @@ void SSLFilter::InitializeLibrary(const char* certificate_database,
}
library_initialized_ = true;
// Allow encoding and decoding of private keys in PKCS#12 files.
SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
status = NSS_SetDomesticPolicy();
if (status != SECSuccess) {
mutex->Unlock(); // MutexLocker destructor not called when throwing.
mutex_->Unlock(); // MutexLocker destructor not called when throwing.
ThrowPRException("TlsException",
"Failed NSS_SetDomesticPolicy call.");
}
// Enable TLS, as well as SSL3 and SSL2.
status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE);
if (status != SECSuccess) {
mutex->Unlock(); // MutexLocker destructor not called when throwing.
mutex_->Unlock(); // MutexLocker destructor not called when throwing.
ThrowPRException("TlsException",
"Failed SSL_OptionSetDefault enable TLS call.");
}
status = SSL_ConfigServerSessionIDCache(0, 0, 0, NULL);
if (status != SECSuccess) {
mutex->Unlock(); // MutexLocker destructor not called when throwing.
mutex_->Unlock(); // MutexLocker destructor not called when throwing.
ThrowPRException("TlsException",
"Failed SSL_ConfigServerSessionIDCache call.");
}
} else if (report_duplicate_initialization) {
mutex->Unlock(); // MutexLocker destructor not called when throwing.
mutex_->Unlock(); // MutexLocker destructor not called when throwing.
// Like ThrowPRException, without adding an OSError.
Dart_ThrowException(DartUtils::NewDartIOException("TlsException",
"Called SecureSocket.initialize more than once",
@ -959,20 +683,23 @@ void SSLFilter::Connect(const char* host_name,
const_cast<char*>(certificate_name));
if (certificate == NULL) {
ThrowCertificateException(
"Cannot find server certificate with distinguished name %s",
"Cannot find server certificate by distinguished name: %s",
certificate_name);
}
} else {
// Look up certificate using the nickname certificate_name.
certificate = PK11_FindCertFromNickname(
const_cast<char*>(certificate_name), GetPassword());
const_cast<char*>(certificate_name),
static_cast<void*>(const_cast<char*>(password_)));
if (certificate == NULL) {
ThrowCertificateException(
"Cannot find server certificate with nickname %s",
"Cannot find server certificate by nickname: %s",
certificate_name);
}
}
SECKEYPrivateKey* key = PK11_FindKeyByAnyCert(certificate, GetPassword());
SECKEYPrivateKey* key = PK11_FindKeyByAnyCert(
certificate,
static_cast<void*>(const_cast<char*>(password_)));
if (key == NULL) {
CERT_DestroyCertificate(certificate);
if (PR_GetError() == -8177) {

View file

@ -46,8 +46,6 @@ class SSLFilter {
kFirstEncrypted = kReadEncrypted
};
static dart::Mutex* mutex; // To protect library initialization.
SSLFilter()
: callback_error(NULL),
string_start_(NULL),
@ -89,17 +87,15 @@ class SSLFilter {
static void InitializeLibrary(const char* certificate_database,
const char* password,
bool use_builtin_root_certificates,
bool read_only,
bool report_duplicate_initialization = true);
static Dart_Port GetServicePort();
Dart_Handle callback_error;
static char* GetPassword() { return password_; }
private:
static const int kMemioBufferSize = 20 * KB;
static bool library_initialized_;
static char* password_;
static const char* password_;
static dart::Mutex* mutex_; // To protect library initialization.
static NativeService filter_service_;
uint8_t* buffers_[kNumBuffers];
@ -119,6 +115,7 @@ class SSLFilter {
return static_cast<BufferIndex>(i) >= kFirstEncrypted;
}
void InitializeBuffers(Dart_Handle dart_this);
void InitializePlatformData();
DISALLOW_COPY_AND_ASSIGN(SSLFilter);
};

View file

@ -8,27 +8,8 @@ patch class SecureSocket {
/* patch */ static void initialize({String database,
String password,
bool useBuiltinRoots: true,
bool readOnly: true})
native "SecureSocket_InitializeLibrary";
/* patch */ static X509Certificate addCertificate(List<int> certificate,
String trust)
native "SecureSocket_AddCertificate";
/* patch */ static importCertificatesWithPrivateKeys(List<int> certificates,
String password)
native "SecureSocket_ImportCertificatesWithPrivateKeys";
/* patch */ static X509Certificate changeTrust(String nickname,
String trust)
native "SecureSocket_ChangeTrust";
/* patch */ static X509Certificate getCertificate(String nickname)
native "SecureSocket_GetCertificate";
/* patch */ static removeCertificate(String nickname)
native "SecureSocket_RemoveCertificate";
bool useBuiltinRoots: true})
native "SecureSocket_InitializeLibrary";
}

View file

@ -289,33 +289,9 @@ patch class SecureSocket {
patch static void initialize({String database,
String password,
bool useBuiltinRoots: true,
bool readOnly: true}) {
bool useBuiltinRoots: true}) {
throw new UnsupportedError("SecureSocket.initialize");
}
patch static X509Certificate addCertificate(List<int> certificate,
String trust) {
throw new UnsupportedError("SecureSocket.addCertificate");
}
patch static importCertificatesWithPrivateKeys(List<int> certificates,
String password) {
throw new UnsupportedError(
"SecureSocket.importCertificatesWithPrivateKeys");
}
patch static X509Certificate getCertificate(String nickname) {
throw new UnsupportedError("SecureSocket.getCertificate");
}
patch static removeCertificate(String nickname) {
throw new UnsupportedError("SecureSocket.removeCertificate");
}
patch static X509Certificate changeTrust(String nickname, String trust) {
throw new UnsupportedError("SecureSocket.changeTrust");
}
}
patch class _SecureFilter {

View file

@ -204,117 +204,7 @@ abstract class SecureSocket implements Socket {
*/
external static void initialize({String database,
String password,
bool useBuiltinRoots: true,
bool readOnly: true});
/**
* Trust strings for use in [addCertificate] and [changeTrust].
*/
static const String TRUST_ISSUE_SERVER_CERTIFICATES = 'C,,';
static const String TRUST_ISSUE_CLIENT_CERTIFICATES = 'T,,';
static const String TRUST_ISSUE_CLIENT_SERVER_CERTIFICATES = 'TC,,';
static const String TRUST_CERTIFICATE = 'P,,';
/**
* Adds a X509 certificate (for SSL and TLS secure networking) to the
* in-memory certificate cache. Returns an X509Certificate object
* with information about the added certificate.
*
* The in-memory certificate cache is different from the certificate
* database opened by `SecureSocket.initialize`, and certificates added
* by [addCertificate] cannot be modified or removed by [changeTrust]
* or [removeCertificate]. However, if the certificate is already in the
* database, then [removeCertificate] will remove it from both the database
* and the in-memory cache.
*
* [certificate] must be a list of bytes encoding a certificate in
* PEM format: a base64 encoded DER certificate, enclosed between
* "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----".
*
* [trust] is a string specifying the allowed uses of this certificate.
* For example, 'TC,,' specifies that the certificate is for a certificate
* authority that is trusted to issue server and client certificates, so
* that a server or client certificate signed by this authority will be
* accepted.
*
* See the documentation of NSS certutil at
* http://developer.mozilla.org/en-US/docs/NSS_reference/NSS_tools_:_certutil
* or
* http://blogs.oracle.com/meena/entry/notes_about_trust_flags
* for more information about trust attributes.
*/
external static X509Certificate addCertificate(List<int> certificate,
String trust);
/**
* Adds a X509 certificates (for SSL and TLS secure networking) with
* their private keys to the certificate database. SecureSocket.initialize
* must have been called with the path to a certificate database, and with
* readOnly set to `false`.
*
* [certificates] must be a list containing the bytes of a PKCS #12 encoded
* list of certificates and private keys. These are commonly called
* `.pfx` or `.p12` files. Only PKCS #12 files using
* 3-key triple-DES and 40 bit RC2 encryption are accepted.
*
* All certificates are imported with no default trust, and the appropriate
* uses of each certificate must be added with `SecureSocket.changeTrust`.
*
* See the documentation of NSS certutil at
* http://developer.mozilla.org/en-US/docs/NSS_reference/NSS_tools_:_certutil
* or
* http://blogs.oracle.com/meena/entry/notes_about_trust_flags
* for more information about trust attributes.
*
* Returns a CertificateError if it fails. The error code -8183 does not
* indicate that the PKCS #12 file is corrupt. It also is returned if
* the certificate database is read-only, or is the default internal database,
* or if the password for the file or database is incorrect.
*/
external static importCertificatesWithPrivateKeys(List<int> certificates,
String password);
/**
* Changes the trust settings for the certificate with nickname [nickname].
* This certificate must exist in the certificate database.
* SecureSocket.initialize must have been called with the path to a
* certificate database, and with readOnly set to false.
*
* [trust] is a string specifying the allowed uses of this certificate.
* For example, 'TC,,' specifies that the certificate is for a certificate
* authority that is trusted to issue server and client certificates, so
* that a server or client certificate signed by this authority will be
* accepted.
*
* See the documentation of NSS certutil at
* http://developer.mozilla.org/en-US/docs/NSS_reference/NSS_tools_:_certutil
* or
* http://blogs.oracle.com/meena/entry/notes_about_trust_flags
* for more information about trust attributes.
*/
external static X509Certificate changeTrust(String nickname,
String trust);
/**
* Gets the certificate with nickname [nickname] from
* the certificate database. Returns an X509Certificate object with
* information about the certificate.
*
* Throws a CertificateException if it cannot find the certificate with
* the given nickname.
*/
external static X509Certificate getCertificate(String nickname);
/**
* Removes the certificate with nickname [nickname] permanently from
* the certificate database.
* This certificate must exist in the certificate database.
* SecureSocket.initialize must have been called with the path to a
* certificate database, and with readOnly set to false.
*
* Returns null if it cannot find the certificate with that nickname.
*/
external static removeCertificate(String nickname);
bool useBuiltinRoots: true});
}
@ -522,8 +412,7 @@ class _RawSecureSocket extends Stream<RawSocketEvent>
static final int NUM_BUFFERS = 4;
// Is a buffer identifier for an encrypted buffer?
static bool _isBufferEncrypted(int identifier) =>
identifier >= READ_ENCRYPTED;
static bool _isBufferEncrypted(int identifier) => identifier >= READ_ENCRYPTED;
RawSocket _socket;
final Completer<_RawSecureSocket> _handshakeComplete =

View file

@ -1,38 +0,0 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// This test verifies that a server certificate can be verified by a client
// that loads the certificate authority certificate it depends on at runtime.
import "package:path/path.dart";
import "dart:io";
import "dart:async";
String scriptDir = dirname(new Options().script);
void main() {
SecureSocket.initialize(database: join(scriptDir, 'pkcert'),
password: 'dartdart');
runServer().then((SecureServerSocket server) {
return Process.run(new Options().executable,
['--checked',
join(scriptDir, 'certificate_test_client.dart'),
server.port.toString(),
join(scriptDir, 'pkcert', 'myauthority.pem')]);
}).then((ProcessResult result) {
if (result.exitCode != 0 || !result.stdout.contains("SUCCESS")) {
print("Client failed with exit code ${result.exitCode}");
print(" stdout (expects \"SUCCESS\\n\"):");
print(result.stdout);
print(" stderr:");
print(result.stderr);
throw new AssertionError();
}
});
}
Future<SecureServerSocket> runServer() =>
SecureServerSocket.bind("localhost", 0, "localhost_cert")
.then((server) => server..listen(
(socket) => socket.pipe(socket).then((_) => server.close())));

View file

@ -1,65 +0,0 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// Client that tests that a certificate authority certificate loaded
// at runtime can be used to verify a certificate chain. The server it
// connects to uses localhost_cert, signed by myauthority_cert, to connect
// securely.
import 'dart:io';
void main() {
int port = int.parse(new Options().arguments[0]);
String certificate = new Options().arguments[1];
SecureSocket.initialize();
var mycert = new File(certificate).readAsBytesSync();
bool threw = false;
try {
SecureSocket.addCertificate("I am not a cert".codeUnits,
SecureSocket.TRUST_ISSUE_SERVER_CERTIFICATES);
} on CertificateException catch (e) {
threw = true;
}
if (!threw) throw "Expected bad certificate to throw";
threw = false;
try {
SecureSocket.addCertificate(mycert, "Trust me, I'm a string");
} on CertificateException catch (e) {
threw = true;
}
if (!threw) throw "Expected bad trust string to throw";
SecureSocket.addCertificate(mycert,
SecureSocket.TRUST_ISSUE_SERVER_CERTIFICATES);
SecureSocket.connect('localhost', port).then((SecureSocket socket) {
socket.writeln('hello world');
socket.listen((data) { });
return socket.close();
}).then((_) {
SecureSocket.changeTrust('myauthority_cert', ',,');
return SecureSocket.connect('localhost', port);
}).then((_) {
throw "Expected untrusted authority to stop connection";
}, onError: (e) {
if (e is! CertificateException) throw e;
}).then((_) {
SecureSocket.changeTrust('myauthority_cert', 'C,,');
return SecureSocket.connect('localhost', port);
}).then((SecureSocket socket) {
socket.writeln('hello world');
socket.listen((data) { });
return socket.close();
}).then((_) {
SecureSocket.removeCertificate('myauthority_cert');
return SecureSocket.connect('localhost', port);
}).then((_) {
throw "Expected untrusted root to stop connection";
}, onError: (e) {
if (e is! CertificateException) throw e;
}).then((_) {
print('SUCCESS'); // Checked by parent process.
});
}

View file

@ -1,42 +0,0 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// Client that tests that a certificate authority certificate loaded
// at runtime can be used to verify a certificate chain. The server it
// connects to uses localhost_cert, signed by myauthority_cert, to connect
// securely. This client tests that addCertificate works if a certificate
// database has been specified.
import 'dart:io';
void main() {
int port = int.parse(new Options().arguments[0]);
String certificate = new Options().arguments[1];
String database = new Options().arguments[2];
SecureSocket.initialize(database: database,
password: 'dartdart',
readOnly: false);
SecureSocket.removeCertificate('localhost_cert');
SecureSocket.removeCertificate('myauthority_cert');
var mycert = new File(certificate).readAsBytesSync();
SecureSocket.addCertificate(mycert,
SecureSocket.TRUST_ISSUE_SERVER_CERTIFICATES);
if (null != SecureSocket.getCertificate('myauthority_cert')) {
throw "Expected getCertificate to return null";
}
SecureSocket.connect('localhost', port).then((SecureSocket socket) {
socket.writeln('hello world');
socket.listen((data) { });
return socket.close();
}).then((_) {
// The certificate is only in the in-memory cache, so cannot be removed.
try {
SecureSocket.removeCertificate('myauthority_cert');
} catch (e) {
if (e is! CertificateException) throw "error $e";
}
}).then((_) {
print('SUCCESS'); // Checked by parent process.
});
}

View file

@ -1,12 +0,0 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import "dart:io";
import "dart:async";
main() {
new Timer(new Duration(seconds: 2), () {
new Directory(new Options().arguments[0]).delete(recursive: true);
});
}

View file

@ -1,11 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIBpDCCAQ2gAwIBAgIFAJq4IS0wDQYJKoZIhvcNAQEFBQAwFjEUMBIGA1UEAxML
bXlhdXRob3JpdHkwHhcNMTMwMjE1MTA0MzA5WhcNMTgwMjE1MTA0MzA5WjAWMRQw
EgYDVQQDEwtteWF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
tnrkyrXF1SEUeOdIiULWs0dOEUlX6t73UDVbbTorF6R66fkjkEK3vW9ekZFUWq5+
HVku4LUViJR140+F+CzUYtN73Ur28GqLa6LY4XtzHfPSfgecgayI1mEU+0f/2l8B
4RiE9V8mW9RqPM6Lb69QrwXSYdzStl6ltuLJhgPGqAMCAwEAATANBgkqhkiG9w0B
AQUFAAOBgQBdBUQTUR5oIRdqBGR87qW7caLAuPoVmzikOrSBNoyamVF0lwFFxgNw
sj5VWdMn0SJhXd3EUMVlHr+4B/c3jUy1PlvBQGURn2cp5c4tj3FMOqkemuA0ywOF
gbt2lqi7/RW4bHITqfPi7CDzE36n25vXc64Ylk7vEi3hUfjYfIqNcA==
-----END CERTIFICATE-----

View file

@ -1,116 +0,0 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// This test verifies the SecureSocket functions addCertificate,
// importCertificatesWithPrivateKeys, changeTrust, getCertificate, and
// removeCertificate.
// It loads a copy of the test certificate database,
// removes all certificates and keys, then imports the certificates and keys
// again. Then it runs a secure server, using the user certificate (a
// certificate with private key), and starts client processes that use
// addCertificate to trust the certificate that signed the server's certificate.
// The clients then test that they can successfully connect to the server.
import "package:expect/expect.dart";
import "package:path/path.dart";
import "dart:io";
import "dart:async";
void main() {
Directory tempDirectory = new Directory('').createTempSync();
String scriptDirectory = dirname(Platform.script);
String database = join(scriptDirectory, 'pkcert');
String serverDatabase = join(tempDirectory.path, 'server');
String clientDatabase = join(tempDirectory.path, 'client');
new Directory(serverDatabase).createSync();
new Directory(clientDatabase).createSync();
cleanUp() {
if (Platform.isWindows) {
// Delay directory deletion until after this script exits.
// The certificate database files are locked until then.
Process.start('start', // Starts a detatched process.
[Platform.executable,
join(scriptDirectory, 'delete_a_directory_later.dart'),
tempDirectory.path],
runInShell: true);
} else {
tempDirectory.delete(recursive: true);
}
}
Future.wait([
copyFileToDirectory(join(database, 'cert9.db'), serverDatabase),
copyFileToDirectory(join(database, 'key4.db'), serverDatabase),
copyFileToDirectory(join(database, 'cert9.db'), clientDatabase),
copyFileToDirectory(join(database, 'key4.db'), clientDatabase),
]).then((_) {
SecureSocket.initialize(database: serverDatabase,
password: 'dartdart',
readOnly: false);
for (var nickname in ['localhost_cert', 'myauthority_cert']) {
Expect.isNotNull(SecureSocket.getCertificate(nickname));
SecureSocket.removeCertificate(nickname);
Expect.isNull(SecureSocket.getCertificate(nickname));
}
var mycerts = new File(join(database, 'localhost.p12')).readAsBytesSync();
SecureSocket.importCertificatesWithPrivateKeys(mycerts, 'dartdart');
checkCertificate('localhost_cert', 'CN=localhost', 'CN=myauthority');
checkCertificate('myauthority_cert', 'CN=myauthority', 'CN=myauthority');
SecureSocket.removeCertificate('myauthority_cert');
return runServer().then((server) {
var tests = ['certificate_test_client.dart',
'certificate_test_client_database.dart'];
return Future.wait(tests.map((test) =>
Process.run(Platform.executable,
['--checked',
join(scriptDirectory, test),
server.port.toString(),
join(database, 'myauthority.pem'),
clientDatabase])))
.then(verifyResults)
.whenComplete(server.close);
});
})
.whenComplete(cleanUp);
}
checkCertificate(nickname, subject, issuer) {
var cert = SecureSocket.getCertificate(nickname);
Expect.isTrue(cert is X509Certificate);
Expect.equals(subject, cert.subject);
Expect.equals(issuer, cert.issuer);
}
Future<SecureServerSocket> runServer() =>
SecureServerSocket.bind("localhost", 0, "localhost_cert")
.then((server) => server..listen((socket) => socket.pipe(socket)));
verifyResults(results) => results.map(verifyResult);
verifyResult(ProcessResult result) {
if (result.exitCode != 0 || !result.stdout.contains('SUCCESS')) {
print("Client failed with exit code ${result.exitCode}");
print(" stdout (expected \"SUCCESS\\n\"):");
print(result.stdout);
print(" stderr:");
print(result.stderr);
Expect.fail("Client failed");
}
}
Future copyFileToDirectory(String file, String directory) {
switch (Platform.operatingSystem) {
case 'linux':
case 'macos':
return Process.run('cp', [file, directory]);
case 'windows':
return Process.run('cmd.exe', ['/C', 'copy $file $directory']);
default:
Expect.fail('Unknown operating system ${Platform.operatingSystem}');
}
}