diff options
Diffstat (limited to '')
-rw-r--r-- | security/manager/ssl/tests/unit/test_cert_dbKey.js | 225 |
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]) + ) + ); +} |