summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/tests/unit/test_cert_dbKey.js
diff options
context:
space:
mode:
Diffstat (limited to 'security/manager/ssl/tests/unit/test_cert_dbKey.js')
-rw-r--r--security/manager/ssl/tests/unit/test_cert_dbKey.js225
1 files changed, 225 insertions, 0 deletions
diff --git a/security/manager/ssl/tests/unit/test_cert_dbKey.js b/security/manager/ssl/tests/unit/test_cert_dbKey.js
new file mode 100644
index 0000000000..3ff36f905c
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_dbKey.js
@@ -0,0 +1,225 @@
+// -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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";
+
+// This test tests that the nsIX509Cert.dbKey and nsIX509CertDB.findCertByDBKey
+// APIs work as expected. That is, getting a certificate's dbKey and using it
+// in findCertByDBKey should return the same certificate. Also, for backwards
+// compatibility, findCertByDBKey should ignore any whitespace in its input
+// (even though now nsIX509Cert.dbKey will never have whitespace in it).
+
+function hexStringToBytes(hex) {
+ let bytes = [];
+ for (let hexByteStr of hex.split(":")) {
+ bytes.push(parseInt(hexByteStr, 16));
+ }
+ return bytes;
+}
+
+function encodeCommonNameAsBytes(commonName) {
+ // The encoding will look something like this (in hex):
+ // 30 (SEQUENCE) <length of contents>
+ // 31 (SET) <length of contents>
+ // 30 (SEQUENCE) <length of contents>
+ // 06 (OID) 03 (length)
+ // 55 04 03 (id-at-commonName)
+ // 0C (UTF8String) <length of common name>
+ // <common name bytes>
+ // To make things simple, it would be nice to have the length of each
+ // component be less than 128 bytes (so we can have single-byte lengths).
+ // For this to hold, the maximum length of the contents of the outermost
+ // SEQUENCE must be 127. Everything not in the contents of the common name
+ // will take up 11 bytes, so the value of the common name itself can be at
+ // most 116 bytes.
+ ok(
+ commonName.length <= 116,
+ "test assumption: common name can't be longer than 116 bytes (makes " +
+ "DER encoding easier)"
+ );
+ let commonNameOIDBytes = [0x06, 0x03, 0x55, 0x04, 0x03];
+ let commonNameBytes = [0x0c, commonName.length];
+ for (let i = 0; i < commonName.length; i++) {
+ commonNameBytes.push(commonName.charCodeAt(i));
+ }
+ let bytes = commonNameOIDBytes.concat(commonNameBytes);
+ bytes.unshift(bytes.length);
+ bytes.unshift(0x30); // SEQUENCE
+ bytes.unshift(bytes.length);
+ bytes.unshift(0x31); // SET
+ bytes.unshift(bytes.length);
+ bytes.unshift(0x30); // SEQUENCE
+ return bytes;
+}
+
+function testInvalidDBKey(certDB, dbKey) {
+ throws(
+ () => certDB.findCertByDBKey(dbKey),
+ /NS_ERROR_ILLEGAL_INPUT/,
+ `findCertByDBKey(${dbKey}) should raise NS_ERROR_ILLEGAL_INPUT`
+ );
+}
+
+function testDBKeyForNonexistentCert(certDB, dbKey) {
+ let cert = certDB.findCertByDBKey(dbKey);
+ ok(!cert, "shouldn't find cert for given dbKey");
+}
+
+function byteArrayToByteString(bytes) {
+ let byteString = "";
+ for (let b of bytes) {
+ byteString += String.fromCharCode(b);
+ }
+ return byteString;
+}
+
+function run_test() {
+ do_get_profile();
+ let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
+ Ci.nsIX509CertDB
+ );
+ let cert = constructCertFromFile("bad_certs/test-ca.pem");
+ equal(
+ cert.issuerName,
+ "CN=" + cert.issuerCommonName,
+ "test assumption: this certificate's issuer distinguished name " +
+ "consists only of a common name"
+ );
+ let issuerBytes = encodeCommonNameAsBytes(cert.issuerCommonName);
+ ok(
+ issuerBytes.length < 256,
+ "test assumption: length of encoded issuer is less than 256 bytes"
+ );
+ let serialNumberBytes = hexStringToBytes(cert.serialNumber);
+ ok(
+ serialNumberBytes.length < 256,
+ "test assumption: length of encoded serial number is less than 256 bytes"
+ );
+ let dbKeyHeader = [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ serialNumberBytes.length,
+ 0,
+ 0,
+ 0,
+ issuerBytes.length,
+ ];
+ let expectedDbKeyBytes = dbKeyHeader.concat(serialNumberBytes, issuerBytes);
+ let expectedDbKey = btoa(byteArrayToByteString(expectedDbKeyBytes));
+ equal(
+ cert.dbKey,
+ expectedDbKey,
+ "actual and expected dbKey values should match"
+ );
+
+ let certFromDbKey = certDB.findCertByDBKey(expectedDbKey);
+ ok(
+ areCertsEqual(certFromDbKey, cert),
+ "nsIX509CertDB.findCertByDBKey should find the right certificate"
+ );
+
+ ok(
+ expectedDbKey.length > 64,
+ "test assumption: dbKey should be longer than 64 characters"
+ );
+ let expectedDbKeyWithCRLF = expectedDbKey.replace(/(.{64})/, "$1\r\n");
+ ok(
+ expectedDbKeyWithCRLF.indexOf("\r\n") == 64,
+ "test self-check: adding CRLF to dbKey should succeed"
+ );
+ certFromDbKey = certDB.findCertByDBKey(expectedDbKeyWithCRLF);
+ ok(
+ areCertsEqual(certFromDbKey, cert),
+ "nsIX509CertDB.findCertByDBKey should work with dbKey with CRLF"
+ );
+
+ let expectedDbKeyWithSpaces = expectedDbKey.replace(/(.{64})/, "$1 ");
+ ok(
+ expectedDbKeyWithSpaces.indexOf(" ") == 64,
+ "test self-check: adding spaces to dbKey should succeed"
+ );
+ certFromDbKey = certDB.findCertByDBKey(expectedDbKeyWithSpaces);
+ ok(
+ areCertsEqual(certFromDbKey, cert),
+ "nsIX509CertDB.findCertByDBKey should work with dbKey with spaces"
+ );
+
+ // Test some invalid dbKey values.
+ testInvalidDBKey(certDB, "AAAA"); // Not long enough.
+ // No header.
+ testInvalidDBKey(
+ certDB,
+ btoa(
+ byteArrayToByteString(
+ [0, 0, 0, serialNumberBytes.length, 0, 0, 0, issuerBytes.length].concat(
+ serialNumberBytes,
+ issuerBytes
+ )
+ )
+ )
+ );
+ testInvalidDBKey(
+ certDB,
+ btoa(
+ byteArrayToByteString([
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 255,
+ 255,
+ 255,
+ 255, // serial number length is way too long
+ 255,
+ 255,
+ 255,
+ 255, // issuer length is way too long
+ 0,
+ 0,
+ 0,
+ 0,
+ ])
+ )
+ );
+ // Truncated issuer.
+ testInvalidDBKey(
+ certDB,
+ btoa(
+ byteArrayToByteString([
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 10, 1, 1, 2, 3,
+ ])
+ )
+ );
+ // Issuer doesn't decode to valid common name.
+ testDBKeyForNonexistentCert(
+ certDB,
+ btoa(
+ byteArrayToByteString([
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 1, 1, 2, 3,
+ ])
+ )
+ );
+
+ // zero-length serial number and issuer -> no such certificate
+ testDBKeyForNonexistentCert(
+ certDB,
+ btoa(
+ byteArrayToByteString([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
+ )
+ );
+}