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 }