tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_cert_dbKey.js (6453B)


      1 // -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 // This Source Code Form is subject to the terms of the Mozilla Public
      3 // License, v. 2.0. If a copy of the MPL was not distributed with this
      4 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
      5 
      6 "use strict";
      7 
      8 // This test tests that the nsIX509Cert.dbKey and nsIX509CertDB.findCertByDBKey
      9 // APIs work as expected. That is, getting a certificate's dbKey and using it
     10 // in findCertByDBKey should return the same certificate. Also, for backwards
     11 // compatibility, findCertByDBKey should ignore any whitespace in its input
     12 // (even though now nsIX509Cert.dbKey will never have whitespace in it).
     13 
     14 function hexStringToBytes(hex) {
     15  let bytes = [];
     16  for (let hexByteStr of hex.split(":")) {
     17    bytes.push(parseInt(hexByteStr, 16));
     18  }
     19  return bytes;
     20 }
     21 
     22 function encodeCommonNameAsBytes(commonName) {
     23  // The encoding will look something like this (in hex):
     24  // 30 (SEQUENCE) <length of contents>
     25  //    31 (SET) <length of contents>
     26  //       30 (SEQUENCE) <length of contents>
     27  //          06 (OID) 03 (length)
     28  //             55 04 03 (id-at-commonName)
     29  //          0C (UTF8String) <length of common name>
     30  //             <common name bytes>
     31  // To make things simple, it would be nice to have the length of each
     32  // component be less than 128 bytes (so we can have single-byte lengths).
     33  // For this to hold, the maximum length of the contents of the outermost
     34  // SEQUENCE must be 127. Everything not in the contents of the common name
     35  // will take up 11 bytes, so the value of the common name itself can be at
     36  // most 116 bytes.
     37  Assert.lessOrEqual(
     38    commonName.length,
     39    116,
     40    "test assumption: common name can't be longer than 116 bytes (makes " +
     41      "DER encoding easier)"
     42  );
     43  let commonNameOIDBytes = [0x06, 0x03, 0x55, 0x04, 0x03];
     44  let commonNameBytes = [0x0c, commonName.length];
     45  for (let i = 0; i < commonName.length; i++) {
     46    commonNameBytes.push(commonName.charCodeAt(i));
     47  }
     48  let bytes = commonNameOIDBytes.concat(commonNameBytes);
     49  bytes.unshift(bytes.length);
     50  bytes.unshift(0x30); // SEQUENCE
     51  bytes.unshift(bytes.length);
     52  bytes.unshift(0x31); // SET
     53  bytes.unshift(bytes.length);
     54  bytes.unshift(0x30); // SEQUENCE
     55  return bytes;
     56 }
     57 
     58 function testInvalidDBKey(certDB, dbKey) {
     59  throws(
     60    () => certDB.findCertByDBKey(dbKey),
     61    /NS_ERROR_ILLEGAL_INPUT/,
     62    `findCertByDBKey(${dbKey}) should raise NS_ERROR_ILLEGAL_INPUT`
     63  );
     64 }
     65 
     66 function testDBKeyForNonexistentCert(certDB, dbKey) {
     67  let cert = certDB.findCertByDBKey(dbKey);
     68  ok(!cert, "shouldn't find cert for given dbKey");
     69 }
     70 
     71 function byteArrayToByteString(bytes) {
     72  let byteString = "";
     73  for (let b of bytes) {
     74    byteString += String.fromCharCode(b);
     75  }
     76  return byteString;
     77 }
     78 
     79 function run_test() {
     80  do_get_profile();
     81  let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
     82    Ci.nsIX509CertDB
     83  );
     84  let cert = constructCertFromFile("bad_certs/test-ca.pem");
     85  equal(
     86    cert.issuerName,
     87    "CN=" + cert.issuerCommonName,
     88    "test assumption: this certificate's issuer distinguished name " +
     89      "consists only of a common name"
     90  );
     91  let issuerBytes = encodeCommonNameAsBytes(cert.issuerCommonName);
     92  Assert.less(
     93    issuerBytes.length,
     94    256,
     95    "test assumption: length of encoded issuer is less than 256 bytes"
     96  );
     97  let serialNumberBytes = hexStringToBytes(cert.serialNumber);
     98  Assert.less(
     99    serialNumberBytes.length,
    100    256,
    101    "test assumption: length of encoded serial number is less than 256 bytes"
    102  );
    103  let dbKeyHeader = [
    104    0,
    105    0,
    106    0,
    107    0,
    108    0,
    109    0,
    110    0,
    111    0,
    112    0,
    113    0,
    114    0,
    115    serialNumberBytes.length,
    116    0,
    117    0,
    118    0,
    119    issuerBytes.length,
    120  ];
    121  let expectedDbKeyBytes = dbKeyHeader.concat(serialNumberBytes, issuerBytes);
    122  let expectedDbKey = btoa(byteArrayToByteString(expectedDbKeyBytes));
    123  equal(
    124    cert.dbKey,
    125    expectedDbKey,
    126    "actual and expected dbKey values should match"
    127  );
    128 
    129  let certFromDbKey = certDB.findCertByDBKey(expectedDbKey);
    130  ok(
    131    areCertsEqual(certFromDbKey, cert),
    132    "nsIX509CertDB.findCertByDBKey should find the right certificate"
    133  );
    134 
    135  Assert.greater(
    136    expectedDbKey.length,
    137    64,
    138    "test assumption: dbKey should be longer than 64 characters"
    139  );
    140  let expectedDbKeyWithCRLF = expectedDbKey.replace(/(.{64})/, "$1\r\n");
    141  Assert.equal(
    142    expectedDbKeyWithCRLF.indexOf("\r\n"),
    143    64,
    144    "test self-check: adding CRLF to dbKey should succeed"
    145  );
    146  certFromDbKey = certDB.findCertByDBKey(expectedDbKeyWithCRLF);
    147  ok(
    148    areCertsEqual(certFromDbKey, cert),
    149    "nsIX509CertDB.findCertByDBKey should work with dbKey with CRLF"
    150  );
    151 
    152  let expectedDbKeyWithSpaces = expectedDbKey.replace(/(.{64})/, "$1  ");
    153  Assert.equal(
    154    expectedDbKeyWithSpaces.indexOf("  "),
    155    64,
    156    "test self-check: adding spaces to dbKey should succeed"
    157  );
    158  certFromDbKey = certDB.findCertByDBKey(expectedDbKeyWithSpaces);
    159  ok(
    160    areCertsEqual(certFromDbKey, cert),
    161    "nsIX509CertDB.findCertByDBKey should work with dbKey with spaces"
    162  );
    163 
    164  // Test some invalid dbKey values.
    165  testInvalidDBKey(certDB, "AAAA"); // Not long enough.
    166  // No header.
    167  testInvalidDBKey(
    168    certDB,
    169    btoa(
    170      byteArrayToByteString(
    171        [0, 0, 0, serialNumberBytes.length, 0, 0, 0, issuerBytes.length].concat(
    172          serialNumberBytes,
    173          issuerBytes
    174        )
    175      )
    176    )
    177  );
    178  testInvalidDBKey(
    179    certDB,
    180    btoa(
    181      byteArrayToByteString([
    182        0,
    183        0,
    184        0,
    185        0,
    186        0,
    187        0,
    188        0,
    189        0,
    190        255,
    191        255,
    192        255,
    193        255, // serial number length is way too long
    194        255,
    195        255,
    196        255,
    197        255, // issuer length is way too long
    198        0,
    199        0,
    200        0,
    201        0,
    202      ])
    203    )
    204  );
    205  // Truncated issuer.
    206  testInvalidDBKey(
    207    certDB,
    208    btoa(
    209      byteArrayToByteString([
    210        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 10, 1, 1, 2, 3,
    211      ])
    212    )
    213  );
    214  // Issuer doesn't decode to valid common name.
    215  testDBKeyForNonexistentCert(
    216    certDB,
    217    btoa(
    218      byteArrayToByteString([
    219        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 1, 1, 2, 3,
    220      ])
    221    )
    222  );
    223 
    224  // zero-length serial number and issuer -> no such certificate
    225  testDBKeyForNonexistentCert(
    226    certDB,
    227    btoa(
    228      byteArrayToByteString([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
    229    )
    230  );
    231 }