mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 1240173 - improve nsIX509Cert.dbKey r=Cykesiopka
This commit is contained in:
parent
83f1f25714
commit
da78a4c1e5
@ -398,19 +398,10 @@ nsCertOverrideService::RememberValidityOverride(const nsACString& aHostName,
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
char *dbkey = nullptr;
|
||||
rv = aCert->GetDbKey(&dbkey);
|
||||
if (NS_FAILED(rv) || !dbkey)
|
||||
nsAutoCString dbkey;
|
||||
rv = aCert->GetDbKey(dbkey);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
||||
// change \n and \r to spaces in the possibly multi-line-base64-encoded key
|
||||
for (char *dbkey_walk = dbkey;
|
||||
*dbkey_walk;
|
||||
++dbkey_walk) {
|
||||
char c = *dbkey_walk;
|
||||
if (c == '\r' || c == '\n') {
|
||||
*dbkey_walk = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@ -421,11 +412,10 @@ nsCertOverrideService::RememberValidityOverride(const nsACString& aHostName,
|
||||
aTemporary,
|
||||
mDottedOidForStoringNewHashes, fpStr,
|
||||
(nsCertOverride::OverrideBits)aOverrideBits,
|
||||
nsDependentCString(dbkey));
|
||||
dbkey);
|
||||
Write();
|
||||
}
|
||||
|
||||
PR_Free(dbkey);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -553,6 +543,8 @@ nsCertOverrideService::AddEntryToList(const nsACString &aHostName, int32_t aPort
|
||||
settings.mFingerprint = fingerprint;
|
||||
settings.mOverrideBits = ob;
|
||||
settings.mDBKey = dbKey;
|
||||
// remove whitespace from stored dbKey for backwards compatibility
|
||||
settings.mDBKey.StripWhitespace();
|
||||
settings.mCert = aCert;
|
||||
}
|
||||
|
||||
@ -599,51 +591,14 @@ nsCertOverrideService::CountPermanentOverrideTelemetry()
|
||||
}
|
||||
|
||||
static bool
|
||||
matchesDBKey(nsIX509Cert *cert, const char *match_dbkey)
|
||||
matchesDBKey(nsIX509Cert* cert, const nsCString& matchDbKey)
|
||||
{
|
||||
char *dbkey = nullptr;
|
||||
nsresult rv = cert->GetDbKey(&dbkey);
|
||||
if (NS_FAILED(rv) || !dbkey)
|
||||
nsAutoCString dbKey;
|
||||
nsresult rv = cert->GetDbKey(dbKey);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
|
||||
bool found_mismatch = false;
|
||||
const char *key1 = dbkey;
|
||||
const char *key2 = match_dbkey;
|
||||
|
||||
// skip over any whitespace when comparing
|
||||
while (*key1 && *key2) {
|
||||
char c1 = *key1;
|
||||
char c2 = *key2;
|
||||
|
||||
switch (c1) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
++key1;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (c2) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
++key2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c1 != c2) {
|
||||
found_mismatch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
++key1;
|
||||
++key2;
|
||||
}
|
||||
|
||||
PR_Free(dbkey);
|
||||
return !found_mismatch;
|
||||
return dbKey.Equals(matchDbKey);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -667,7 +622,7 @@ nsCertOverrideService::IsCertUsedForOverrides(nsIX509Cert *aCert,
|
||||
still_ok = false;
|
||||
}
|
||||
|
||||
if (still_ok && matchesDBKey(aCert, settings.mDBKey.get())) {
|
||||
if (still_ok && matchesDBKey(aCert, settings.mDBKey)) {
|
||||
nsAutoCString cert_fingerprint;
|
||||
nsresult rv = NS_ERROR_UNEXPECTED;
|
||||
if (settings.mFingerprintAlgOID.Equals(mDottedOidForStoringNewHashes)) {
|
||||
@ -697,7 +652,7 @@ nsCertOverrideService::EnumerateCertOverrides(nsIX509Cert *aCert,
|
||||
if (!aCert) {
|
||||
aEnumerator(settings, aUserData);
|
||||
} else {
|
||||
if (matchesDBKey(aCert, settings.mDBKey.get())) {
|
||||
if (matchesDBKey(aCert, settings.mDBKey)) {
|
||||
nsAutoCString cert_fingerprint;
|
||||
nsresult rv = NS_ERROR_UNEXPECTED;
|
||||
if (settings.mFingerprintAlgOID.Equals(mDottedOidForStoringNewHashes)) {
|
||||
|
@ -102,29 +102,26 @@ nsClientAuthRememberService::RememberDecision(const nsACString & aHostName,
|
||||
{
|
||||
// aClientCert == nullptr means: remember that user does not want to use a cert
|
||||
NS_ENSURE_ARG_POINTER(aServerCert);
|
||||
if (aHostName.IsEmpty())
|
||||
if (aHostName.IsEmpty()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsAutoCString fpStr;
|
||||
nsresult rv = GetCertFingerprintByOidTag(aServerCert, SEC_OID_SHA256, fpStr);
|
||||
if (NS_FAILED(rv))
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter lock(monitor);
|
||||
if (aClientCert) {
|
||||
RefPtr<nsNSSCertificate> pipCert(new nsNSSCertificate(aClientCert));
|
||||
char *dbkey = nullptr;
|
||||
rv = pipCert->GetDbKey(&dbkey);
|
||||
if (NS_SUCCEEDED(rv) && dbkey) {
|
||||
AddEntryToList(aHostName, fpStr,
|
||||
nsDependentCString(dbkey));
|
||||
nsAutoCString dbkey;
|
||||
rv = pipCert->GetDbKey(dbkey);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
AddEntryToList(aHostName, fpStr, dbkey);
|
||||
}
|
||||
if (dbkey) {
|
||||
PORT_Free(dbkey);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
nsCString empty;
|
||||
AddEntryToList(aHostName, fpStr, empty);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ interface nsICertVerificationListener;
|
||||
/**
|
||||
* This represents a X.509 certificate.
|
||||
*/
|
||||
[scriptable, uuid(f8ed8364-ced9-4c6e-86ba-48af53c393e6)]
|
||||
[scriptable, uuid(bdc3979a-5422-4cd5-8589-696b6e96ea83)]
|
||||
interface nsIX509Cert : nsISupports {
|
||||
|
||||
/**
|
||||
@ -130,7 +130,7 @@ interface nsIX509Cert : nsISupports {
|
||||
/**
|
||||
* A unique identifier of this certificate within the local storage.
|
||||
*/
|
||||
readonly attribute string dbKey;
|
||||
readonly attribute ACString dbKey;
|
||||
|
||||
/**
|
||||
* A human readable identifier to label this certificate.
|
||||
|
@ -50,6 +50,10 @@
|
||||
#include "ssl.h"
|
||||
#include "plbase64.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <winsock.h> // for htonl
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::psm;
|
||||
|
||||
@ -486,32 +490,37 @@ nsNSSCertificate::FormatUIStrings(const nsAutoString& nickname,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSCertificate::GetDbKey(char** aDbKey)
|
||||
nsNSSCertificate::GetDbKey(nsACString& aDbKey)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (isAlreadyShutDown())
|
||||
if (isAlreadyShutDown()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
SECItem key;
|
||||
static_assert(sizeof(uint64_t) == 8, "type size sanity check");
|
||||
static_assert(sizeof(uint32_t) == 4, "type size sanity check");
|
||||
// The format of the key is the base64 encoding of the following:
|
||||
// 4 bytes: {0, 0, 0, 0} (this was intended to be the module ID, but it was
|
||||
// never implemented)
|
||||
// 4 bytes: {0, 0, 0, 0} (this was intended to be the slot ID, but it was
|
||||
// never implemented)
|
||||
// 4 bytes: <serial number length in big-endian order>
|
||||
// 4 bytes: <DER-encoded issuer distinguished name length in big-endian order>
|
||||
// n bytes: <bytes of serial number>
|
||||
// m bytes: <DER-encoded issuer distinguished name>
|
||||
nsAutoCString buf;
|
||||
const char leadingZeroes[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
buf.Append(leadingZeroes, sizeof(leadingZeroes));
|
||||
uint32_t serialNumberLen = htonl(mCert->serialNumber.len);
|
||||
buf.Append(reinterpret_cast<const char*>(&serialNumberLen), sizeof(uint32_t));
|
||||
uint32_t issuerLen = htonl(mCert->derIssuer.len);
|
||||
buf.Append(reinterpret_cast<const char*>(&issuerLen), sizeof(uint32_t));
|
||||
buf.Append(reinterpret_cast<const char*>(mCert->serialNumber.data),
|
||||
mCert->serialNumber.len);
|
||||
buf.Append(reinterpret_cast<const char*>(mCert->derIssuer.data),
|
||||
mCert->derIssuer.len);
|
||||
|
||||
NS_ENSURE_ARG(aDbKey);
|
||||
*aDbKey = nullptr;
|
||||
key.len = NS_NSS_LONG*4+mCert->serialNumber.len+mCert->derIssuer.len;
|
||||
key.data = (unsigned char*) moz_xmalloc(key.len);
|
||||
if (!key.data)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_NSS_PUT_LONG(0,key.data); // later put moduleID
|
||||
NS_NSS_PUT_LONG(0,&key.data[NS_NSS_LONG]); // later put slotID
|
||||
NS_NSS_PUT_LONG(mCert->serialNumber.len,&key.data[NS_NSS_LONG*2]);
|
||||
NS_NSS_PUT_LONG(mCert->derIssuer.len,&key.data[NS_NSS_LONG*3]);
|
||||
memcpy(&key.data[NS_NSS_LONG*4], mCert->serialNumber.data,
|
||||
mCert->serialNumber.len);
|
||||
memcpy(&key.data[NS_NSS_LONG*4+mCert->serialNumber.len],
|
||||
mCert->derIssuer.data, mCert->derIssuer.len);
|
||||
|
||||
*aDbKey = NSSBase64_EncodeItem(nullptr, nullptr, 0, &key);
|
||||
free(key.data); // SECItem is a 'c' type without a destructor
|
||||
return (*aDbKey) ? NS_OK : NS_ERROR_FAILURE;
|
||||
return Base64Encode(buf, aDbKey);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -132,17 +132,6 @@ private:
|
||||
void operator=(const nsNSSCertListEnumerator&) = delete;
|
||||
};
|
||||
|
||||
|
||||
#define NS_NSS_LONG 4
|
||||
#define NS_NSS_GET_LONG(x) ((((unsigned long)((x)[0])) << 24) | \
|
||||
(((unsigned long)((x)[1])) << 16) | \
|
||||
(((unsigned long)((x)[2])) << 8) | \
|
||||
((unsigned long)((x)[3])) )
|
||||
#define NS_NSS_PUT_LONG(src,dest) (dest)[0] = (((src) >> 24) & 0xff); \
|
||||
(dest)[1] = (((src) >> 16) & 0xff); \
|
||||
(dest)[2] = (((src) >> 8) & 0xff); \
|
||||
(dest)[3] = ((src) & 0xff);
|
||||
|
||||
#define NS_X509CERT_CID { /* 660a3226-915c-4ffb-bb20-8985a632df05 */ \
|
||||
0x660a3226, \
|
||||
0x915c, \
|
||||
|
@ -48,6 +48,10 @@
|
||||
#include "ssl.h"
|
||||
#include "plbase64.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <winsock.h> // for ntohl
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::psm;
|
||||
using mozilla::psm::SharedSSLState;
|
||||
@ -137,42 +141,58 @@ nsNSSCertificateDB::FindCertByDBKey(const char *aDBkey, nsISupports *aToken,
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
SECItem keyItem = {siBuffer, nullptr, 0};
|
||||
SECItem *dummy;
|
||||
static_assert(sizeof(uint64_t) == 8, "type size sanity check");
|
||||
static_assert(sizeof(uint32_t) == 4, "type size sanity check");
|
||||
// (From nsNSSCertificate::GetDbKey)
|
||||
// The format of the key is the base64 encoding of the following:
|
||||
// 4 bytes: {0, 0, 0, 0} (this was intended to be the module ID, but it was
|
||||
// never implemented)
|
||||
// 4 bytes: {0, 0, 0, 0} (this was intended to be the slot ID, but it was
|
||||
// never implemented)
|
||||
// 4 bytes: <serial number length in big-endian order>
|
||||
// 4 bytes: <DER-encoded issuer distinguished name length in big-endian order>
|
||||
// n bytes: <bytes of serial number>
|
||||
// m bytes: <DER-encoded issuer distinguished name>
|
||||
nsAutoCString decoded;
|
||||
nsAutoCString tmpDBKey(aDBkey);
|
||||
// Filter out any whitespace for backwards compatibility.
|
||||
tmpDBKey.StripWhitespace();
|
||||
nsresult rv = Base64Decode(tmpDBKey, decoded);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (decoded.Length() < 16) {
|
||||
return NS_ERROR_ILLEGAL_INPUT;
|
||||
}
|
||||
const char* reader = decoded.BeginReading();
|
||||
uint64_t zeroes = *reinterpret_cast<const uint64_t*>(reader);
|
||||
if (zeroes != 0) {
|
||||
return NS_ERROR_ILLEGAL_INPUT;
|
||||
}
|
||||
reader += sizeof(uint64_t);
|
||||
uint32_t serialNumberLen = ntohl(*reinterpret_cast<const uint32_t*>(reader));
|
||||
reader += sizeof(uint32_t);
|
||||
uint32_t issuerLen = ntohl(*reinterpret_cast<const uint32_t*>(reader));
|
||||
reader += sizeof(uint32_t);
|
||||
if (decoded.Length() != 16ULL + serialNumberLen + issuerLen) {
|
||||
return NS_ERROR_ILLEGAL_INPUT;
|
||||
}
|
||||
CERTIssuerAndSN issuerSN;
|
||||
//unsigned long moduleID,slotID;
|
||||
issuerSN.serialNumber.len = serialNumberLen;
|
||||
issuerSN.serialNumber.data = (unsigned char*)reader;
|
||||
reader += serialNumberLen;
|
||||
issuerSN.derIssuer.len = issuerLen;
|
||||
issuerSN.derIssuer.data = (unsigned char*)reader;
|
||||
reader += issuerLen;
|
||||
MOZ_ASSERT(reader == decoded.EndReading());
|
||||
|
||||
dummy = NSSBase64_DecodeBuffer(nullptr, &keyItem, aDBkey,
|
||||
(uint32_t)strlen(aDBkey));
|
||||
if (!dummy || keyItem.len < NS_NSS_LONG*4) {
|
||||
PR_FREEIF(keyItem.data);
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ScopedCERTCertificate cert;
|
||||
// someday maybe we can speed up the search using the moduleID and slotID
|
||||
// moduleID = NS_NSS_GET_LONG(keyItem.data);
|
||||
// slotID = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG]);
|
||||
|
||||
// build the issuer/SN structure
|
||||
issuerSN.serialNumber.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*2]);
|
||||
issuerSN.derIssuer.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*3]);
|
||||
if (issuerSN.serialNumber.len == 0 || issuerSN.derIssuer.len == 0
|
||||
|| issuerSN.serialNumber.len + issuerSN.derIssuer.len
|
||||
!= keyItem.len - NS_NSS_LONG*4) {
|
||||
PR_FREEIF(keyItem.data);
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
issuerSN.serialNumber.data= &keyItem.data[NS_NSS_LONG*4];
|
||||
issuerSN.derIssuer.data= &keyItem.data[NS_NSS_LONG*4+
|
||||
issuerSN.serialNumber.len];
|
||||
|
||||
cert = CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN);
|
||||
PR_FREEIF(keyItem.data);
|
||||
ScopedCERTCertificate cert(
|
||||
CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN));
|
||||
if (cert) {
|
||||
nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
|
||||
if (!nssCert)
|
||||
if (!nssCert) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
nssCert.forget(_cert);
|
||||
}
|
||||
return NS_OK;
|
||||
@ -1221,12 +1241,10 @@ nsNSSCertificateDB::getCertNames(CERTCertList *certList,
|
||||
node = CERT_LIST_NEXT(node)) {
|
||||
if (getCertType(node->cert) == type) {
|
||||
RefPtr<nsNSSCertificate> pipCert(new nsNSSCertificate(node->cert));
|
||||
char *dbkey = nullptr;
|
||||
char *namestr = nullptr;
|
||||
nsAutoString certstr;
|
||||
pipCert->GetDbKey(&dbkey);
|
||||
nsAutoCString dbkey;
|
||||
pipCert->GetDbKey(dbkey);
|
||||
nsAutoString keystr = NS_ConvertASCIItoUTF16(dbkey);
|
||||
PR_FREEIF(dbkey);
|
||||
char *namestr = nullptr;
|
||||
if (type == nsIX509Cert::EMAIL_CERT) {
|
||||
namestr = node->cert->emailAddr;
|
||||
} else {
|
||||
@ -1237,6 +1255,7 @@ nsNSSCertificateDB::getCertNames(CERTCertList *certList,
|
||||
}
|
||||
}
|
||||
nsAutoString certname = NS_ConvertASCIItoUTF16(namestr ? namestr : "");
|
||||
nsAutoString certstr;
|
||||
certstr.Append(char16_t(DELIM));
|
||||
certstr += certname;
|
||||
certstr.Append(char16_t(DELIM));
|
||||
|
@ -31,7 +31,7 @@ nsNSSCertificateFakeTransport::~nsNSSCertificateFakeTransport()
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSCertificateFakeTransport::GetDbKey(char**)
|
||||
nsNSSCertificateFakeTransport::GetDbKey(nsACString&)
|
||||
{
|
||||
NS_NOTREACHED("Unimplemented on content process");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
152
security/manager/ssl/tests/unit/test_cert_dbKey.js
Normal file
152
security/manager/ssl/tests/unit/test_cert_dbKey.js
Normal file
@ -0,0 +1,152 @@
|
||||
// -*- 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) {
|
||||
let exceptionCaught = false;
|
||||
try {
|
||||
let cert = certDB.findCertByDBKey(dbKey, null);
|
||||
} catch(e) {
|
||||
do_print(e);
|
||||
exceptionCaught = true;
|
||||
}
|
||||
ok(exceptionCaught, "should have thrown and caught an exception");
|
||||
}
|
||||
|
||||
function testDBKeyForNonexistentCert(certDB, dbKey) {
|
||||
let cert = certDB.findCertByDBKey(dbKey, null);
|
||||
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, null);
|
||||
ok(certFromDbKey.equals(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, null);
|
||||
ok(certFromDbKey.equals(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, null);
|
||||
ok(certFromDbKey.equals(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 ])));
|
||||
}
|
@ -53,6 +53,7 @@ skip-if = toolkit == 'android' || toolkit == 'gonk'
|
||||
[test_pinning_dynamic.js]
|
||||
[test_pinning_header_parsing.js]
|
||||
|
||||
[test_cert_dbKey.js]
|
||||
[test_cert_keyUsage.js]
|
||||
[test_logoutAndTeardown.js]
|
||||
run-sequentially = hardcoded ports
|
||||
|
Loading…
Reference in New Issue
Block a user