dart:io | Change the way SecureSocket initializes the NSS library with an empty database.
BUG=dartbug.com/7104
Review URL: https://codereview.chromium.org//13985012
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@21363 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index 0f9140b..e66ff35 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -17,6 +17,7 @@
#include <prerror.h>
#include <prinit.h>
#include <prnetdb.h>
+#include <secmod.h>
#include <ssl.h>
#include <sslproto.h>
@@ -333,36 +334,57 @@
bad_certificate_callback_ = ThrowIfError(Dart_NewPersistentHandle(callback));
}
+static const char* builtin_roots_module =
+#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID)
+ "name=\"Root Certs\" library=\"libnssckbi.so\"";
+#elif defined(TARGET_OS_MACOS)
+ "name=\"Root Certs\" library=\"libnssckbi.dylib\"";
+#elif defined(TARGET_OS_WINDOWS)
+ "name=\"Root Certs\" library=\"nssckbi.dll\"";
+#else
+#error Automatic target os detection failed.
+#endif
+
+
void SSLFilter::InitializeLibrary(const char* certificate_database,
const char* password,
bool use_builtin_root_certificates,
bool report_duplicate_initialization) {
MutexLocker locker(&mutex_);
+ SECStatus status;
if (!library_initialized_) {
password_ = strdup(password); // This one copy persists until Dart exits.
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
// TODO(whesse): Verify there are no UTF-8 issues here.
- PRUint32 init_flags = NSS_INIT_READONLY;
- if (certificate_database == NULL) {
- // Passing the empty string as the database path does not try to open
- // a database in the current directory.
- certificate_database = "";
- // The flag NSS_INIT_NOCERTDB is documented to do what we want here,
- // however it causes the builtins not to be available on Windows.
- init_flags |= NSS_INIT_FORCEOPEN;
- }
- if (!use_builtin_root_certificates) {
- init_flags |= NSS_INIT_NOMODDB;
- }
- SECStatus status = NSS_Initialize(certificate_database,
- "",
- "",
- SECMOD_DB,
- init_flags);
- if (status != SECSuccess) {
- mutex_.Unlock(); // MutexLocker destructor not called when throwing.
- ThrowPRException("Failed NSS_Init call.");
+ if (certificate_database == NULL || certificate_database[0] == '\0') {
+ status = NSS_NoDB_Init(NULL);
+ if (status != SECSuccess) {
+ mutex_.Unlock(); // MutexLocker destructor not called when throwing.
+ ThrowPRException("Failed NSS_NoDB_Init call.");
+ }
+ if (use_builtin_root_certificates) {
+ SECMODModule* module = SECMOD_LoadUserModule(
+ const_cast<char*>(builtin_roots_module), NULL, PR_FALSE);
+ if (!module) {
+ mutex_.Unlock(); // MutexLocker destructor not called when throwing.
+ ThrowPRException("Failed to load builtin root certificates.");
+ }
+ }
+ } else {
+ PRUint32 init_flags = NSS_INIT_READONLY;
+ if (!use_builtin_root_certificates) {
+ init_flags |= NSS_INIT_NOMODDB;
+ }
+ status = NSS_Initialize(certificate_database,
+ "",
+ "",
+ SECMOD_DB,
+ init_flags);
+ if (status != SECSuccess) {
+ mutex_.Unlock(); // MutexLocker destructor not called when throwing.
+ ThrowPRException("Failed NSS_Init call.");
+ }
}
library_initialized_ = true;
diff --git a/tests/standalone/io/secure_no_builtin_roots_database_test.dart b/tests/standalone/io/secure_no_builtin_roots_database_test.dart
new file mode 100644
index 0000000..078ba70
--- /dev/null
+++ b/tests/standalone/io/secure_no_builtin_roots_database_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2012, 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 "package:expect/expect.dart";
+import "dart:io";
+import "dart:uri";
+import "dart:isolate";
+import "dart:async";
+
+void testGoogleUrl() {
+ ReceivePort keepAlive = new ReceivePort();
+ HttpClient client = new HttpClient();
+ client.getUrl(Uri.parse('https://www.google.com'))
+ .then((request) => request.close())
+ .then((response) => Expect.fail("Unexpected successful connection"))
+ .catchError((error) {
+ Expect.isTrue(error is AsyncError);
+ Expect.isTrue(error.error is SocketIOException);
+ keepAlive.close();
+ client.close();
+ });
+}
+
+void InitializeSSL() {
+ // If the built-in root certificates aren't loaded, the connection
+ // should signal an error. Even when an external database is loaded,
+ // they should not be loaded.
+ Path scriptDir = new Path(new Options().script).directoryPath;
+ Path certificateDatabase = scriptDir.append('pkcert');
+ SecureSocket.initialize(database: certificateDatabase.toNativePath(),
+ password: 'dartdart',
+ useBuiltinRoots: false);
+}
+
+void main() {
+ InitializeSSL();
+ testGoogleUrl();
+}