bug 1188100 - fold PSM's test_client_cert.js into necko's test_tls_server.js r=mcmanus

This commit is contained in:
David Keeler 2015-07-29 14:27:54 -07:00
parent 0897b64884
commit 9db6074701
13 changed files with 68 additions and 255 deletions

View File

@ -6,16 +6,6 @@
const { utils: Cu, interfaces: Ci } = Components;
const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
function CertDialogService() {}
CertDialogService.prototype = {
classID: Components.ID("{a70153f2-3590-4317-93e9-73b3e7ffca5d}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICertificateDialogs]),
getPKCS12FilePassword: function() {
return true; // Simulates entering an empty password
}
};
let Prompter = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrompt]),
alert: function() {} // Do nothing when asked to show an alert
@ -32,6 +22,5 @@ WindowWatcherService.prototype = {
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
CertDialogService,
WindowWatcherService
]);

View File

@ -1,4 +1,2 @@
component {a70153f2-3590-4317-93e9-73b3e7ffca5d} cert_dialog.js
contract @mozilla.org/nsCertificateDialogs;1 {a70153f2-3590-4317-93e9-73b3e7ffca5d}
component {01ae923c-81bb-45db-b860-d423b0fc4fe1} cert_dialog.js
contract @mozilla.org/embedcomp/window-watcher;1 {01ae923c-81bb-45db-b860-d423b0fc4fe1}

View File

@ -38,7 +38,7 @@ function getCert() {
return deferred.promise;
}
function startServer(cert) {
function startServer(cert, expectingPeerCert, clientCertificateConfig) {
let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"]
.createInstance(Ci.nsITLSServerSocket);
tlsServer.init(-1, true, -1);
@ -57,8 +57,12 @@ function startServer(cert) {
},
onHandshakeDone: function(socket, status) {
do_print("TLS handshake done");
ok(!!status.peerCert, "Has peer cert");
ok(status.peerCert.equals(cert), "Peer cert matches expected cert");
if (expectingPeerCert) {
ok(!!status.peerCert, "Has peer cert");
ok(status.peerCert.equals(cert), "Peer cert matches expected cert");
} else {
ok(!status.peerCert, "No peer cert (as expected)");
}
equal(status.tlsVersionUsed, Ci.nsITLSClientStatus.TLS_VERSION_1_2,
"Using TLS 1.2");
@ -78,7 +82,7 @@ function startServer(cert) {
tlsServer.setSessionCache(false);
tlsServer.setSessionTickets(false);
tlsServer.setRequestClientCertificate(Ci.nsITLSServerSocket.REQUIRE_ALWAYS);
tlsServer.setRequestClientCertificate(clientCertificateConfig);
tlsServer.asyncListen(listener);
@ -92,7 +96,9 @@ function storeCertOverride(port, cert) {
overrideBits, true);
}
function startClient(port, cert) {
function startClient(port, cert, expectingBadCertAlert) {
let SSL_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE;
let SSL_ERROR_BAD_CERT_ALERT = SSL_ERROR_BASE + 17;
let transport =
socketTransportService.createTransport(["ssl"], 1, "127.0.0.1", port, null);
let input;
@ -117,22 +123,23 @@ function startClient(port, cert) {
output.close();
inputDeferred.resolve();
} catch (e) {
let SEC_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE;
let SEC_ERROR_UNKNOWN_ISSUER = SEC_ERROR_BASE + 13;
let errorCode = -1 * (e.result & 0xFFFF);
if (errorCode == SEC_ERROR_UNKNOWN_ISSUER) {
do_print("Client doesn't like server cert");
if (expectingBadCertAlert && errorCode == SSL_ERROR_BAD_CERT_ALERT) {
inputDeferred.resolve();
} else {
inputDeferred.reject(e);
}
inputDeferred.reject(e);
}
},
onOutputStreamReady: function(output) {
try {
// Set the cert we want to avoid any cert UI prompts
let clientSecInfo = transport.securityInfo;
let tlsControl = clientSecInfo.QueryInterface(Ci.nsISSLSocketControl);
tlsControl.clientCert = cert;
// Set the client certificate as appropriate.
if (cert) {
let clientSecInfo = transport.securityInfo;
let tlsControl = clientSecInfo.QueryInterface(Ci.nsISSLSocketControl);
tlsControl.clientCert = cert;
}
output.write("HELLO", 5);
do_print("Output to server written");
@ -140,8 +147,6 @@ function startClient(port, cert) {
input = transport.openInputStream(0, 0, 0);
input.asyncWait(handler, 0, 0, Services.tm.currentThread);
} catch (e) {
let SSL_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE;
let SSL_ERROR_BAD_CERT_ALERT = SSL_ERROR_BASE + 17;
let errorCode = -1 * (e.result & 0xFFFF);
if (errorCode == SSL_ERROR_BAD_CERT_ALERT) {
do_print("Server doesn't like client cert");
@ -158,10 +163,53 @@ function startClient(port, cert) {
return promise.all([inputDeferred.promise, outputDeferred.promise]);
}
// Replace the UI dialog that prompts the user to pick a client certificate.
do_load_manifest("client_cert_chooser.manifest");
add_task(function*() {
let cert = yield getCert();
ok(!!cert, "Got self-signed cert");
let port = startServer(cert);
let port = startServer(cert, true, Ci.nsITLSServerSocket.REQUIRE_ALWAYS);
storeCertOverride(port, cert);
yield startClient(port, cert);
yield startClient(port, cert, false);
});
add_task(function*() {
let cert = yield getCert();
ok(!!cert, "Got self-signed cert");
let port = startServer(cert, true, Ci.nsITLSServerSocket.REQUIRE_ALWAYS);
storeCertOverride(port, cert);
yield startClient(port, null, true);
});
add_task(function*() {
let cert = yield getCert();
ok(!!cert, "Got self-signed cert");
let port = startServer(cert, true, Ci.nsITLSServerSocket.REQUEST_ALWAYS);
storeCertOverride(port, cert);
yield startClient(port, cert, false);
});
add_task(function*() {
let cert = yield getCert();
ok(!!cert, "Got self-signed cert");
let port = startServer(cert, false, Ci.nsITLSServerSocket.REQUEST_ALWAYS);
storeCertOverride(port, cert);
yield startClient(port, null, false);
});
add_task(function*() {
let cert = yield getCert();
ok(!!cert, "Got self-signed cert");
let port = startServer(cert, false, Ci.nsITLSServerSocket.REQUEST_NEVER);
storeCertOverride(port, cert);
yield startClient(port, cert, false);
});
add_task(function*() {
let cert = yield getCert();
ok(!!cert, "Got self-signed cert");
let port = startServer(cert, false, Ci.nsITLSServerSocket.REQUEST_NEVER);
storeCertOverride(port, cert);
yield startClient(port, null, false);
});

View File

@ -4,6 +4,8 @@ tail =
skip-if = toolkit == 'gonk'
support-files =
CA.cert.der
client_cert_chooser.js
client_cert_chooser.manifest
data/image.png
data/system_root.lnk
data/test_psl.txt

View File

@ -1,68 +0,0 @@
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
"use strict";
// Tests specifying a particular client cert to use via the nsISSLSocketControl
// |clientCert| attribute prior to connecting to the server.
function run_test() {
do_get_profile();
// Init key token (to prevent password prompt)
const tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
.getService(Ci.nsIPK11TokenDB);
let keyToken = tokenDB.getInternalKeyToken();
if (keyToken.needsUserInit) {
keyToken.initPassword("");
}
// Replace the UI dialog that would prompt for the following PKCS #12 file's
// password, as well as an alert that appears after it succeeds.
do_load_manifest("test_client_cert/cert_dialog.manifest");
// Load the user cert and look it up in XPCOM format
const certDB = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
let clientCertFile = do_get_file("test_client_cert/client-cert.p12", false);
certDB.importPKCS12File(null, clientCertFile);
// Find the cert by its common name
let clientCert;
let certs = certDB.getCerts().getEnumerator();
while (certs.hasMoreElements()) {
let cert = certs.getNext().QueryInterface(Ci.nsIX509Cert);
if (cert.certType === Ci.nsIX509Cert.USER_CERT &&
cert.commonName === "client-cert") {
clientCert = cert;
break;
}
}
ok(clientCert, "Client cert found");
add_tls_server_setup("ClientAuthServer");
add_connection_test("noclientauth.example.com", PRErrorCodeSuccess);
add_connection_test("requestclientauth.example.com", PRErrorCodeSuccess);
add_connection_test("requestclientauth.example.com", PRErrorCodeSuccess,
null, null, transport => {
do_print("Setting client cert on transport");
let sslSocketControl = transport.securityInfo
.QueryInterface(Ci.nsISSLSocketControl);
sslSocketControl.clientCert = clientCert;
});
add_connection_test("requireclientauth.example.com",
SSL_ERROR_BAD_CERT_ALERT);
add_connection_test("requireclientauth.example.com", PRErrorCodeSuccess,
null, null, transport => {
do_print("Setting client cert on transport");
let sslSocketControl =
transport.securityInfo.QueryInterface(Ci.nsISSLSocketControl);
sslSocketControl.clientCert = clientCert;
});
run_next_test();
}

View File

@ -1,33 +0,0 @@
#!/usr/bin/python
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import tempfile, os, sys, random
libpath = os.path.abspath("../psm_common_py")
sys.path.append(libpath)
import CertUtils
dest_dir = os.getcwd()
db = tempfile.mkdtemp()
serial = random.randint(100, 40000000)
name = "client-cert"
[key, cert] = CertUtils.generate_cert_generic(db, dest_dir, serial, "rsa",
name, "")
CertUtils.generate_pkcs12(db, dest_dir, cert, key, name)
# Print a blank line and the fingerprint of the cert that ClientAuthServer.cpp
# should be modified with.
print
CertUtils.print_cert_info(cert)
print ('You now MUST update the fingerprint in ClientAuthServer.cpp to match ' +
'the fingerprint printed above.')
# Remove unnecessary .der file
os.remove(dest_dir + "/" + name + ".der")

View File

@ -1,116 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 sw=2 tw=80 et: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This is a standalone server for testing client cert authentication.
// The client is expected to connect, initiate an SSL handshake (with SNI
// to indicate which "server" to connect to), and verify the certificate.
// If all is good, the client then sends one encrypted byte and receives that
// same byte back.
// This server also has the ability to "call back" another process waiting on
// it. That is, when the server is all set up and ready to receive connections,
// it will connect to a specified port and issue a simple HTTP request.
#include <stdio.h>
#include "hasht.h"
#include "ScopedNSSTypes.h"
#include "ssl.h"
#include "TLSServer.h"
using namespace mozilla;
using namespace mozilla::test;
struct ClientAuthHost
{
const char *mHostName;
bool mRequestClientAuth;
bool mRequireClientAuth;
};
// Hostname, cert nickname pairs.
static const ClientAuthHost sClientAuthHosts[] =
{
{ "noclientauth.example.com", false, false },
{ "requestclientauth.example.com", true, false },
{ "requireclientauth.example.com", true, true },
{ nullptr, false, false }
};
static const unsigned char sClientCertFingerprint[] =
{
0xD2, 0x2F, 0x00, 0x9A, 0x9E, 0xED, 0x79, 0xDC,
0x8D, 0x17, 0x98, 0x8E, 0xEC, 0x76, 0x05, 0x91,
0xA5, 0xF6, 0xC9, 0xFA, 0x16, 0x8B, 0xD2, 0x5F,
0xE1, 0x52, 0x04, 0x7C, 0xF4, 0x76, 0x42, 0x9D
};
SECStatus
AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig,
PRBool isServer)
{
ScopedCERTCertificate clientCert(SSL_PeerCertificate(fd));
unsigned char certFingerprint[SHA256_LENGTH];
SECStatus rv = PK11_HashBuf(SEC_OID_SHA256, certFingerprint,
clientCert->derCert.data,
clientCert->derCert.len);
if (rv != SECSuccess) {
return rv;
}
static_assert(sizeof(sClientCertFingerprint) == SHA256_LENGTH,
"Ensure fingerprint has corrent length");
bool match = !memcmp(certFingerprint, sClientCertFingerprint,
sizeof(certFingerprint));
return match ? SECSuccess : SECFailure;
}
int32_t
DoSNISocketConfig(PRFileDesc* aFd, const SECItem* aSrvNameArr,
uint32_t aSrvNameArrSize, void* aArg)
{
const ClientAuthHost *host = GetHostForSNI(aSrvNameArr, aSrvNameArrSize,
sClientAuthHosts);
if (!host) {
return SSL_SNI_SEND_ALERT;
}
if (gDebugLevel >= DEBUG_VERBOSE) {
fprintf(stderr, "found pre-defined host '%s'\n", host->mHostName);
}
SECStatus srv = ConfigSecureServerWithNamedCert(aFd, DEFAULT_CERT_NICKNAME,
nullptr, nullptr);
if (srv != SECSuccess) {
return SSL_SNI_SEND_ALERT;
}
SSL_OptionSet(aFd, SSL_REQUEST_CERTIFICATE, host->mRequestClientAuth);
if (host->mRequireClientAuth) {
SSL_OptionSet(aFd, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_ALWAYS);
} else {
SSL_OptionSet(aFd, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER);
}
// Override default client auth hook to just check fingerprint
srv = SSL_AuthCertificateHook(aFd, AuthCertificateHook, nullptr);
if (srv != SECSuccess) {
return SSL_SNI_SEND_ALERT;
}
return 0;
}
int
main(int argc, char* argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s <NSS DB directory>\n", argv[0]);
return 1;
}
return StartServer(argv[1], DoSNISocketConfig, nullptr);
}

View File

@ -8,7 +8,6 @@ FAIL_ON_WARNINGS = True
GeckoSimplePrograms([
'BadCertServer',
'ClientAuthServer',
'GenerateOCSPResponse',
'OCSPStaplingServer',
], linkage=None)

View File

@ -8,7 +8,6 @@ support-files =
tlsserver/**
test_cert_signatures/**
test_certviewer_invalid_oids/**
test_client_cert/**
test_ev_certs/**
test_getchain/**
test_intermediate_basic_usage_constraints/**
@ -134,8 +133,6 @@ skip-if = toolkit == 'gonk' && debug
run-sequentially = hardcoded ports
[test_cert_chains.js]
run-sequentially = hardcoded ports
[test_client_cert.js]
run-sequentially = hardcoded ports
[test_nsCertType.js]
run-sequentially = hardcoded ports
[test_nsIX509Cert_utf8.js]

View File

@ -23,7 +23,6 @@ TEST_HARNESS_BINS := \
certutil$(BIN_SUFFIX) \
pk12util$(BIN_SUFFIX) \
BadCertServer$(BIN_SUFFIX) \
ClientAuthServer$(BIN_SUFFIX) \
OCSPStaplingServer$(BIN_SUFFIX) \
GenerateOCSPResponse$(BIN_SUFFIX) \
fix_stack_using_bpsyms.py \

View File

@ -387,7 +387,6 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
"certutil",
"pk12util",
"BadCertServer",
"ClientAuthServer",
"OCSPStaplingServer",
"GenerateOCSPResponse"]
for fname in binaries:

View File

@ -614,7 +614,6 @@ NO_PKG_FILES += \
certutil* \
pk12util* \
BadCertServer* \
ClientAuthServer* \
OCSPStaplingServer* \
GenerateOCSPResponse* \
chrome/chrome.rdf \