mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 1203312 - convert tlsserver to generate certificates at build time r=Cykesiopka,mgoodwin
This commit is contained in:
parent
98c6366a22
commit
50b152df26
@ -81,7 +81,7 @@ static const char kDigiCert_High_Assurance_EV_Root_CAFingerprint[] =
|
||||
|
||||
/* End Entity Test Cert */
|
||||
static const char kEnd_Entity_Test_CertFingerprint[] =
|
||||
"lzCakFt+nADIfIkgk+UE/EQ9SaT2nay2yu2iykVbvV8=";
|
||||
"VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
|
||||
|
||||
/* Entrust Root Certification Authority */
|
||||
static const char kEntrust_Root_Certification_AuthorityFingerprint[] =
|
||||
|
@ -435,7 +435,7 @@ function _setupTLSServerTest(serverBinName)
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
// The trusted CA that is typically used for "good" certificates.
|
||||
addCertFromFile(certdb, "tlsserver/test-ca.der", "CTu,u,u");
|
||||
addCertFromFile(certdb, "tlsserver/test-ca.pem", "CTu,u,u");
|
||||
|
||||
const CALLBACK_PORT = 8444;
|
||||
|
||||
@ -639,9 +639,8 @@ FakeSSLStatus.prototype = {
|
||||
|
||||
// Utility functions for adding tests relating to certificate error overrides
|
||||
|
||||
// Helper function for add_cert_override_test and
|
||||
// add_prevented_cert_override_test. Probably doesn't need to be called
|
||||
// directly.
|
||||
// Helper function for add_cert_override_test. Probably doesn't need to be
|
||||
// called directly.
|
||||
function add_cert_override(aHost, aExpectedBits, aSecurityInfo) {
|
||||
let sslstatus = aSecurityInfo.QueryInterface(Ci.nsISSLStatusProvider)
|
||||
.SSLStatus;
|
||||
@ -668,6 +667,28 @@ function add_cert_override_test(aHost, aExpectedBits, aExpectedError) {
|
||||
add_connection_test(aHost, PRErrorCodeSuccess);
|
||||
}
|
||||
|
||||
// Helper function for add_prevented_cert_override_test. This is much like
|
||||
// add_cert_override except it may not be the case that the connection has an
|
||||
// SSLStatus set on it. In this case, the error was not overridable anyway, so
|
||||
// we consider it a success.
|
||||
function attempt_adding_cert_override(aHost, aExpectedBits, aSecurityInfo) {
|
||||
let sslstatus = aSecurityInfo.QueryInterface(Ci.nsISSLStatusProvider)
|
||||
.SSLStatus;
|
||||
if (sslstatus) {
|
||||
let bits =
|
||||
(sslstatus.isUntrusted ? Ci.nsICertOverrideService.ERROR_UNTRUSTED : 0) |
|
||||
(sslstatus.isDomainMismatch ? Ci.nsICertOverrideService.ERROR_MISMATCH : 0) |
|
||||
(sslstatus.isNotValidAtThisTime ? Ci.nsICertOverrideService.ERROR_TIME : 0);
|
||||
Assert.equal(bits, aExpectedBits,
|
||||
"Actual and expected override bits should match");
|
||||
let cert = sslstatus.serverCert;
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
certOverrideService.rememberValidityOverride(aHost, 8443, cert, aExpectedBits,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
// Given a host, expected error bits (see nsICertOverrideService.idl), and
|
||||
// an expected error code, tests that an initial connection to the host fails
|
||||
// with the expected errors and that adding an override does not result in a
|
||||
@ -676,6 +697,6 @@ function add_cert_override_test(aHost, aExpectedBits, aExpectedError) {
|
||||
// overridable, even if an entry is added to the override service.
|
||||
function add_prevented_cert_override_test(aHost, aExpectedBits, aExpectedError) {
|
||||
add_connection_test(aHost, aExpectedError, null,
|
||||
add_cert_override.bind(this, aHost, aExpectedBits));
|
||||
attempt_adding_cert_override.bind(this, aHost, aExpectedBits));
|
||||
add_connection_test(aHost, aExpectedError);
|
||||
}
|
||||
|
@ -16,7 +16,8 @@ subject:<subject distinguished name specification>
|
||||
[validity:<YYYYMMDD-YYYYMMDD|duration in days>]
|
||||
[issuerKey:<key specification>]
|
||||
[subjectKey:<key specification>]
|
||||
[signature:{sha1WithRSAEncryption,sha256WithRSAEncryption,ecdsaWithSHA256}]
|
||||
[signature:{sha256WithRSAEncryption,sha1WithRSAEncryption,
|
||||
md5WithRSAEncryption,ecdsaWithSHA256}]
|
||||
[extension:<extension name:<extension-specific data>>]
|
||||
[...]
|
||||
|
||||
@ -31,6 +32,7 @@ subjectAlternativeName:[<dNSName>,...]
|
||||
authorityInformationAccess:<OCSP URI>
|
||||
certificatePolicies:<policy OID>
|
||||
nameConstraints:{permitted,excluded}:[<dNSName|directoryName>,...]
|
||||
nsCertType:sslServer
|
||||
|
||||
Where:
|
||||
[] indicates an optional field or component of a field
|
||||
@ -64,6 +66,9 @@ be 'utf8String' or 'printableString'. If the given string does not
|
||||
contain a '/', it is assumed to represent a common name.
|
||||
DirectoryNames also use this format. When specifying a directoryName in
|
||||
a nameConstraints extension, the implicit form may not be used.
|
||||
|
||||
If an extension name has '[critical]' after it, it will be marked as
|
||||
critical. Otherwise (by default), it will not be marked as critical.
|
||||
"""
|
||||
|
||||
from pyasn1.codec.der import decoder
|
||||
@ -178,6 +183,14 @@ class UnknownDNTypeError(UnknownBaseError):
|
||||
self.category = 'DN'
|
||||
|
||||
|
||||
class UnknownNSCertTypeError(UnknownBaseError):
|
||||
"""Helper exception type to handle unknown nsCertType types."""
|
||||
|
||||
def __init__(self, value):
|
||||
UnknownBaseError.__init__(self, value)
|
||||
self.category = 'nsCertType'
|
||||
|
||||
|
||||
def getASN1Tag(asn1Type):
|
||||
"""Helper function for returning the base tag value of a given
|
||||
type from the pyasn1 package"""
|
||||
@ -254,27 +267,29 @@ def stringToDN(string, tag=None):
|
||||
name.setComponentByPosition(0, rdns)
|
||||
return name
|
||||
|
||||
def stringToAlgorithmIdentifier(string):
|
||||
def stringToAlgorithmIdentifiers(string):
|
||||
"""Helper function that converts a description of an algorithm
|
||||
to a representation usable by the pyasn1 package"""
|
||||
to a representation usable by the pyasn1 package and a hash
|
||||
algorithm name for use by pykey."""
|
||||
algorithmIdentifier = rfc2459.AlgorithmIdentifier()
|
||||
algorithmName = None
|
||||
algorithm = None
|
||||
name = None
|
||||
if string == 'sha1WithRSAEncryption':
|
||||
name = 'SHA-1'
|
||||
algorithmName = 'SHA-1'
|
||||
algorithm = rfc2459.sha1WithRSAEncryption
|
||||
elif string == 'sha256WithRSAEncryption':
|
||||
name = 'SHA-256'
|
||||
algorithmName = 'SHA-256'
|
||||
algorithm = univ.ObjectIdentifier('1.2.840.113549.1.1.11')
|
||||
elif string == 'md5WithRSAEncryption':
|
||||
algorithmName = 'MD5'
|
||||
algorithm = rfc2459.md5WithRSAEncryption
|
||||
elif string == 'ecdsaWithSHA256':
|
||||
# Note that this value is only used by pykey.py to tell if
|
||||
# ECDSA is allowed. It does not conform to the pyECC syntax.
|
||||
name = 'SHA-256'
|
||||
algorithmName = 'sha256'
|
||||
algorithm = univ.ObjectIdentifier('1.2.840.10045.4.3.2')
|
||||
else:
|
||||
raise UnknownAlgorithmTypeError(string)
|
||||
algorithmIdentifier.setComponentByName('algorithm', algorithm)
|
||||
return (algorithmIdentifier, name)
|
||||
return (algorithmIdentifier, algorithmName)
|
||||
|
||||
def datetimeToTime(dt):
|
||||
"""Takes a datetime object and returns an rfc2459.Time object with
|
||||
@ -380,22 +395,28 @@ class Certificate:
|
||||
self.notAfter = self.now + delta
|
||||
|
||||
def decodeExtension(self, extension):
|
||||
extensionType = extension.split(':')[0]
|
||||
value = ':'.join(extension.split(':')[1:])
|
||||
match = re.search('([a-zA-Z]+)(\[critical\])?:(.*)', extension)
|
||||
if not match:
|
||||
raise UnknownExtensionTypeError(extension)
|
||||
extensionType = match.group(1)
|
||||
critical = match.group(2)
|
||||
value = match.group(3)
|
||||
if extensionType == 'basicConstraints':
|
||||
self.addBasicConstraints(value)
|
||||
self.addBasicConstraints(value, critical)
|
||||
elif extensionType == 'keyUsage':
|
||||
self.addKeyUsage(value)
|
||||
self.addKeyUsage(value, critical)
|
||||
elif extensionType == 'extKeyUsage':
|
||||
self.addExtKeyUsage(value)
|
||||
self.addExtKeyUsage(value, critical)
|
||||
elif extensionType == 'subjectAlternativeName':
|
||||
self.addSubjectAlternativeName(value)
|
||||
self.addSubjectAlternativeName(value, critical)
|
||||
elif extensionType == 'authorityInformationAccess':
|
||||
self.addAuthorityInformationAccess(value)
|
||||
self.addAuthorityInformationAccess(value, critical)
|
||||
elif extensionType == 'certificatePolicies':
|
||||
self.addCertificatePolicies(value)
|
||||
self.addCertificatePolicies(value, critical)
|
||||
elif extensionType == 'nameConstraints':
|
||||
self.addNameConstraints(value)
|
||||
self.addNameConstraints(value, critical)
|
||||
elif extensionType == 'nsCertType':
|
||||
self.addNSCertType(value, critical)
|
||||
else:
|
||||
raise UnknownExtensionTypeError(extensionType)
|
||||
|
||||
@ -407,16 +428,20 @@ class Certificate:
|
||||
else:
|
||||
raise UnknownKeyTargetError(subjectOrIssuer)
|
||||
|
||||
def addExtension(self, extensionType, extensionValue):
|
||||
def addExtension(self, extensionType, extensionValue, critical):
|
||||
if not self.extensions:
|
||||
self.extensions = []
|
||||
encapsulated = univ.OctetString(encoder.encode(extensionValue))
|
||||
extension = rfc2459.Extension()
|
||||
extension.setComponentByName('extnID', extensionType)
|
||||
# critical is either the string '[critical]' or None.
|
||||
# We only care whether or not it is truthy.
|
||||
if critical:
|
||||
extension.setComponentByName('critical', True)
|
||||
extension.setComponentByName('extnValue', encapsulated)
|
||||
self.extensions.append(extension)
|
||||
|
||||
def addBasicConstraints(self, basicConstraints):
|
||||
def addBasicConstraints(self, basicConstraints, critical):
|
||||
cA = basicConstraints.split(',')[0]
|
||||
pathLenConstraint = basicConstraints.split(',')[1]
|
||||
basicConstraintsExtension = rfc2459.BasicConstraints()
|
||||
@ -427,11 +452,11 @@ class Certificate:
|
||||
subtypeSpec=constraint.ValueRangeConstraint(0, 64))
|
||||
basicConstraintsExtension.setComponentByName('pathLenConstraint',
|
||||
pathLenConstraintValue)
|
||||
self.addExtension(rfc2459.id_ce_basicConstraints, basicConstraintsExtension)
|
||||
self.addExtension(rfc2459.id_ce_basicConstraints, basicConstraintsExtension, critical)
|
||||
|
||||
def addKeyUsage(self, keyUsage):
|
||||
def addKeyUsage(self, keyUsage, critical):
|
||||
keyUsageExtension = rfc2459.KeyUsage(keyUsage)
|
||||
self.addExtension(rfc2459.id_ce_keyUsage, keyUsageExtension)
|
||||
self.addExtension(rfc2459.id_ce_keyUsage, keyUsageExtension, critical)
|
||||
|
||||
def keyPurposeToOID(self, keyPurpose):
|
||||
if keyPurpose == 'serverAuth':
|
||||
@ -452,15 +477,15 @@ class Certificate:
|
||||
return rfc2459.id_kp_timeStamping
|
||||
raise UnknownKeyPurposeTypeError(keyPurpose)
|
||||
|
||||
def addExtKeyUsage(self, extKeyUsage):
|
||||
def addExtKeyUsage(self, extKeyUsage, critical):
|
||||
extKeyUsageExtension = rfc2459.ExtKeyUsageSyntax()
|
||||
count = 0
|
||||
for keyPurpose in extKeyUsage.split(','):
|
||||
extKeyUsageExtension.setComponentByPosition(count, self.keyPurposeToOID(keyPurpose))
|
||||
count += 1
|
||||
self.addExtension(rfc2459.id_ce_extKeyUsage, extKeyUsageExtension)
|
||||
self.addExtension(rfc2459.id_ce_extKeyUsage, extKeyUsageExtension, critical)
|
||||
|
||||
def addSubjectAlternativeName(self, dNSNames):
|
||||
def addSubjectAlternativeName(self, dNSNames, critical):
|
||||
subjectAlternativeName = rfc2459.SubjectAltName()
|
||||
count = 0
|
||||
for dNSName in dNSNames.split(','):
|
||||
@ -471,15 +496,15 @@ class Certificate:
|
||||
generalName.setComponentByName('dNSName', dNSName.decode(encoding='string_escape'))
|
||||
subjectAlternativeName.setComponentByPosition(count, generalName)
|
||||
count += 1
|
||||
self.addExtension(rfc2459.id_ce_subjectAltName, subjectAlternativeName)
|
||||
self.addExtension(rfc2459.id_ce_subjectAltName, subjectAlternativeName, critical)
|
||||
|
||||
def addAuthorityInformationAccess(self, ocspURI):
|
||||
def addAuthorityInformationAccess(self, ocspURI, critical):
|
||||
sequence = univ.Sequence()
|
||||
accessDescription = stringToAccessDescription(ocspURI)
|
||||
sequence.setComponentByPosition(0, accessDescription)
|
||||
self.addExtension(rfc2459.id_pe_authorityInfoAccess, sequence)
|
||||
self.addExtension(rfc2459.id_pe_authorityInfoAccess, sequence, critical)
|
||||
|
||||
def addCertificatePolicies(self, policyOID):
|
||||
def addCertificatePolicies(self, policyOID, critical):
|
||||
policies = rfc2459.CertificatePolicies()
|
||||
policy = rfc2459.PolicyInformation()
|
||||
if policyOID == 'any':
|
||||
@ -487,9 +512,9 @@ class Certificate:
|
||||
policyIdentifier = rfc2459.CertPolicyId(policyOID)
|
||||
policy.setComponentByName('policyIdentifier', policyIdentifier)
|
||||
policies.setComponentByPosition(0, policy)
|
||||
self.addExtension(rfc2459.id_ce_certificatePolicies, policies)
|
||||
self.addExtension(rfc2459.id_ce_certificatePolicies, policies, critical)
|
||||
|
||||
def addNameConstraints(self, constraints):
|
||||
def addNameConstraints(self, constraints, critical):
|
||||
nameConstraints = NameConstraints()
|
||||
if constraints.startswith('permitted:'):
|
||||
(subtreesType, subtreesTag) = ('permittedSubtrees', 0)
|
||||
@ -514,7 +539,13 @@ class Certificate:
|
||||
generalSubtrees.setComponentByPosition(pos, generalSubtree)
|
||||
pos = pos + 1
|
||||
nameConstraints.setComponentByName(subtreesType, generalSubtrees)
|
||||
self.addExtension(rfc2459.id_ce_nameConstraints, nameConstraints)
|
||||
self.addExtension(rfc2459.id_ce_nameConstraints, nameConstraints, critical)
|
||||
|
||||
def addNSCertType(self, certType, critical):
|
||||
if certType != 'sslServer':
|
||||
raise UnknownNSCertTypeError(certType)
|
||||
self.addExtension(univ.ObjectIdentifier('2.16.840.1.113730.1.1'), univ.BitString("'01'B"),
|
||||
critical)
|
||||
|
||||
def getVersion(self):
|
||||
return rfc2459.Version(self.versionValue).subtype(
|
||||
@ -523,9 +554,6 @@ class Certificate:
|
||||
def getSerialNumber(self):
|
||||
return decoder.decode(self.serialNumber)[0]
|
||||
|
||||
def getSignature(self):
|
||||
return stringToAlgorithmIdentifier(self.signature)
|
||||
|
||||
def getIssuer(self):
|
||||
return stringToDN(self.issuer)
|
||||
|
||||
@ -545,8 +573,7 @@ class Certificate:
|
||||
return stringToDN(self.subject)
|
||||
|
||||
def toDER(self):
|
||||
(signatureOID, hashAlg) = self.getSignature()
|
||||
|
||||
(signatureOID, hashName) = stringToAlgorithmIdentifiers(self.signature)
|
||||
tbsCertificate = rfc2459.TBSCertificate()
|
||||
tbsCertificate.setComponentByName('version', self.getVersion())
|
||||
tbsCertificate.setComponentByName('serialNumber', self.getSerialNumber())
|
||||
@ -568,8 +595,7 @@ class Certificate:
|
||||
certificate.setComponentByName('tbsCertificate', tbsCertificate)
|
||||
certificate.setComponentByName('signatureAlgorithm', signatureOID)
|
||||
tbsDER = encoder.encode(tbsCertificate)
|
||||
|
||||
certificate.setComponentByName('signatureValue', self.issuerKey.sign(tbsDER, hashAlg))
|
||||
certificate.setComponentByName('signatureValue', self.issuerKey.sign(tbsDER, hashName))
|
||||
return encoder.encode(certificate)
|
||||
|
||||
def toPEM(self):
|
||||
|
@ -66,13 +66,6 @@ class UnknownKeySpecificationError(UnknownBaseError):
|
||||
UnknownBaseError.__init__(self, value)
|
||||
self.category = 'key specification'
|
||||
|
||||
class ParameterError(UnknownBaseError):
|
||||
"""Exception type indicating that the key was misconfigured"""
|
||||
|
||||
def __init__(self, value):
|
||||
UnknownBaseError.__init__(self, value)
|
||||
self.category = 'key parameter'
|
||||
|
||||
class RSAPublicKey(univ.Sequence):
|
||||
"""Helper type for encoding an RSA public key"""
|
||||
componentType = namedtype.NamedTypes(
|
||||
@ -560,12 +553,12 @@ class RSAKey:
|
||||
spki.setComponentByName('subjectPublicKey', subjectPublicKey)
|
||||
return spki
|
||||
|
||||
def sign(self, data, digest):
|
||||
def sign(self, data, hashAlgorithmName):
|
||||
"""Returns a hexified bit string representing a
|
||||
signature by this key over the specified data.
|
||||
Intended for use with pyasn1.type.univ.BitString"""
|
||||
rsaPrivateKey = rsa.PrivateKey(self.RSA_N, self.RSA_E, self.RSA_D, self.RSA_P, self.RSA_Q)
|
||||
signature = rsa.sign(data, rsaPrivateKey, digest)
|
||||
signature = rsa.sign(data, rsaPrivateKey, hashAlgorithmName)
|
||||
return byteStringToHexifiedBitString(signature)
|
||||
|
||||
|
||||
@ -671,14 +664,10 @@ class ECCKey:
|
||||
spki.setComponentByName('subjectPublicKey', subjectPublicKey)
|
||||
return spki
|
||||
|
||||
def sign(self, data, digest):
|
||||
def sign(self, data, hashAlgorithmName):
|
||||
"""Returns a hexified bit string representing a
|
||||
signature by this key over the specified data.
|
||||
Intended for use with pyasn1.type.univ.BitString"""
|
||||
# This should really only be used with SHA-256
|
||||
if digest != "SHA-256":
|
||||
raise ParameterError(digest)
|
||||
|
||||
# There is some non-determinism in ECDSA signatures. Work around
|
||||
# this by patching ecc.ecdsa.urandom to not be random.
|
||||
with mock.patch('ecc.ecdsa.urandom', side_effect=notRandom):
|
||||
@ -688,9 +677,9 @@ class ECCKey:
|
||||
# Also patch in secp256k1 if applicable.
|
||||
if self.keyOID == secp256k1:
|
||||
with mock.patch('ecc.curves.DOMAINS', {256: secp256k1Params}):
|
||||
x, y = encoding.dec_point(self.key.sign(data, 'sha256'))
|
||||
x, y = encoding.dec_point(self.key.sign(data, hashAlgorithmName))
|
||||
else:
|
||||
x, y = encoding.dec_point(self.key.sign(data, 'sha256'))
|
||||
x, y = encoding.dec_point(self.key.sign(data, hashAlgorithmName))
|
||||
point = ECPoint()
|
||||
point.setComponentByName('x', x)
|
||||
point.setComponentByName('y', y)
|
||||
|
@ -94,15 +94,15 @@ var blocklist_contents =
|
||||
"<serialNumber>and serial</serialNumber></certItem>" +
|
||||
// some mixed
|
||||
// In this case, the issuer name and the valid serialNumber correspond
|
||||
// to test-int.der in tlsserver/
|
||||
"<certItem issuerName='MBIxEDAOBgNVBAMTB1Rlc3QgQ0E='>" +
|
||||
// to test-int.pem in tlsserver/
|
||||
"<certItem issuerName='MBIxEDAOBgNVBAMMB1Rlc3QgQ0E='>" +
|
||||
"<serialNumber>oops! more nonsense.</serialNumber>" +
|
||||
"<serialNumber>X1o=</serialNumber></certItem>" +
|
||||
"<serialNumber>Y1HQqXGtw7ek2v/QAqBL8jf6rbA=</serialNumber></certItem>" +
|
||||
// ... and some good
|
||||
// In this case, the issuer name and the valid serialNumber correspond
|
||||
// to other-test-ca.der in tlsserver/ (for testing root revocation)
|
||||
"<certItem issuerName='MBgxFjAUBgNVBAMTDU90aGVyIHRlc3QgQ0E='>" +
|
||||
"<serialNumber>AKEIivg=</serialNumber></certItem>" +
|
||||
// to other-test-ca.pem in tlsserver/ (for testing root revocation)
|
||||
"<certItem issuerName='MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0E='>" +
|
||||
"<serialNumber>Szin5enUEn9TnVq29c4IMPNFuqE=</serialNumber></certItem>" +
|
||||
// This item corresponds to an entry in sample_revocations.txt where:
|
||||
// isser name is "another imaginary issuer" base-64 encoded, and
|
||||
// serialNumbers are:
|
||||
@ -113,8 +113,9 @@ var blocklist_contents =
|
||||
"<certItem issuerName='YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy'>" +
|
||||
"<serialNumber>c2VyaWFsMi4=</serialNumber>" +
|
||||
"<serialNumber>YW5vdGhlciBzZXJpYWwu</serialNumber>" +
|
||||
"</certItem><certItem subject='MCIxIDAeBgNVBAMTF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5'"+
|
||||
" pubKeyHash='2ETEb0QP574JkM+35JVwS899PLUmt1rrJyWOV6GRfAE='>" +
|
||||
// This item revokes same-issuer-ee.pem by subject and serial number.
|
||||
"</certItem><certItem subject='MCIxIDAeBgNVBAMMF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5'"+
|
||||
" pubKeyHash='VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8='>" +
|
||||
"</certItem></certItems></blocklist>";
|
||||
testserver.registerPathHandler("/push_blocked_cert/",
|
||||
function serveResponse(request, response) {
|
||||
@ -136,13 +137,12 @@ var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
converter.charset = "UTF-8";
|
||||
|
||||
function verify_cert(file, expectedError) {
|
||||
let cert_der = readFile(do_get_file(file));
|
||||
let ee = certDB.constructX509(cert_der, cert_der.length);
|
||||
let ee = constructCertFromFile(file);
|
||||
checkCertErrorGeneric(certDB, ee, expectedError, certificateUsageSSLServer);
|
||||
}
|
||||
|
||||
function load_cert(cert, trust) {
|
||||
let file = "tlsserver/" + cert + ".der";
|
||||
let file = "tlsserver/" + cert + ".pem";
|
||||
addCertFromFile(certDB, file, trust);
|
||||
}
|
||||
|
||||
@ -201,20 +201,20 @@ function run_test() {
|
||||
ok(test_is_revoked(certList, "another imaginary issuer", "serial2."),
|
||||
"issuer / serial pair should be blocked");
|
||||
|
||||
// Soon we'll load a blocklist which revokes test-int.der, which issued
|
||||
// test-int-ee.der.
|
||||
// Soon we'll load a blocklist which revokes test-int.pem, which issued
|
||||
// test-int-ee.pem.
|
||||
// Check the cert validates before we load the blocklist
|
||||
let file = "tlsserver/test-int-ee.der";
|
||||
let file = "tlsserver/test-int-ee.pem";
|
||||
verify_cert(file, PRErrorCodeSuccess);
|
||||
|
||||
// The blocklist also revokes other-test-ca.der, which issued other-ca-ee.der.
|
||||
// The blocklist also revokes other-test-ca.pem, which issued other-ca-ee.pem.
|
||||
// Check the cert validates before we load the blocklist
|
||||
file = "tlsserver/other-issuer-ee.der";
|
||||
file = "tlsserver/other-issuer-ee.pem";
|
||||
verify_cert(file, PRErrorCodeSuccess);
|
||||
|
||||
// The blocklist will revoke same-issuer-ee.der via subject / pubKeyHash.
|
||||
// The blocklist will revoke same-issuer-ee.pem via subject / pubKeyHash.
|
||||
// Check the cert validates before we load the blocklist
|
||||
file = "tlsserver/same-issuer-ee.der";
|
||||
file = "tlsserver/same-issuer-ee.pem";
|
||||
verify_cert(file, PRErrorCodeSuccess);
|
||||
|
||||
// blocklist load is async so we must use add_test from here
|
||||
@ -271,35 +271,35 @@ function run_test() {
|
||||
contents = contents + (contents.length == 0 ? "" : "\n") + line.value;
|
||||
} while (hasmore);
|
||||
let expected = "# Auto generated contents. Do not edit.\n" +
|
||||
"MCIxIDAeBgNVBAMTF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5\n"+
|
||||
"\t2ETEb0QP574JkM+35JVwS899PLUmt1rrJyWOV6GRfAE=\n"+
|
||||
"MBgxFjAUBgNVBAMTDU90aGVyIHRlc3QgQ0E=\n" +
|
||||
" AKEIivg=\n" +
|
||||
"MBIxEDAOBgNVBAMTB1Rlc3QgQ0E=\n" +
|
||||
" X1o=\n" +
|
||||
"MCIxIDAeBgNVBAMMF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5\n"+
|
||||
"\tVCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=\n"+
|
||||
"MBIxEDAOBgNVBAMMB1Rlc3QgQ0E=\n" +
|
||||
" Y1HQqXGtw7ek2v/QAqBL8jf6rbA=\n" +
|
||||
"MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0E=\n" +
|
||||
" Szin5enUEn9TnVq29c4IMPNFuqE=\n" +
|
||||
"YW5vdGhlciBpbWFnaW5hcnkgaXNzdWVy\n" +
|
||||
" YW5vdGhlciBzZXJpYWwu\n" +
|
||||
" c2VyaWFsMi4=";
|
||||
equal(contents, expected, "revocations.txt should be as expected");
|
||||
|
||||
// Check the blocklisted intermediate now causes a failure
|
||||
let file = "tlsserver/test-int-ee.der";
|
||||
let file = "tlsserver/test-int-ee.pem";
|
||||
verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
|
||||
|
||||
// Check the ee with the blocklisted root also causes a failure
|
||||
file = "tlsserver/other-issuer-ee.der";
|
||||
file = "tlsserver/other-issuer-ee.pem";
|
||||
verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
|
||||
|
||||
// Check the ee blocked by subject / pubKey causes a failure
|
||||
file = "tlsserver/same-issuer-ee.der";
|
||||
file = "tlsserver/same-issuer-ee.pem";
|
||||
verify_cert(file, SEC_ERROR_REVOKED_CERTIFICATE);
|
||||
|
||||
// Check a non-blocklisted chain still validates OK
|
||||
file = "tlsserver/default-ee.der";
|
||||
file = "tlsserver/default-ee.pem";
|
||||
verify_cert(file, PRErrorCodeSuccess);
|
||||
|
||||
// Check a bad cert is still bad (unknown issuer)
|
||||
file = "tlsserver/unknown-issuer.der";
|
||||
file = "tlsserver/unknownissuer.pem";
|
||||
verify_cert(file, SEC_ERROR_UNKNOWN_ISSUER);
|
||||
|
||||
// check that save with no further update is a no-op
|
||||
|
@ -9,16 +9,16 @@ function build_cert_chain(certNames) {
|
||||
let certList = Cc["@mozilla.org/security/x509certlist;1"]
|
||||
.createInstance(Ci.nsIX509CertList);
|
||||
certNames.forEach(function(certName) {
|
||||
let cert = constructCertFromFile("tlsserver/" + certName + ".der");
|
||||
let cert = constructCertFromFile("tlsserver/" + certName + ".pem");
|
||||
certList.addCert(cert);
|
||||
});
|
||||
return certList;
|
||||
}
|
||||
|
||||
function test_cert_equals() {
|
||||
let certA = constructCertFromFile("tlsserver/default-ee.der");
|
||||
let certB = constructCertFromFile("tlsserver/default-ee.der");
|
||||
let certC = constructCertFromFile("tlsserver/expired-ee.der");
|
||||
let certA = constructCertFromFile("tlsserver/default-ee.pem");
|
||||
let certB = constructCertFromFile("tlsserver/default-ee.pem");
|
||||
let certC = constructCertFromFile("tlsserver/expired-ee.pem");
|
||||
|
||||
ok(certA != certB,
|
||||
"Cert objects constructed from the same file should not be equal" +
|
||||
|
@ -13,20 +13,6 @@
|
||||
|
||||
do_get_profile();
|
||||
|
||||
function add_non_overridable_test(aHost, aExpectedError) {
|
||||
add_connection_test(
|
||||
aHost, aExpectedError, null,
|
||||
function (securityInfo) {
|
||||
// bug 754369 - no SSLStatus probably means this is a non-overridable
|
||||
// error, which is what we're testing (although it would be best to test
|
||||
// this directly).
|
||||
securityInfo.QueryInterface(Ci.nsISSLStatusProvider);
|
||||
equal(securityInfo.SSLStatus, null,
|
||||
"As a proxy to checking that the connection error is" +
|
||||
" non-overridable, SSLStatus should be null");
|
||||
});
|
||||
}
|
||||
|
||||
function check_telemetry() {
|
||||
let histogram = Cc["@mozilla.org/base/telemetry;1"]
|
||||
.getService(Ci.nsITelemetry)
|
||||
@ -70,11 +56,11 @@ function check_telemetry() {
|
||||
.snapshot();
|
||||
equal(keySizeHistogram.counts[0], 0,
|
||||
"Actual and expected unchecked key size counts should match");
|
||||
equal(keySizeHistogram.counts[1], 0,
|
||||
equal(keySizeHistogram.counts[1], 12,
|
||||
"Actual and expected successful verifications of 2048-bit keys should match");
|
||||
equal(keySizeHistogram.counts[2], 12,
|
||||
equal(keySizeHistogram.counts[2], 0,
|
||||
"Actual and expected successful verifications of 1024-bit keys should match");
|
||||
equal(keySizeHistogram.counts[3], 48,
|
||||
equal(keySizeHistogram.counts[3], 54,
|
||||
"Actual and expected key size verification failures should match");
|
||||
|
||||
run_next_test();
|
||||
@ -147,22 +133,24 @@ function add_simple_tests() {
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_ISSUER);
|
||||
|
||||
add_non_overridable_test("inadequatekeyusage.example.com",
|
||||
SEC_ERROR_INADEQUATE_KEY_USAGE);
|
||||
add_prevented_cert_override_test("inadequatekeyusage.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_INADEQUATE_KEY_USAGE);
|
||||
|
||||
// This is intended to test the case where a verification has failed for one
|
||||
// overridable reason (e.g. unknown issuer) but then, in the process of
|
||||
// reporting that error, a non-overridable error is encountered. The
|
||||
// non-overridable error should be prioritized.
|
||||
add_test(function() {
|
||||
let rootCert = constructCertFromFile("tlsserver/test-ca.der");
|
||||
let rootCert = constructCertFromFile("tlsserver/test-ca.pem");
|
||||
setCertTrust(rootCert, ",,");
|
||||
run_next_test();
|
||||
});
|
||||
add_non_overridable_test("nsCertTypeCritical.example.com",
|
||||
SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
|
||||
add_prevented_cert_override_test("nsCertTypeCritical.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
|
||||
add_test(function() {
|
||||
let rootCert = constructCertFromFile("tlsserver/test-ca.der");
|
||||
let rootCert = constructCertFromFile("tlsserver/test-ca.pem");
|
||||
setCertTrust(rootCert, "CTu,,");
|
||||
run_next_test();
|
||||
});
|
||||
@ -188,7 +176,7 @@ function add_simple_tests() {
|
||||
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Ci.nsICertOverrideService);
|
||||
certOverrideService.clearValidityOverride("end-entity-issued-by-v1-cert.example.com", 8443);
|
||||
let v1Cert = constructCertFromFile("tlsserver/v1Cert.der");
|
||||
let v1Cert = constructCertFromFile("tlsserver/v1Cert.pem");
|
||||
setCertTrust(v1Cert, "CTu,,");
|
||||
clearSessionCache();
|
||||
run_next_test();
|
||||
@ -197,7 +185,7 @@ function add_simple_tests() {
|
||||
PRErrorCodeSuccess);
|
||||
// Reset the trust for that certificate.
|
||||
add_test(function() {
|
||||
let v1Cert = constructCertFromFile("tlsserver/v1Cert.der");
|
||||
let v1Cert = constructCertFromFile("tlsserver/v1Cert.pem");
|
||||
setCertTrust(v1Cert, ",,");
|
||||
clearSessionCache();
|
||||
run_next_test();
|
||||
@ -209,10 +197,11 @@ function add_simple_tests() {
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SEC_ERROR_CA_CERT_INVALID);
|
||||
|
||||
// This host presents a 1008-bit RSA key. NSS determines this key is too
|
||||
// This host presents a 1016-bit RSA key. NSS determines this key is too
|
||||
// small and terminates the connection. The error is not overridable.
|
||||
add_non_overridable_test("inadequate-key-size-ee.example.com",
|
||||
SSL_ERROR_WEAK_SERVER_CERT_KEY);
|
||||
add_prevented_cert_override_test("inadequate-key-size-ee.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
SSL_ERROR_WEAK_SERVER_CERT_KEY);
|
||||
|
||||
add_cert_override_test("ipAddressAsDNSNameInSAN.example.com",
|
||||
Ci.nsICertOverrideService.ERROR_MISMATCH,
|
||||
@ -263,13 +252,13 @@ function add_distrust_tests() {
|
||||
// Before we specifically distrust this certificate, it should be trusted.
|
||||
add_connection_test("untrusted.example.com", PRErrorCodeSuccess);
|
||||
|
||||
add_distrust_test("tlsserver/default-ee.der", "untrusted.example.com",
|
||||
add_distrust_test("tlsserver/default-ee.pem", "untrusted.example.com",
|
||||
SEC_ERROR_UNTRUSTED_CERT);
|
||||
|
||||
add_distrust_test("tlsserver/other-test-ca.der",
|
||||
add_distrust_test("tlsserver/other-test-ca.pem",
|
||||
"untrustedissuer.example.com", SEC_ERROR_UNTRUSTED_ISSUER);
|
||||
|
||||
add_distrust_test("tlsserver/test-ca.der",
|
||||
add_distrust_test("tlsserver/test-ca.pem",
|
||||
"ca-used-as-end-entity.example.com",
|
||||
SEC_ERROR_UNTRUSTED_ISSUER);
|
||||
}
|
||||
@ -283,7 +272,9 @@ function add_distrust_test(certFileName, hostName, expectedResult) {
|
||||
clearSessionCache();
|
||||
run_next_test();
|
||||
});
|
||||
add_non_overridable_test(hostName, expectedResult);
|
||||
add_prevented_cert_override_test(hostName,
|
||||
Ci.nsICertOverrideService.ERROR_UNTRUSTED,
|
||||
expectedResult);
|
||||
add_test(function () {
|
||||
setCertTrust(certToDistrust, "u,,");
|
||||
run_next_test();
|
||||
|
@ -24,7 +24,7 @@ function respondWithSHA1OCSP(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "application/ocsp-response");
|
||||
|
||||
let args = [ ["good-delegated", "localhostAndExampleCom", "delegatedSHA1Signer" ] ];
|
||||
let args = [ ["good-delegated", "default-ee", "delegatedSHA1Signer" ] ];
|
||||
let responses = generateOCSPResponses(args, "tlsserver");
|
||||
response.write(responses[0]);
|
||||
}
|
||||
@ -37,7 +37,7 @@ function respondWithError(request, response) {
|
||||
}
|
||||
|
||||
function generateGoodOCSPResponse() {
|
||||
let args = [ ["good", "localhostAndExampleCom", "unused" ] ];
|
||||
let args = [ ["good", "default-ee", "unused" ] ];
|
||||
let responses = generateOCSPResponses(args, "tlsserver");
|
||||
return responses[0];
|
||||
}
|
||||
@ -54,7 +54,7 @@ function add_ocsp_test(aHost, aExpectedResult, aResponses, aMessage) {
|
||||
// check the number of requests matches the size of aResponses
|
||||
equal(gFetchCount, aResponses.length,
|
||||
"should have made " + aResponses.length +
|
||||
" OCSP request" + aResponses.length == 1 ? "" : "s");
|
||||
" OCSP request" + (aResponses.length == 1 ? "" : "s"));
|
||||
});
|
||||
}
|
||||
|
||||
@ -134,6 +134,10 @@ function add_tests() {
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
respondWithError,
|
||||
],
|
||||
"No stapled response -> a fetch should have been attempted");
|
||||
|
||||
|
@ -16,7 +16,7 @@ function run_test() {
|
||||
// get a TLS connection.
|
||||
add_tls_server_setup("OCSPStaplingServer");
|
||||
|
||||
let args = [["good", "localhostAndExampleCom", "unused"]];
|
||||
let args = [["good", "default-ee", "unused"]];
|
||||
let ocspResponses = generateOCSPResponses(args, "tlsserver");
|
||||
let goodOCSPResponse = ocspResponses[0];
|
||||
|
||||
|
@ -20,7 +20,7 @@ function run_test() {
|
||||
// get a TLS connection.
|
||||
add_tls_server_setup("OCSPStaplingServer");
|
||||
|
||||
let args = [["bad-signature", "localhostAndExampleCom", "unused"]];
|
||||
let args = [["bad-signature", "default-ee", "unused"]];
|
||||
let ocspResponses = generateOCSPResponses(args, "tlsserver");
|
||||
let ocspResponseBadSignature = ocspResponses[0];
|
||||
|
||||
|
@ -21,7 +21,7 @@ function add_ocsp_test(aHost, aExpectedResult, aStaplingEnabled) {
|
||||
});
|
||||
}
|
||||
|
||||
function add_tests(certDB, otherTestCA) {
|
||||
function add_tests() {
|
||||
// In the absence of OCSP stapling, these should actually all work.
|
||||
add_ocsp_test("ocsp-stapling-good.example.com",
|
||||
PRErrorCodeSuccess, false);
|
||||
@ -73,6 +73,9 @@ function add_tests(certDB, otherTestCA) {
|
||||
|
||||
// This stapled response is from a CA that is untrusted and did not issue
|
||||
// the server's certificate.
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
let otherTestCA = constructCertFromFile("tlsserver/other-test-ca.pem");
|
||||
add_test(function() {
|
||||
certDB.setCertTrust(otherTestCA, Ci.nsIX509Cert.CA_CERT,
|
||||
Ci.nsIX509CertDB.UNTRUSTED);
|
||||
@ -186,11 +189,6 @@ function check_ocsp_stapling_telemetry() {
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
let otherTestCAFile = do_get_file("tlsserver/other-test-ca.der", false);
|
||||
let otherTestCADER = readFile(otherTestCAFile);
|
||||
let otherTestCA = certDB.constructX509(otherTestCADER, otherTestCADER.length);
|
||||
|
||||
let fakeOCSPResponder = new HttpServer();
|
||||
fakeOCSPResponder.registerPrefixHandler("/", function (request, response) {
|
||||
@ -202,7 +200,7 @@ function run_test() {
|
||||
|
||||
add_tls_server_setup("OCSPStaplingServer");
|
||||
|
||||
add_tests(certDB, otherTestCA);
|
||||
add_tests();
|
||||
|
||||
add_test(function () {
|
||||
fakeOCSPResponder.stop(check_ocsp_stapling_telemetry);
|
||||
|
@ -24,18 +24,18 @@ function add_ocsp_test(aHost, aExpectedResult, aOCSPResponseToServe,
|
||||
function() {
|
||||
equal(gOCSPRequestCount, aExpectedRequestCount,
|
||||
"Should have made " + aExpectedRequestCount +
|
||||
" fallback OCSP request" + aExpectedRequestCount == 1 ? "" : "s");
|
||||
" fallback OCSP request" + (aExpectedRequestCount == 1 ? "" : "s"));
|
||||
});
|
||||
}
|
||||
|
||||
do_get_profile();
|
||||
Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
|
||||
Services.prefs.setIntPref("security.OCSP.enabled", 1);
|
||||
var args = [["good", "localhostAndExampleCom", "unused"],
|
||||
["expiredresponse", "localhostAndExampleCom", "unused"],
|
||||
["oldvalidperiod", "localhostAndExampleCom", "unused"],
|
||||
["revoked", "localhostAndExampleCom", "unused"],
|
||||
["unknown", "localhostAndExampleCom", "unused"],
|
||||
var args = [["good", "default-ee", "unused"],
|
||||
["expiredresponse", "default-ee", "unused"],
|
||||
["oldvalidperiod", "default-ee", "unused"],
|
||||
["revoked", "default-ee", "unused"],
|
||||
["unknown", "default-ee", "unused"],
|
||||
];
|
||||
var ocspResponses = generateOCSPResponses(args, "tlsserver");
|
||||
// Fresh response, certificate is good.
|
||||
@ -53,9 +53,9 @@ var ocspResponseUnknown = ocspResponses[4];
|
||||
var willNotRetry = 1;
|
||||
// but sometimes, since a bad response is in the cache, OCSP fetch will be
|
||||
// attempted for each validation - in practice, for these test certs, this
|
||||
// means 4 requests because various hash algorithm combinations are tried
|
||||
// (for sha-1 telemetry)
|
||||
var willRetry = 4;
|
||||
// means 8 requests because various hash algorithm and key size combinations
|
||||
// are tried.
|
||||
var willRetry = 8;
|
||||
|
||||
function run_test() {
|
||||
let ocspResponder = new HttpServer();
|
||||
|
@ -249,7 +249,7 @@ function run_test() {
|
||||
add_tls_server_setup("BadCertServer");
|
||||
|
||||
// Add a user-specified trust anchor.
|
||||
addCertFromFile(certdb, "tlsserver/other-test-ca.der", "CTu,u,u");
|
||||
addCertFromFile(certdb, "tlsserver/other-test-ca.pem", "CTu,u,u");
|
||||
|
||||
test_strict();
|
||||
test_mitm();
|
||||
|
@ -0,0 +1,3 @@
|
||||
issuer:Test CA
|
||||
subject:EE with bad subjectAltNames
|
||||
extension:subjectAlternativeName:*.*.example.com
|
@ -0,0 +1,5 @@
|
||||
issuer:Test CA
|
||||
subject:Before UNIX Epoch Test End-entity
|
||||
validity:19460214-20310101
|
||||
extension:subjectAlternativeName:before-epoch.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,5 @@
|
||||
issuer:Test CA
|
||||
subject:Before UNIX Epoch Test Intermediate
|
||||
validity:19460214-20310101
|
||||
extension:basicConstraints:cA,
|
||||
extension:keyUsage:cRLSign,keyCertSign
|
@ -0,0 +1,4 @@
|
||||
issuer:Before UNIX Epoch Test Intermediate
|
||||
subject:Test End-entity with Before UNIX Epoch issuer
|
||||
extension:subjectAlternativeName:before-epoch-issuer.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,5 @@
|
||||
issuer:Test CA
|
||||
subject:Test Intermediate used as End-Entity
|
||||
extension:basicConstraints:cA,
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
||||
extension:subjectAlternativeName:ca-used-as-end-entity.example.com
|
Binary file not shown.
@ -27,7 +27,7 @@ struct BadCertHost
|
||||
// Hostname, cert nickname pairs.
|
||||
const BadCertHost sBadCertHosts[] =
|
||||
{
|
||||
{ "expired.example.com", "expired" },
|
||||
{ "expired.example.com", "expired-ee" },
|
||||
{ "notyetvalid.example.com", "notYetValid" },
|
||||
{ "before-epoch.example.com", "beforeEpoch" },
|
||||
{ "selfsigned.example.com", "selfsigned" },
|
||||
@ -38,7 +38,7 @@ const BadCertHost sBadCertHosts[] =
|
||||
{ "notyetvalidissuer.example.com", "notYetValidIssuer" },
|
||||
{ "before-epoch-issuer.example.com", "beforeEpochIssuer" },
|
||||
{ "md5signature.example.com", "md5signature" },
|
||||
{ "untrusted.example.com", "localhostAndExampleCom" },
|
||||
{ "untrusted.example.com", "default-ee" },
|
||||
{ "untrustedissuer.example.com", "untrustedissuer" },
|
||||
{ "mismatch-expired.example.com", "mismatch-expired" },
|
||||
{ "mismatch-notYetValid.example.com", "mismatch-notYetValid" },
|
||||
@ -46,23 +46,23 @@ const BadCertHost sBadCertHosts[] =
|
||||
{ "untrusted-expired.example.com", "untrusted-expired" },
|
||||
{ "md5signature-expired.example.com", "md5signature-expired" },
|
||||
{ "mismatch-untrusted-expired.example.com", "mismatch-untrusted-expired" },
|
||||
{ "inadequatekeyusage.example.com", "inadequatekeyusage" },
|
||||
{ "inadequatekeyusage.example.com", "inadequatekeyusage-ee" },
|
||||
{ "selfsigned-inadequateEKU.example.com", "selfsigned-inadequateEKU" },
|
||||
{ "self-signed-end-entity-with-cA-true.example.com", "self-signed-EE-with-cA-true" },
|
||||
{ "ca-used-as-end-entity.example.com", "ca-used-as-end-entity" },
|
||||
{ "ca-used-as-end-entity-name-mismatch.example.com", "ca-used-as-end-entity" },
|
||||
// All of include-subdomains.pinning.example.com is pinned to End Entity
|
||||
// Test Cert with nick localhostAndExampleCom. Any other nick will only
|
||||
// Test Cert with nick default-ee. Any other nick will only
|
||||
// pass pinning when security.cert_pinning.enforcement.level != strict and
|
||||
// otherCA is added as a user-specified trust anchor. See StaticHPKPins.h.
|
||||
{ "include-subdomains.pinning.example.com", "localhostAndExampleCom" },
|
||||
{ "good.include-subdomains.pinning.example.com", "localhostAndExampleCom" },
|
||||
{ "bad.include-subdomains.pinning.example.com", "otherIssuerEE" },
|
||||
{ "bad.include-subdomains.pinning.example.com.", "otherIssuerEE" },
|
||||
{ "bad.include-subdomains.pinning.example.com..", "otherIssuerEE" },
|
||||
{ "exclude-subdomains.pinning.example.com", "localhostAndExampleCom" },
|
||||
{ "sub.exclude-subdomains.pinning.example.com", "otherIssuerEE" },
|
||||
{ "test-mode.pinning.example.com", "otherIssuerEE" },
|
||||
{ "include-subdomains.pinning.example.com", "default-ee" },
|
||||
{ "good.include-subdomains.pinning.example.com", "default-ee" },
|
||||
{ "bad.include-subdomains.pinning.example.com", "other-issuer-ee" },
|
||||
{ "bad.include-subdomains.pinning.example.com.", "other-issuer-ee" },
|
||||
{ "bad.include-subdomains.pinning.example.com..", "other-issuer-ee" },
|
||||
{ "exclude-subdomains.pinning.example.com", "default-ee" },
|
||||
{ "sub.exclude-subdomains.pinning.example.com", "other-issuer-ee" },
|
||||
{ "test-mode.pinning.example.com", "other-issuer-ee" },
|
||||
{ "unknownissuer.include-subdomains.pinning.example.com", "unknownissuer" },
|
||||
{ "unknownissuer.test-mode.pinning.example.com", "unknownissuer" },
|
||||
{ "nsCertTypeNotCritical.example.com", "nsCertTypeNotCritical" },
|
||||
@ -78,13 +78,37 @@ const BadCertHost sBadCertHosts[] =
|
||||
};
|
||||
|
||||
int32_t
|
||||
DoSNISocketConfig(PRFileDesc *aFd, const SECItem *aSrvNameArr,
|
||||
uint32_t aSrvNameArrSize, void *aArg)
|
||||
DoSNISocketConfigBySubjectCN(PRFileDesc* aFd, const SECItem* aSrvNameArr,
|
||||
uint32_t aSrvNameArrSize)
|
||||
{
|
||||
const BadCertHost *host = GetHostForSNI(aSrvNameArr, aSrvNameArrSize,
|
||||
for (uint32_t i = 0; i < aSrvNameArrSize; i++) {
|
||||
ScopedPORTString name((char*)PORT_ZAlloc(aSrvNameArr[i].len + 1));
|
||||
if (name) {
|
||||
PORT_Memcpy(name, aSrvNameArr[i].data, aSrvNameArr[i].len);
|
||||
if (SECSuccess == ConfigSecureServerWithNamedCert(aFd, name,
|
||||
nullptr, nullptr)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SSL_SNI_SEND_ALERT;
|
||||
}
|
||||
|
||||
int32_t
|
||||
DoSNISocketConfig(PRFileDesc* aFd, const SECItem* aSrvNameArr,
|
||||
uint32_t aSrvNameArrSize, void* aArg)
|
||||
{
|
||||
const BadCertHost* host = GetHostForSNI(aSrvNameArr, aSrvNameArrSize,
|
||||
sBadCertHosts);
|
||||
if (!host) {
|
||||
return SSL_SNI_SEND_ALERT;
|
||||
// No static cert <-> hostname mapping found. This happens when we use a
|
||||
// collection of certificates in a given directory and build a cert DB at
|
||||
// runtime, rather than using an NSS cert DB populated at build time.
|
||||
// (This will be the default in the future.)
|
||||
// For all given server names, check if the runtime-built cert DB contains
|
||||
// a certificate with a matching subject CN.
|
||||
return DoSNISocketConfigBySubjectCN(aFd, aSrvNameArr, aSrvNameArrSize);
|
||||
}
|
||||
|
||||
if (gDebugLevel >= DEBUG_VERBOSE) {
|
||||
|
@ -110,219 +110,6 @@ WriteResponse(const char* filename, const SECItem* item)
|
||||
return true;
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
SECStatus
|
||||
ReadFileToBuffer(const char* basePath, const char* filename, char (&buf)[N])
|
||||
{
|
||||
static_assert(N > 0, "input buffer too small for ReadFileToBuffer");
|
||||
if (PR_snprintf(buf, N - 1, "%s/%s", basePath, filename) == 0) {
|
||||
PrintPRError("PR_snprintf failed");
|
||||
return SECFailure;
|
||||
}
|
||||
ScopedPRFileDesc fd(PR_OpenFile(buf, PR_RDONLY, 0));
|
||||
if (!fd) {
|
||||
PrintPRError("PR_Open failed");
|
||||
return SECFailure;
|
||||
}
|
||||
int32_t fileSize = PR_Available(fd);
|
||||
if (fileSize < 0) {
|
||||
PrintPRError("PR_Available failed");
|
||||
return SECFailure;
|
||||
}
|
||||
if (static_cast<size_t>(fileSize) > N - 1) {
|
||||
PR_fprintf(PR_STDERR, "file too large - not reading\n");
|
||||
return SECFailure;
|
||||
}
|
||||
int32_t bytesRead = PR_Read(fd, buf, fileSize);
|
||||
if (bytesRead != fileSize) {
|
||||
PrintPRError("PR_Read failed");
|
||||
return SECFailure;
|
||||
}
|
||||
buf[bytesRead] = 0;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRDir, PRDir, PR_CloseDir);
|
||||
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPORTString, unsigned char, PORT_Free);
|
||||
|
||||
};
|
||||
|
||||
void
|
||||
AddKeyFromFile(const char* basePath, const char* filename)
|
||||
{
|
||||
const char* PRIVATE_KEY_HEADER = "-----BEGIN PRIVATE KEY-----";
|
||||
const char* PRIVATE_KEY_FOOTER = "-----END PRIVATE KEY-----";
|
||||
|
||||
char buf[16384] = { 0 };
|
||||
SECStatus rv = ReadFileToBuffer(basePath, filename, buf);
|
||||
if (rv != SECSuccess) {
|
||||
return;
|
||||
}
|
||||
if (strncmp(buf, PRIVATE_KEY_HEADER, strlen(PRIVATE_KEY_HEADER)) != 0) {
|
||||
PR_fprintf(PR_STDERR, "invalid key - not importing\n");
|
||||
return;
|
||||
}
|
||||
const char* bufPtr = buf + strlen(PRIVATE_KEY_HEADER);
|
||||
size_t bufLen = strlen(buf);
|
||||
char base64[16384] = { 0 };
|
||||
char* base64Ptr = base64;
|
||||
while (bufPtr < buf + bufLen) {
|
||||
if (strncmp(bufPtr, PRIVATE_KEY_FOOTER, strlen(PRIVATE_KEY_FOOTER)) == 0) {
|
||||
break;
|
||||
}
|
||||
if (*bufPtr != '\r' && *bufPtr != '\n') {
|
||||
*base64Ptr = *bufPtr;
|
||||
base64Ptr++;
|
||||
}
|
||||
bufPtr++;
|
||||
}
|
||||
|
||||
unsigned int binLength;
|
||||
ScopedPORTString bin(ATOB_AsciiToData(base64, &binLength));
|
||||
if (!bin || binLength == 0) {
|
||||
PrintPRError("ATOB_AsciiToData failed");
|
||||
return;
|
||||
}
|
||||
ScopedSECItem secitem(SECITEM_AllocItem(nullptr, nullptr, binLength));
|
||||
if (!secitem) {
|
||||
PrintPRError("SECITEM_AllocItem failed");
|
||||
return;
|
||||
}
|
||||
memcpy(secitem->data, bin, binLength);
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
if (!slot) {
|
||||
PrintPRError("PK11_GetInternalKeySlot failed");
|
||||
return;
|
||||
}
|
||||
if (PK11_NeedUserInit(slot)) {
|
||||
if (PK11_InitPin(slot, nullptr, nullptr) != SECSuccess) {
|
||||
PrintPRError("PK11_InitPin failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
SECKEYPrivateKey* privateKey;
|
||||
if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, secitem, nullptr, nullptr,
|
||||
true, false, KU_ALL,
|
||||
&privateKey, nullptr)
|
||||
!= SECSuccess) {
|
||||
PrintPRError("PK11_ImportDERPrivateKeyInfoAndReturnKey failed");
|
||||
return;
|
||||
}
|
||||
SECKEY_DestroyPrivateKey(privateKey);
|
||||
}
|
||||
|
||||
SECStatus
|
||||
DecodeCertCallback(void* arg, SECItem** certs, int numcerts)
|
||||
{
|
||||
if (numcerts != 1) {
|
||||
PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
SECItem* certDEROut = static_cast<SECItem*>(arg);
|
||||
return SECITEM_CopyItem(nullptr, certDEROut, *certs);
|
||||
}
|
||||
|
||||
void
|
||||
AddCertificateFromFile(const char* basePath, const char* filename)
|
||||
{
|
||||
char buf[16384] = { 0 };
|
||||
SECStatus rv = ReadFileToBuffer(basePath, filename, buf);
|
||||
if (rv != SECSuccess) {
|
||||
return;
|
||||
}
|
||||
SECItem certDER;
|
||||
rv = CERT_DecodeCertPackage(buf, strlen(buf), DecodeCertCallback, &certDER);
|
||||
if (rv != SECSuccess) {
|
||||
PrintPRError("CERT_DecodeCertPackage failed");
|
||||
return;
|
||||
}
|
||||
ScopedCERTCertificate cert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
|
||||
&certDER, nullptr, false,
|
||||
true));
|
||||
PORT_Free(certDER.data);
|
||||
if (!cert) {
|
||||
PrintPRError("CERT_NewTempCertificate failed");
|
||||
return;
|
||||
}
|
||||
const char* extension = strstr(filename, ".pem");
|
||||
if (!extension) {
|
||||
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
|
||||
return;
|
||||
}
|
||||
size_t nicknameLength = extension - filename;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memcpy(buf, filename, nicknameLength);
|
||||
buf[nicknameLength] = 0;
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
if (!slot) {
|
||||
PrintPRError("PK11_GetInternalKeySlot failed");
|
||||
return;
|
||||
}
|
||||
rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, buf, false);
|
||||
if (rv != SECSuccess) {
|
||||
PrintPRError("PK11_ImportCert failed");
|
||||
}
|
||||
}
|
||||
|
||||
SECStatus
|
||||
InitializeNSS(const char* nssCertDBDir)
|
||||
{
|
||||
// First attempt to initialize NSS in read-only mode, in case the specified
|
||||
// directory contains NSS DBs that are tracked by revision control.
|
||||
// If this succeeds, we're done.
|
||||
if (NSS_Initialize(nssCertDBDir, "", "", SECMOD_DB, NSS_INIT_READONLY)
|
||||
== SECSuccess) {
|
||||
return SECSuccess;
|
||||
}
|
||||
// Otherwise, create a new read-write DB and load all .pem and .key files.
|
||||
if (NSS_Initialize(nssCertDBDir, "", "", SECMOD_DB, 0) != SECSuccess) {
|
||||
PrintPRError("NSS_Initialize failed");
|
||||
return SECFailure;
|
||||
}
|
||||
const char* basePath = nssCertDBDir;
|
||||
// The NSS cert DB path could have been specified as "sql:path". Trim off
|
||||
// the leading "sql:" if so.
|
||||
if (strncmp(basePath, "sql:", 4) == 0) {
|
||||
basePath = basePath + 4;
|
||||
}
|
||||
ScopedPRDir fdDir(PR_OpenDir(basePath));
|
||||
if (!fdDir) {
|
||||
PrintPRError("PR_OpenDir failed");
|
||||
return SECFailure;
|
||||
}
|
||||
// On the B2G ICS emulator, operations taken in AddCertificateFromFile or
|
||||
// AddKeyFromFile appear to interact poorly with readdir (more specifically,
|
||||
// something is causing readdir to never return null - it indefinitely loops
|
||||
// through every file in the directory, which causes timeouts). Rather than
|
||||
// waste more time chasing this down, loading certificates and keys happens in
|
||||
// two phases: filename collection and then loading. (This is probably a good
|
||||
// idea anyway because readdir isn't reentrant. Something could change later
|
||||
// such that it gets called as a result of calling AddCertificateFromFile or
|
||||
// AddKeyFromFile.)
|
||||
std::vector<std::string> certificates;
|
||||
std::vector<std::string> keys;
|
||||
for (PRDirEntry* dirEntry = PR_ReadDir(fdDir, PR_SKIP_BOTH); dirEntry;
|
||||
dirEntry = PR_ReadDir(fdDir, PR_SKIP_BOTH)) {
|
||||
size_t nameLength = strlen(dirEntry->name);
|
||||
if (nameLength > 4) {
|
||||
if (strncmp(dirEntry->name + nameLength - 4, ".pem", 4) == 0) {
|
||||
certificates.push_back(dirEntry->name);
|
||||
} else if (strncmp(dirEntry->name + nameLength - 4, ".key", 4) == 0) {
|
||||
keys.push_back(dirEntry->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (std::string& certificate : certificates) {
|
||||
AddCertificateFromFile(basePath, certificate.c_str());
|
||||
}
|
||||
for (std::string& key : keys) {
|
||||
AddKeyFromFile(basePath, key.c_str());
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ const OCSPHost sOCSPHosts[] =
|
||||
{ "ocsp-stapling-unknown.example.com", ORTUnknown, nullptr },
|
||||
{ "ocsp-stapling-unknown-old.example.com", ORTUnknownOld, nullptr },
|
||||
{ "ocsp-stapling-good-other.example.com", ORTGoodOtherCert, "ocspOtherEndEntity" },
|
||||
{ "ocsp-stapling-good-other-ca.example.com", ORTGoodOtherCA, "otherCA" },
|
||||
{ "ocsp-stapling-good-other-ca.example.com", ORTGoodOtherCA, "other-test-ca" },
|
||||
{ "ocsp-stapling-expired.example.com", ORTExpired, nullptr },
|
||||
{ "ocsp-stapling-expired-fresh-ca.example.com", ORTExpiredFreshCA, nullptr },
|
||||
{ "ocsp-stapling-none.example.com", ORTNone, nullptr },
|
||||
@ -52,7 +52,7 @@ const OCSPHost sOCSPHosts[] =
|
||||
{ "ocsp-stapling-delegated-keyUsage-crlSigning.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerKeyUsageCrlSigning" },
|
||||
{ "ocsp-stapling-delegated-wrong-extKeyUsage.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerWrongExtKeyUsage" },
|
||||
{ "ocsp-stapling-ancient-valid.example.com", ORTAncientAlmostExpired, nullptr},
|
||||
{ "keysize-ocsp-delegated.example.com", ORTDelegatedIncluded, "rsa-1008-keysizeDelegatedSigner" },
|
||||
{ "keysize-ocsp-delegated.example.com", ORTDelegatedIncluded, "rsa-1016-keysizeDelegatedSigner" },
|
||||
{ "revoked-ca-cert-used-as-end-entity.example.com", ORTRevoked, "ca-used-as-end-entity" },
|
||||
{ nullptr, ORTNull, nullptr }
|
||||
};
|
||||
|
Binary file not shown.
@ -0,0 +1 @@
|
||||
default
|
@ -0,0 +1,4 @@
|
||||
issuer:Test CA
|
||||
subject:Test End-entity
|
||||
extension:subjectAlternativeName:localhost,*.example.com,*.pinning.example.com,*.include-subdomains.pinning.example.com,*.exclude-subdomains.pinning.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,5 @@
|
||||
issuer:Test CA
|
||||
subject:Test SHA1 Delegated Responder
|
||||
subjectKey:alternate
|
||||
signature:sha1WithRSAEncryption
|
||||
extension:extKeyUsage:OCSPSigning
|
@ -0,0 +1,4 @@
|
||||
issuer:Test CA
|
||||
subject:Test Delegated Responder
|
||||
subjectKey:alternate
|
||||
extension:extKeyUsage:OCSPSigning
|
@ -0,0 +1,4 @@
|
||||
issuer:Test End-entity
|
||||
subject:EE Issued by non-CA
|
||||
extension:subjectAlternativeName:localhost,*.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,3 @@
|
||||
issuer:V1 Cert
|
||||
subject:EE Issued by V1 Cert
|
||||
extension:subjectAlternativeName:localhost,*.example.com
|
Binary file not shown.
@ -0,0 +1,5 @@
|
||||
issuer:Test CA
|
||||
subject:Expired Test End-entity
|
||||
validity:20130101-20140101
|
||||
extension:subjectAlternativeName:expired.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,5 @@
|
||||
issuer:Test CA
|
||||
subject:Expired Test Intermediate
|
||||
validity:20110101-20130101
|
||||
extension:basicConstraints:cA,
|
||||
extension:keyUsage:cRLSign,keyCertSign
|
@ -0,0 +1,4 @@
|
||||
issuer:Expired Test Intermediate
|
||||
subject:Test End-entity with expired issuer
|
||||
extension:subjectAlternativeName:expiredissuer.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -1,354 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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/.
|
||||
#
|
||||
# Usage: ./generate_certs.sh <path to objdir> <output directory> [--clobber]
|
||||
# e.g. (from the root of mozilla-central)
|
||||
# `./security/manager/ssl/tests/unit/tlsserver/generate_certs.sh \
|
||||
# obj-x86_64-unknown-linux-gnu/ \
|
||||
# security/manager/ssl/tests/unit/tlsserver/`
|
||||
#
|
||||
# The --clobber switch is optional. If specified, the existing database of
|
||||
# keys and certificates is removed and repopulated. By default, existing
|
||||
# databases are preserved and only keys and certificates that don't already
|
||||
# exist in the database are added.
|
||||
# NB: If --clobber is specified, the following files to be overwritten if they
|
||||
# are in the output directory:
|
||||
# cert9.db, key4.db, pkcs11.txt, test-ca.der, other-test-ca.der, default-ee.der
|
||||
# (if --clobber is not specified, then only cert9.db and key4.db are modified)
|
||||
# NB: If --clobber is specified, you must run genHPKPStaticPins.js after
|
||||
# running this file, since its output (StaticHPKPins.h) depends on
|
||||
# default-ee.der
|
||||
|
||||
set -x
|
||||
set -e
|
||||
|
||||
if [ $# -lt 2 ]; then
|
||||
echo "Usage: `basename ${0}` <path to objdir> <output directory> [--clobber]"
|
||||
exit $E_BADARGS
|
||||
fi
|
||||
|
||||
OBJDIR=${1}
|
||||
OUTPUT_DIR=${2}
|
||||
CLOBBER=0
|
||||
if [ "${3}" == "--clobber" ]; then
|
||||
CLOBBER=1
|
||||
fi
|
||||
# Use the SQL DB so we can run tests on Android.
|
||||
DB_ARGUMENT="sql:$OUTPUT_DIR"
|
||||
RUN_MOZILLA="$OBJDIR/dist/bin/run-mozilla.sh"
|
||||
CERTUTIL="$OBJDIR/dist/bin/certutil"
|
||||
# On BSD, mktemp requires either a template or a prefix.
|
||||
MKTEMP="mktemp temp.XXXX"
|
||||
|
||||
NOISE_FILE=`$MKTEMP`
|
||||
# Make a good effort at putting something unique in the noise file.
|
||||
date +%s%N > "$NOISE_FILE"
|
||||
PASSWORD_FILE=`$MKTEMP`
|
||||
|
||||
function cleanup {
|
||||
rm -f "$NOISE_FILE" "$PASSWORD_FILE"
|
||||
}
|
||||
|
||||
if [ ! -f "$RUN_MOZILLA" ]; then
|
||||
echo "Could not find run-mozilla.sh at \'$RUN_MOZILLA\' - I'll try without it"
|
||||
RUN_MOZILLA=""
|
||||
fi
|
||||
|
||||
if [ ! -f "$CERTUTIL" ]; then
|
||||
echo "Could not find certutil at \'$CERTUTIL\'"
|
||||
exit $E_BADARGS
|
||||
fi
|
||||
|
||||
if [ ! -d "$OUTPUT_DIR" ]; then
|
||||
echo "Could not find output directory at \'$OUTPUT_DIR\'"
|
||||
exit $E_BADARGS
|
||||
fi
|
||||
|
||||
if [ -f "$OUTPUT_DIR/cert9.db" -o -f "$OUTPUT_DIR/key4.db" -o -f "$OUTPUT_DIR/pkcs11.txt" ]; then
|
||||
if [ $CLOBBER -eq 1 ]; then
|
||||
echo "Found pre-existing NSS DBs. Clobbering old certificates."
|
||||
rm -f "$OUTPUT_DIR/cert9.db" "$OUTPUT_DIR/key4.db" "$OUTPUT_DIR/pkcs11.txt"
|
||||
$RUN_MOZILLA $CERTUTIL -d $DB_ARGUMENT -N -f $PASSWORD_FILE
|
||||
else
|
||||
echo "Found pre-existing NSS DBs. Only generating newly added certificates."
|
||||
echo "(re-run with --clobber to remove and regenerate old certificates)"
|
||||
fi
|
||||
else
|
||||
echo "No pre-existing NSS DBs found. Creating new ones."
|
||||
$RUN_MOZILLA $CERTUTIL -d $DB_ARGUMENT -N -f $PASSWORD_FILE
|
||||
fi
|
||||
|
||||
COMMON_ARGS="-v 360 -w -1 -2 -z $NOISE_FILE"
|
||||
|
||||
function export_cert {
|
||||
NICKNAME="${1}"
|
||||
DERFILE="${2}"
|
||||
|
||||
$RUN_MOZILLA $CERTUTIL -d $DB_ARGUMENT -L -n $NICKNAME -r > $OUTPUT_DIR/$DERFILE
|
||||
}
|
||||
|
||||
# Bash doesn't actually allow return values in a sane way, so just use a
|
||||
# global variable.
|
||||
function cert_already_exists {
|
||||
NICKNAME="${1}"
|
||||
ALREADY_EXISTS=1
|
||||
$RUN_MOZILLA $CERTUTIL -d $DB_ARGUMENT -L -n $NICKNAME || ALREADY_EXISTS=0
|
||||
}
|
||||
|
||||
function make_CA {
|
||||
CA_RESPONSES="y\n1\ny"
|
||||
NICKNAME="${1}"
|
||||
SUBJECT="${2}"
|
||||
DERFILE="${3}"
|
||||
|
||||
cert_already_exists $NICKNAME
|
||||
if [ $ALREADY_EXISTS -eq 1 ]; then
|
||||
echo "cert \"$NICKNAME\" already exists - not regenerating it (use --clobber to force regeneration)"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "$CA_RESPONSES" | $RUN_MOZILLA $CERTUTIL -d $DB_ARGUMENT -S \
|
||||
-n $NICKNAME \
|
||||
-s "$SUBJECT" \
|
||||
-t "CT,," \
|
||||
-x $COMMON_ARGS
|
||||
export_cert $NICKNAME $DERFILE
|
||||
}
|
||||
|
||||
SERIALNO=$RANDOM
|
||||
|
||||
function make_INT {
|
||||
INT_RESPONSES="y\n0\ny\n2\n7\nhttp://localhost:8888/\n\nn\nn\n"
|
||||
NICKNAME="${1}"
|
||||
SUBJECT="${2}"
|
||||
CA="${3}"
|
||||
EXTRA_ARGS="${4}"
|
||||
|
||||
cert_already_exists $NICKNAME
|
||||
if [ $ALREADY_EXISTS -eq 1 ]; then
|
||||
echo "cert \"$NICKNAME\" already exists - not regenerating it (use --clobber to force regeneration)"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "$INT_RESPONSES" | $RUN_MOZILLA $CERTUTIL -d $DB_ARGUMENT -S \
|
||||
-n $NICKNAME \
|
||||
-s "$SUBJECT" \
|
||||
-c $CA \
|
||||
-t ",," \
|
||||
-m $SERIALNO \
|
||||
--extAIA \
|
||||
$COMMON_ARGS \
|
||||
$EXTRA_ARGS
|
||||
SERIALNO=$(($SERIALNO + 1))
|
||||
}
|
||||
|
||||
# This creates an X.509 version 1 certificate (note --certVersion 1 and a lack
|
||||
# of extensions).
|
||||
function make_V1 {
|
||||
NICKNAME="${1}"
|
||||
SUBJECT="${2}"
|
||||
CA="${3}"
|
||||
|
||||
cert_already_exists $NICKNAME
|
||||
if [ $ALREADY_EXISTS -eq 1 ]; then
|
||||
echo "cert \"$NICKNAME\" already exists - not regenerating it (use --clobber to force regeneration)"
|
||||
return
|
||||
fi
|
||||
|
||||
$RUN_MOZILLA $CERTUTIL -d $DB_ARGUMENT -S \
|
||||
-n $NICKNAME \
|
||||
-s "$SUBJECT" \
|
||||
-c $CA \
|
||||
-t ",," \
|
||||
-m $SERIALNO \
|
||||
--certVersion 1 \
|
||||
-v 360 -w -1 -z $NOISE_FILE
|
||||
|
||||
SERIALNO=$(($SERIALNO + 1))
|
||||
}
|
||||
|
||||
function make_EE {
|
||||
CERT_RESPONSES="n\n\ny\n2\n7\nhttp://localhost:8888/\n\nn\nn\n"
|
||||
NICKNAME="${1}"
|
||||
SUBJECT="${2}"
|
||||
CA="${3}"
|
||||
SUBJECT_ALT_NAME="${4}"
|
||||
EXTRA_ARGS="${5} ${6}"
|
||||
|
||||
[ -z "$SUBJECT_ALT_NAME" ] && SUBJECT_ALT_NAME_PART="" || SUBJECT_ALT_NAME_PART="-8 $SUBJECT_ALT_NAME"
|
||||
|
||||
cert_already_exists $NICKNAME
|
||||
if [ $ALREADY_EXISTS -eq 1 ]; then
|
||||
echo "cert \"$NICKNAME\" already exists - not regenerating it (use --clobber to force regeneration)"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "$CERT_RESPONSES" | $RUN_MOZILLA $CERTUTIL -d $DB_ARGUMENT -S \
|
||||
-n $NICKNAME \
|
||||
-s "$SUBJECT" \
|
||||
$SUBJECT_ALT_NAME_PART \
|
||||
-c $CA \
|
||||
-t ",," \
|
||||
-m $SERIALNO \
|
||||
--extAIA \
|
||||
$COMMON_ARGS \
|
||||
$EXTRA_ARGS
|
||||
SERIALNO=$(($SERIALNO + 1))
|
||||
}
|
||||
|
||||
function make_EE_with_nsCertType {
|
||||
NICKNAME="${1}"
|
||||
SUBJECT="${2}"
|
||||
CA="${3}"
|
||||
SUBJECT_ALT_NAME="${4}"
|
||||
NS_CERT_TYPE_CRITICAL="${5}"
|
||||
EXTRA_ARGS="${6}"
|
||||
# This adds the Netscape certificate type extension with the "sslServer"
|
||||
# bit asserted. Its criticality depends on if "y" or "n" was passed as
|
||||
# an argument to this function.
|
||||
CERT_RESPONSES="n\n\ny\n1\n8\n$NS_CERT_TYPE_CRITICAL\n"
|
||||
|
||||
cert_already_exists $NICKNAME
|
||||
if [ $ALREADY_EXISTS -eq 1 ]; then
|
||||
echo "cert \"$NICKNAME\" already exists - not regenerating it (use --clobber to force regeneration)"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "$CERT_RESPONSES" | $RUN_MOZILLA $CERTUTIL -d $DB_ARGUMENT -S \
|
||||
-n $NICKNAME \
|
||||
-s "$SUBJECT" \
|
||||
-8 $SUBJECT_ALT_NAME \
|
||||
-c $CA \
|
||||
-t ",," \
|
||||
-m $SERIALNO \
|
||||
-5 \
|
||||
$COMMON_ARGS \
|
||||
$EXTRA_ARGS
|
||||
SERIALNO=$(($SERIALNO + 1))
|
||||
}
|
||||
|
||||
function make_delegated {
|
||||
CERT_RESPONSES="n\n\ny\n"
|
||||
NICKNAME="${1}"
|
||||
SUBJECT="${2}"
|
||||
CA="${3}"
|
||||
EXTRA_ARGS="${4}"
|
||||
|
||||
cert_already_exists $NICKNAME
|
||||
if [ $ALREADY_EXISTS -eq 1 ]; then
|
||||
echo "cert \"$NICKNAME\" already exists - not regenerating it (use --clobber to force regeneration)"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "$CERT_RESPONSES" | $RUN_MOZILLA $CERTUTIL -d $DB_ARGUMENT -S \
|
||||
-n $NICKNAME \
|
||||
-s "$SUBJECT" \
|
||||
-c $CA \
|
||||
-t ",," \
|
||||
-m $SERIALNO \
|
||||
$COMMON_ARGS \
|
||||
$EXTRA_ARGS
|
||||
SERIALNO=$(($SERIALNO + 1))
|
||||
}
|
||||
|
||||
make_CA testCA 'CN=Test CA' test-ca.der
|
||||
make_CA otherCA 'CN=Other test CA' other-test-ca.der
|
||||
|
||||
make_EE localhostAndExampleCom 'CN=Test End-entity' testCA "localhost,*.example.com,*.pinning.example.com,*.include-subdomains.pinning.example.com,*.exclude-subdomains.pinning.example.com"
|
||||
# Make another EE cert using testCA for subject / pubkey revocation
|
||||
make_EE sameIssuerEE 'CN=Another Test End-entity' testCA "localhost,*.example.com"
|
||||
# Make an EE cert issued by otherCA
|
||||
make_EE otherIssuerEE 'CN=Wrong CA Pin Test End-Entity' otherCA "*.include-subdomains.pinning.example.com,*.exclude-subdomains.pinning.example.com,*.pinning.example.com"
|
||||
|
||||
export_cert localhostAndExampleCom default-ee.der
|
||||
export_cert sameIssuerEE same-issuer-ee.der
|
||||
export_cert otherIssuerEE other-issuer-ee.der
|
||||
|
||||
# A cert that is like localhostAndExampleCom, but with a different serial number for
|
||||
# testing the "OCSP response is from the right issuer, but it is for the wrong cert"
|
||||
# case.
|
||||
make_EE ocspOtherEndEntity 'CN=Other Cert' testCA "localhost,*.example.com"
|
||||
|
||||
make_INT testINT 'CN=Test Intermediate' testCA
|
||||
export_cert testINT test-int.der
|
||||
make_EE ocspEEWithIntermediate 'CN=Test End-entity with Intermediate' testINT "localhost,*.example.com"
|
||||
make_EE expired 'CN=Expired Test End-entity' testCA "expired.example.com" "-w -400"
|
||||
export_cert expired expired-ee.der
|
||||
make_EE notYetValid 'CN=Not Yet Valid Test End-entity' testCA "notyetvalid.example.com" "-w 400"
|
||||
make_EE mismatch 'CN=Mismatch Test End-entity' testCA "doesntmatch.example.com,*.alsodoesntmatch.example.com"
|
||||
make_EE mismatchCN 'CN=doesntmatch.example.com' testCA
|
||||
make_EE ipAddressAsDNSNameInSAN 'CN=127.0.0.1' testCA "127.0.0.1"
|
||||
make_EE noValidNames 'CN=End-entity with no valid names' testCA
|
||||
make_EE selfsigned 'CN=Self-signed Test End-entity' testCA "selfsigned.example.com" "-x"
|
||||
# If the certificate 'CN=Test Intermediate' isn't loaded into memory,
|
||||
# this certificate will have an unknown issuer.
|
||||
# deletedINT is never kept in the database, so it always gets regenerated.
|
||||
# That's ok, because if unknownissuer was already in the database, it won't
|
||||
# get regenerated. Either way, deletedINT will then be removed again.
|
||||
make_INT deletedINT 'CN=Test Intermediate to delete' testCA
|
||||
make_EE unknownissuer 'CN=Test End-entity from unknown issuer' deletedINT "unknownissuer.example.com,unknownissuer.include-subdomains.pinning.example.com,unknownissuer.test-mode.pinning.example.com"
|
||||
export_cert unknownissuer unknown-issuer.der
|
||||
|
||||
$RUN_MOZILLA $CERTUTIL -d $DB_ARGUMENT -D -n deletedINT
|
||||
|
||||
# certutil doesn't expose a way to directly specify a notBefore time.
|
||||
# Workaround this by just providing a large enough warp that the notBefore time
|
||||
# falls before the UNIX Epoch.
|
||||
make_EE beforeEpoch 'CN=Before UNIX Epoch Test End-entity' testCA "before-epoch.example.com" "-w -720 -v 960"
|
||||
make_INT beforeEpochINT 'CN=Before UNIX Epoch Test Intermediate' testCA "-w -720 -v 960"
|
||||
make_EE beforeEpochIssuer 'CN=Test End-entity with Before UNIX Epoch issuer' beforeEpochINT "before-epoch-issuer.example.com"
|
||||
|
||||
make_INT expiredINT 'CN=Expired Test Intermediate' testCA "-w -400"
|
||||
make_EE expiredissuer 'CN=Test End-entity with expired issuer' expiredINT "expiredissuer.example.com"
|
||||
make_INT notYetValidINT 'CN=Not Yet Valid Test Intermediate' testCA "-w 400"
|
||||
make_EE notYetValidIssuer 'CN=Test End-entity with not yet valid issuer' notYetValidINT "notyetvalidissuer.example.com"
|
||||
NSS_ALLOW_WEAK_SIGNATURE_ALG=1 make_EE md5signature 'CN=Test End-entity with MD5 signature' testCA "md5signature.example.com" "-Z MD5"
|
||||
make_EE untrustedissuer 'CN=Test End-entity with untrusted issuer' otherCA "untrustedissuer.example.com"
|
||||
|
||||
make_EE mismatch-expired 'CN=Mismatch-Expired Test End-entity' testCA "doesntmatch.example.com" "-w -400"
|
||||
make_EE mismatch-notYetValid 'CN=Mismatch-Not Yet Valid Test End-entity' testCA "doesntmatch.example.com" "-w 400"
|
||||
make_EE mismatch-untrusted 'CN=Mismatch-Untrusted Test End-entity' otherCA "doesntmatch.example.com"
|
||||
make_EE untrusted-expired 'CN=Untrusted-Expired Test End-entity' otherCA "untrusted-expired.example.com" "-w -400"
|
||||
make_EE mismatch-untrusted-expired 'CN=Mismatch-Untrusted-Expired Test End-entity' otherCA "doesntmatch.example.com" "-w -400"
|
||||
NSS_ALLOW_WEAK_SIGNATURE_ALG=1 make_EE md5signature-expired 'CN=Test MD5Signature-Expired End-entity' testCA "md5signature-expired.example.com" "-Z MD5" "-w -400"
|
||||
|
||||
make_EE inadequatekeyusage 'CN=Inadequate Key Usage Test End-entity' testCA "inadequatekeyusage.example.com" "--keyUsage crlSigning"
|
||||
export_cert inadequatekeyusage inadequatekeyusage-ee.der
|
||||
make_EE selfsigned-inadequateEKU 'CN=Self-signed Inadequate EKU Test End-entity' unused "selfsigned-inadequateEKU.example.com" "--keyUsage keyEncipherment,dataEncipherment --extKeyUsage serverAuth" "-x"
|
||||
|
||||
make_delegated delegatedSigner 'CN=Test Delegated Responder' testCA "--extKeyUsage ocspResponder"
|
||||
make_delegated delegatedSHA1Signer 'CN=Test SHA1 Delegated Responder' testCA "--extKeyUsage ocspResponder -Z SHA1"
|
||||
make_delegated invalidDelegatedSignerNoExtKeyUsage 'CN=Test Invalid Delegated Responder No extKeyUsage' testCA
|
||||
make_delegated invalidDelegatedSignerFromIntermediate 'CN=Test Invalid Delegated Responder From Intermediate' testINT "--extKeyUsage ocspResponder"
|
||||
make_delegated invalidDelegatedSignerKeyUsageCrlSigning 'CN=Test Invalid Delegated Responder keyUsage crlSigning' testCA "--keyUsage crlSigning"
|
||||
make_delegated invalidDelegatedSignerWrongExtKeyUsage 'CN=Test Invalid Delegated Responder Wrong extKeyUsage' testCA "--extKeyUsage codeSigning"
|
||||
|
||||
make_INT self-signed-EE-with-cA-true 'CN=Test Self-signed End-entity with CA true' unused "-x -8 self-signed-end-entity-with-cA-true.example.com"
|
||||
make_INT ca-used-as-end-entity 'CN=Test Intermediate used as End-Entity' testCA "-8 ca-used-as-end-entity.example.com"
|
||||
|
||||
make_delegated rsa-1008-keysizeDelegatedSigner 'CN=RSA 1008 Key Size Test Delegated Responder' testCA "--extKeyUsage ocspResponder -g 1008"
|
||||
make_EE inadequateKeySizeEE 'CN=Inadequate Key Size End-Entity' testINT "inadequate-key-size-ee.example.com" "-g 1008"
|
||||
|
||||
make_EE_with_nsCertType nsCertTypeCritical 'CN=nsCertType Critical' testCA "localhost,*.example.com" "y"
|
||||
make_EE_with_nsCertType nsCertTypeNotCritical 'CN=nsCertType Not Critical' testCA "localhost,*.example.com" "n"
|
||||
make_EE_with_nsCertType nsCertTypeCriticalWithExtKeyUsage 'CN=nsCertType Critical With extKeyUsage' testCA "localhost,*.example.com" "y" "--extKeyUsage serverAuth"
|
||||
|
||||
# Make an X.509 version 1 certificate that will issue another certificate.
|
||||
# By default, this causes an error in verification that we allow overrides for.
|
||||
# However, if the v1 certificate is a trust anchor, then verification succeeds.
|
||||
make_V1 v1Cert 'CN=V1 Cert' testCA
|
||||
export_cert v1Cert v1Cert.der
|
||||
make_EE eeIssuedByV1Cert 'CN=EE Issued by V1 Cert' v1Cert "localhost,*.example.com"
|
||||
|
||||
make_EE eeIssuedByNonCA 'CN=EE Issued by non-CA' localhostAndExampleCom "localhost,*.example.com"
|
||||
|
||||
# Make a valid EE using testINT to test OneCRL revocation of testINT
|
||||
make_EE eeIssuedByIntermediate 'CN=EE issued by intermediate' testINT "localhost"
|
||||
export_cert eeIssuedByIntermediate test-int-ee.der
|
||||
|
||||
make_EE badSubjectAltNames 'CN=EE with bad subjectAltNames' testCA "*.*.example.com"
|
||||
|
||||
cleanup
|
@ -0,0 +1,5 @@
|
||||
issuer:Test Intermediate
|
||||
subject:Inadequate Key Size End-Entity
|
||||
subjectKey:rsa1016
|
||||
extension:subjectAlternativeName:inadequate-key-size-ee.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
Binary file not shown.
@ -0,0 +1,5 @@
|
||||
issuer:Test CA
|
||||
subject:Inadequate Key Usage Test End-entity
|
||||
extension:keyUsage:cRLSign
|
||||
extension:subjectAlternativeName:inadequatekeyusage.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,4 @@
|
||||
issuer:Test Intermediate
|
||||
subject:Test Invalid Delegated Responder From Intermediate
|
||||
subjectKey:alternate
|
||||
extension:extKeyUsage:OCSPSigning
|
@ -0,0 +1,4 @@
|
||||
issuer:Test CA
|
||||
subject:Test Invalid Delegated Responder keyUsage crlSigning
|
||||
subjectKey:alternate
|
||||
extension:keyUsage:cRLSign
|
@ -0,0 +1,3 @@
|
||||
issuer:Test CA
|
||||
subject:Test Invalid Delegated Responder No extKeyUsage
|
||||
subjectKey:alternate
|
@ -0,0 +1,4 @@
|
||||
issuer:Test CA
|
||||
subject:Test Invalid Delegated Responder Wrong extKeyUsage
|
||||
subjectKey:alternate
|
||||
extension:extKeyUsage:codeSigning
|
@ -0,0 +1,3 @@
|
||||
issuer:Test CA
|
||||
subject:127.0.0.1
|
||||
extension:subjectAlternativeName:127.0.0.1
|
Binary file not shown.
@ -5,7 +5,11 @@
|
||||
#include "TLSServer.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "ScopedNSSTypes.h"
|
||||
#include "base64.h"
|
||||
#include "nspr.h"
|
||||
#include "nss.h"
|
||||
#include "plarenas.h"
|
||||
@ -22,7 +26,7 @@ static const uint16_t LISTEN_PORT = 8443;
|
||||
DebugLevel gDebugLevel = DEBUG_ERRORS;
|
||||
uint16_t gCallbackPort = 0;
|
||||
|
||||
const char DEFAULT_CERT_NICKNAME[] = "localhostAndExampleCom";
|
||||
const char DEFAULT_CERT_NICKNAME[] = "default-ee";
|
||||
|
||||
struct Connection
|
||||
{
|
||||
@ -60,6 +64,222 @@ PrintPRError(const char *aPrefix)
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
SECStatus
|
||||
ReadFileToBuffer(const char* basePath, const char* filename, char (&buf)[N])
|
||||
{
|
||||
static_assert(N > 0, "input buffer too small for ReadFileToBuffer");
|
||||
if (PR_snprintf(buf, N - 1, "%s/%s", basePath, filename) == 0) {
|
||||
PrintPRError("PR_snprintf failed");
|
||||
return SECFailure;
|
||||
}
|
||||
ScopedPRFileDesc fd(PR_OpenFile(buf, PR_RDONLY, 0));
|
||||
if (!fd) {
|
||||
PrintPRError("PR_Open failed");
|
||||
return SECFailure;
|
||||
}
|
||||
int32_t fileSize = PR_Available(fd);
|
||||
if (fileSize < 0) {
|
||||
PrintPRError("PR_Available failed");
|
||||
return SECFailure;
|
||||
}
|
||||
if (static_cast<size_t>(fileSize) > N - 1) {
|
||||
PR_fprintf(PR_STDERR, "file too large - not reading\n");
|
||||
return SECFailure;
|
||||
}
|
||||
int32_t bytesRead = PR_Read(fd, buf, fileSize);
|
||||
if (bytesRead != fileSize) {
|
||||
PrintPRError("PR_Read failed");
|
||||
return SECFailure;
|
||||
}
|
||||
buf[bytesRead] = 0;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
AddKeyFromFile(const char* basePath, const char* filename)
|
||||
{
|
||||
const char* PRIVATE_KEY_HEADER = "-----BEGIN PRIVATE KEY-----";
|
||||
const char* PRIVATE_KEY_FOOTER = "-----END PRIVATE KEY-----";
|
||||
|
||||
char buf[16384] = { 0 };
|
||||
SECStatus rv = ReadFileToBuffer(basePath, filename, buf);
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
if (strncmp(buf, PRIVATE_KEY_HEADER, strlen(PRIVATE_KEY_HEADER)) != 0) {
|
||||
PR_fprintf(PR_STDERR, "invalid key - not importing\n");
|
||||
return SECFailure;
|
||||
}
|
||||
const char* bufPtr = buf + strlen(PRIVATE_KEY_HEADER);
|
||||
size_t bufLen = strlen(buf);
|
||||
char base64[16384] = { 0 };
|
||||
char* base64Ptr = base64;
|
||||
while (bufPtr < buf + bufLen) {
|
||||
if (strncmp(bufPtr, PRIVATE_KEY_FOOTER, strlen(PRIVATE_KEY_FOOTER)) == 0) {
|
||||
break;
|
||||
}
|
||||
if (*bufPtr != '\r' && *bufPtr != '\n') {
|
||||
*base64Ptr = *bufPtr;
|
||||
base64Ptr++;
|
||||
}
|
||||
bufPtr++;
|
||||
}
|
||||
|
||||
unsigned int binLength;
|
||||
ScopedPORTString bin((char*)ATOB_AsciiToData(base64, &binLength));
|
||||
if (!bin || binLength == 0) {
|
||||
PrintPRError("ATOB_AsciiToData failed");
|
||||
return SECFailure;
|
||||
}
|
||||
ScopedSECItem secitem(::SECITEM_AllocItem(nullptr, nullptr, binLength));
|
||||
if (!secitem) {
|
||||
PrintPRError("SECITEM_AllocItem failed");
|
||||
return SECFailure;
|
||||
}
|
||||
PORT_Memcpy(secitem->data, bin, binLength);
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
if (!slot) {
|
||||
PrintPRError("PK11_GetInternalKeySlot failed");
|
||||
return SECFailure;
|
||||
}
|
||||
if (PK11_NeedUserInit(slot)) {
|
||||
if (PK11_InitPin(slot, nullptr, nullptr) != SECSuccess) {
|
||||
PrintPRError("PK11_InitPin failed");
|
||||
return SECFailure;
|
||||
}
|
||||
}
|
||||
SECKEYPrivateKey* privateKey;
|
||||
if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, secitem, nullptr, nullptr,
|
||||
true, false, KU_ALL,
|
||||
&privateKey, nullptr)
|
||||
!= SECSuccess) {
|
||||
PrintPRError("PK11_ImportDERPrivateKeyInfoAndReturnKey failed");
|
||||
return SECFailure;
|
||||
}
|
||||
SECKEY_DestroyPrivateKey(privateKey);
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
DecodeCertCallback(void* arg, SECItem** certs, int numcerts)
|
||||
{
|
||||
if (numcerts != 1) {
|
||||
PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
SECItem* certDEROut = static_cast<SECItem*>(arg);
|
||||
return SECITEM_CopyItem(nullptr, certDEROut, *certs);
|
||||
}
|
||||
|
||||
SECStatus
|
||||
AddCertificateFromFile(const char* basePath, const char* filename)
|
||||
{
|
||||
char buf[16384] = { 0 };
|
||||
SECStatus rv = ReadFileToBuffer(basePath, filename, buf);
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
SECItem certDER;
|
||||
rv = CERT_DecodeCertPackage(buf, strlen(buf), DecodeCertCallback, &certDER);
|
||||
if (rv != SECSuccess) {
|
||||
PrintPRError("CERT_DecodeCertPackage failed");
|
||||
return rv;
|
||||
}
|
||||
ScopedCERTCertificate cert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
|
||||
&certDER, nullptr, false,
|
||||
true));
|
||||
PORT_Free(certDER.data);
|
||||
if (!cert) {
|
||||
PrintPRError("CERT_NewTempCertificate failed");
|
||||
return SECFailure;
|
||||
}
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
if (!slot) {
|
||||
PrintPRError("PK11_GetInternalKeySlot failed");
|
||||
return SECFailure;
|
||||
}
|
||||
// The nickname is the filename without '.pem'.
|
||||
std::string nickname(filename, strlen(filename) - 4);
|
||||
rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, nickname.c_str(), false);
|
||||
if (rv != SECSuccess) {
|
||||
PrintPRError("PK11_ImportCert failed");
|
||||
return rv;
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
LoadCertificatesAndKeys(const char* basePath)
|
||||
{
|
||||
// The NSS cert DB path could have been specified as "sql:path". Trim off
|
||||
// the leading "sql:" if so.
|
||||
if (strncmp(basePath, "sql:", 4) == 0) {
|
||||
basePath = basePath + 4;
|
||||
}
|
||||
|
||||
ScopedPRDir fdDir(PR_OpenDir(basePath));
|
||||
if (!fdDir) {
|
||||
PrintPRError("PR_OpenDir failed");
|
||||
return SECFailure;
|
||||
}
|
||||
// On the B2G ICS emulator, operations taken in AddCertificateFromFile
|
||||
// appear to interact poorly with readdir (more specifically, something is
|
||||
// causing readdir to never return null - it indefinitely loops through every
|
||||
// file in the directory, which causes timeouts). Rather than waste more time
|
||||
// chasing this down, loading certificates and keys happens in two phases:
|
||||
// filename collection and then loading. (This is probably a good
|
||||
// idea anyway because readdir isn't reentrant. Something could change later
|
||||
// such that it gets called as a result of calling AddCertificateFromFile or
|
||||
// AddKeyFromFile.)
|
||||
std::vector<std::string> certificates;
|
||||
std::vector<std::string> keys;
|
||||
for (PRDirEntry* dirEntry = PR_ReadDir(fdDir, PR_SKIP_BOTH); dirEntry;
|
||||
dirEntry = PR_ReadDir(fdDir, PR_SKIP_BOTH)) {
|
||||
size_t nameLength = strlen(dirEntry->name);
|
||||
if (nameLength > 4) {
|
||||
if (strncmp(dirEntry->name + nameLength - 4, ".pem", 4) == 0) {
|
||||
certificates.push_back(dirEntry->name);
|
||||
} else if (strncmp(dirEntry->name + nameLength - 4, ".key", 4) == 0) {
|
||||
keys.push_back(dirEntry->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
SECStatus rv;
|
||||
for (std::string& certificate : certificates) {
|
||||
rv = AddCertificateFromFile(basePath, certificate.c_str());
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
for (std::string& key : keys) {
|
||||
rv = AddKeyFromFile(basePath, key.c_str());
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
InitializeNSS(const char* nssCertDBDir)
|
||||
{
|
||||
// Try initializing an existing DB.
|
||||
if (NSS_Init(nssCertDBDir) == SECSuccess) {
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
// Create a new DB if there is none...
|
||||
SECStatus rv = NSS_Initialize(nssCertDBDir, nullptr, nullptr, nullptr, 0);
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// ...and load all certificates into it.
|
||||
return LoadCertificatesAndKeys(nssCertDBDir);
|
||||
}
|
||||
|
||||
nsresult
|
||||
SendAll(PRFileDesc *aSocket, const char *aData, size_t aDataLen)
|
||||
{
|
||||
@ -239,9 +459,10 @@ ConfigSecureServerWithNamedCert(PRFileDesc *fd, const char *certName,
|
||||
certList->len = 2;
|
||||
}
|
||||
|
||||
ScopedSECKEYPrivateKey key(PK11_FindKeyByAnyCert(cert, nullptr));
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
ScopedSECKEYPrivateKey key(PK11_FindKeyByDERCert(slot, cert, nullptr));
|
||||
if (!key) {
|
||||
PrintPRError("PK11_FindKeyByAnyCert failed");
|
||||
PrintPRError("PK11_FindKeyByDERCert failed");
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
@ -286,8 +507,8 @@ StartServer(const char *nssCertDBDir, SSLSNISocketConfig sniSocketConfig,
|
||||
gCallbackPort = atoi(callbackPort);
|
||||
}
|
||||
|
||||
if (NSS_Init(nssCertDBDir) != SECSuccess) {
|
||||
PrintPRError("NSS_Init failed");
|
||||
if (InitializeNSS(nssCertDBDir) != SECSuccess) {
|
||||
PR_fprintf(PR_STDERR, "InitializeNSS failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,13 @@
|
||||
#include "secerr.h"
|
||||
#include "ssl.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRDir, PRDir, PR_CloseDir);
|
||||
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPORTString, char, PORT_Free);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
namespace mozilla { namespace test {
|
||||
|
||||
enum DebugLevel
|
||||
@ -42,6 +49,9 @@ ConfigSecureServerWithNamedCert(PRFileDesc *fd, const char *certName,
|
||||
/*optional*/ ScopedCERTCertificate *cert,
|
||||
/*optional*/ SSLKEAType *kea);
|
||||
|
||||
SECStatus
|
||||
InitializeNSS(const char* nssCertDBDir);
|
||||
|
||||
int
|
||||
StartServer(const char *nssCertDBDir, SSLSNISocketConfig sniSocketConfig,
|
||||
void *sniSocketConfigArg);
|
||||
|
@ -0,0 +1,6 @@
|
||||
issuer:Test CA
|
||||
subject:Test MD5Signature-Expired End-entity
|
||||
validity:20110101-20130101
|
||||
signature:md5WithRSAEncryption
|
||||
extension:subjectAlternativeName:md5signature-expired.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,5 @@
|
||||
issuer:Test CA
|
||||
subject:Test End-entity with MD5 signature
|
||||
signature:md5WithRSAEncryption
|
||||
extension:subjectAlternativeName:md5signature.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,5 @@
|
||||
issuer:Test CA
|
||||
subject:Mismatch-Expired Test End-entity
|
||||
validity:20130101-20140101
|
||||
extension:subjectAlternativeName:doesntmatch.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,5 @@
|
||||
issuer:Test CA
|
||||
subject:Mismatch-Not Yet Valid Test End-entity
|
||||
validity:20330101-20340101
|
||||
extension:subjectAlternativeName:doesntmatch.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,5 @@
|
||||
issuer:Other test CA
|
||||
subject:Mismatch-Untrusted-Expired Test End-entity
|
||||
validity:20110101-20130101
|
||||
extension:subjectAlternativeName:doesntmatch.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,4 @@
|
||||
issuer:Other test CA
|
||||
subject:Mismatch-Untrusted Test End-entity
|
||||
extension:subjectAlternativeName:doesntmatch.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,4 @@
|
||||
issuer:Test CA
|
||||
subject:Mismatch Test End-entity
|
||||
extension:subjectAlternativeName:doesntmatch.example.com,*.alsodoesntmatch.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,2 @@
|
||||
issuer:Test CA
|
||||
subject:doesntmatch.example.com
|
@ -6,3 +6,79 @@
|
||||
|
||||
# lib must be first, because cmd depends on its output
|
||||
DIRS += ['lib', 'cmd']
|
||||
|
||||
test_certificates = (
|
||||
'badSubjectAltNames.pem',
|
||||
'beforeEpochINT.pem',
|
||||
'beforeEpochIssuer.pem',
|
||||
'beforeEpoch.pem',
|
||||
'ca-used-as-end-entity.pem',
|
||||
'default-ee.pem',
|
||||
'delegatedSHA1Signer.pem',
|
||||
'delegatedSigner.pem',
|
||||
'eeIssuedByNonCA.pem',
|
||||
'eeIssuedByV1Cert.pem',
|
||||
'expired-ee.pem',
|
||||
'expiredINT.pem',
|
||||
'expiredissuer.pem',
|
||||
'inadequateKeySizeEE.pem',
|
||||
'inadequatekeyusage-ee.pem',
|
||||
'invalidDelegatedSignerFromIntermediate.pem',
|
||||
'invalidDelegatedSignerKeyUsageCrlSigning.pem',
|
||||
'invalidDelegatedSignerNoExtKeyUsage.pem',
|
||||
'invalidDelegatedSignerWrongExtKeyUsage.pem',
|
||||
'ipAddressAsDNSNameInSAN.pem',
|
||||
'md5signature-expired.pem',
|
||||
'md5signature.pem',
|
||||
'mismatchCN.pem',
|
||||
'mismatch-expired.pem',
|
||||
'mismatch-notYetValid.pem',
|
||||
'mismatch.pem',
|
||||
'mismatch-untrusted-expired.pem',
|
||||
'mismatch-untrusted.pem',
|
||||
'notYetValidINT.pem',
|
||||
'notYetValidIssuer.pem',
|
||||
'notYetValid.pem',
|
||||
'noValidNames.pem',
|
||||
'nsCertTypeCritical.pem',
|
||||
'nsCertTypeCriticalWithExtKeyUsage.pem',
|
||||
'nsCertTypeNotCritical.pem',
|
||||
'ocspEEWithIntermediate.pem',
|
||||
'ocspOtherEndEntity.pem',
|
||||
'other-test-ca.pem',
|
||||
'other-issuer-ee.pem',
|
||||
'rsa-1016-keysizeDelegatedSigner.pem',
|
||||
'same-issuer-ee.pem',
|
||||
'self-signed-EE-with-cA-true.pem',
|
||||
'selfsigned-inadequateEKU.pem',
|
||||
'selfsigned.pem',
|
||||
'test-ca.pem',
|
||||
'test-int-ee.pem',
|
||||
'test-int.pem',
|
||||
'unknownissuer.pem',
|
||||
'untrusted-expired.pem',
|
||||
'untrustedissuer.pem',
|
||||
'v1Cert.pem',
|
||||
)
|
||||
|
||||
for test_certificate in test_certificates:
|
||||
input_file = test_certificate + '.certspec'
|
||||
GENERATED_FILES += [test_certificate]
|
||||
props = GENERATED_FILES[test_certificate]
|
||||
props.script = '../pycert.py'
|
||||
props.inputs = [input_file]
|
||||
TEST_HARNESS_FILES.xpcshell.security.manager.ssl.tests.unit.tlsserver += ['!%s' % test_certificate]
|
||||
|
||||
test_keys = (
|
||||
'default-ee.key',
|
||||
'other-test-ca.key',
|
||||
'rsa-1016-keysizeDelegatedSigner.key',
|
||||
)
|
||||
|
||||
for test_key in test_keys:
|
||||
input_file = test_key + '.keyspec'
|
||||
GENERATED_FILES += [test_key]
|
||||
props = GENERATED_FILES[test_key]
|
||||
props.script = '../pykey.py'
|
||||
props.inputs = [input_file]
|
||||
TEST_HARNESS_FILES.xpcshell.security.manager.ssl.tests.unit.tlsserver += ['!%s' % test_key]
|
||||
|
@ -0,0 +1,3 @@
|
||||
issuer:Test CA
|
||||
subject:End-entity with no valid names
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,5 @@
|
||||
issuer:Test CA
|
||||
subject:Not Yet Valid Test End-entity
|
||||
validity:20310101-20320101
|
||||
extension:subjectAlternativeName:notyetvalid.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,5 @@
|
||||
issuer:Test CA
|
||||
subject:Not Yet Valid Test Intermediate
|
||||
validity:20310101-20330101
|
||||
extension:basicConstraints:cA,
|
||||
extension:keyUsage:cRLSign,keyCertSign
|
@ -0,0 +1,4 @@
|
||||
issuer:Not Yet Valid Test Intermediate
|
||||
subject:Test End-entity with not yet valid issuer
|
||||
extension:subjectAlternativeName:notyetvalidissuer.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,4 @@
|
||||
issuer:Test CA
|
||||
subject:nsCertType Critical
|
||||
extension:subjectAlternativeName:localhost,*.example.com
|
||||
extension:nsCertType[critical]:sslServer
|
@ -0,0 +1,6 @@
|
||||
issuer:Test CA
|
||||
subject:nsCertType Critical With extKeyUsage
|
||||
extension:subjectAlternativeName:localhost,*.example.com
|
||||
extension:nsCertType[critical]:sslServer
|
||||
extension:basicConstraints:,
|
||||
extension:extKeyUsage:serverAuth
|
@ -0,0 +1,4 @@
|
||||
issuer:Test CA
|
||||
subject:nsCertType Not Critical
|
||||
extension:subjectAlternativeName:localhost,*.example.com
|
||||
extension:nsCertType:sslServer
|
@ -0,0 +1,4 @@
|
||||
issuer:Test Intermediate
|
||||
subject:Test End-entity with Intermediate
|
||||
extension:subjectAlternativeName:localhost,*.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,4 @@
|
||||
issuer:Test CA
|
||||
subject:Other Cert
|
||||
extension:subjectAlternativeName:localhost,*.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
issuer:Other test CA
|
||||
subject:Wrong CA Pin Test End-Entity
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
extension:subjectAlternativeName:*.include-subdomains.pinning.example.com,*.exclude-subdomains.pinning.example.com,*.pinning.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
Binary file not shown.
@ -0,0 +1 @@
|
||||
alternate
|
@ -0,0 +1,7 @@
|
||||
issuer:Other test CA
|
||||
subject:Other test CA
|
||||
issuerKey:alternate
|
||||
subjectKey:alternate
|
||||
validity:20150101-20250101
|
||||
extension:basicConstraints:cA,
|
||||
extension:keyUsage:cRLSign,keyCertSign
|
@ -1,5 +0,0 @@
|
||||
library=
|
||||
name=NSS Internal PKCS #11 Module
|
||||
parameters=configdir='sql:security/manager/ssl/tests/unit/tlsserver' certPrefix='' keyPrefix='' secmod='secmod.db' flags= updatedir='' updateCertPrefix='' updateKeyPrefix='' updateid='' updateTokenDescription=''
|
||||
NSS=Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={slotFlags=[RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512] askpw=any timeout=30})
|
||||
|
@ -0,0 +1 @@
|
||||
rsa1016
|
@ -0,0 +1,4 @@
|
||||
issuer:Test CA
|
||||
subject:RSA 1016 Key Size Test Delegated Responder
|
||||
subjectKey:rsa1016
|
||||
extension:extKeyUsage:OCSPSigning
|
Binary file not shown.
@ -0,0 +1,4 @@
|
||||
issuer:Test CA
|
||||
subject:Another Test End-entity
|
||||
extension:subjectAlternativeName:localhost,*.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,5 @@
|
||||
issuer:Test Self-signed End-entity with CA true
|
||||
subject:Test Self-signed End-entity with CA true
|
||||
extension:basicConstraints:cA,
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
||||
extension:subjectAlternativeName:self-signed-end-entity-with-cA-true.example.com
|
@ -0,0 +1,6 @@
|
||||
issuer:Self-signed Inadequate EKU Test End-entity
|
||||
subject:Self-signed Inadequate EKU Test End-entity
|
||||
extension:keyUsage:keyEncipherment,dataEncipherment
|
||||
extension:extKeyUsage:serverAuth
|
||||
extension:subjectAlternativeName:selfsigned-inadequateEKU.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,4 @@
|
||||
issuer:Self-signed Test End-entity
|
||||
subject:Self-signed Test End-entity
|
||||
extension:subjectAlternativeName:selfsigned.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
Binary file not shown.
@ -0,0 +1,4 @@
|
||||
issuer:Test CA
|
||||
subject:Test CA
|
||||
extension:basicConstraints:cA,
|
||||
extension:keyUsage:cRLSign,keyCertSign
|
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
issuer:Test Intermediate
|
||||
subject:EE issued by intermediate
|
||||
extension:subjectAlternativeName:localhost
|
Binary file not shown.
@ -0,0 +1,5 @@
|
||||
issuer:Test CA
|
||||
subject:Test Intermediate
|
||||
validity:20150101-20250101
|
||||
extension:basicConstraints:cA,
|
||||
extension:keyUsage:cRLSign,keyCertSign
|
Binary file not shown.
@ -0,0 +1,4 @@
|
||||
issuer:Test Intermediate to delete
|
||||
subject:Test End-entity from unknown issuer
|
||||
extension:subjectAlternativeName:unknownissuer.example.com,unknownissuer.include-subdomains.pinning.example.com,unknownissuer.test-mode.pinning.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,5 @@
|
||||
issuer:Other test CA
|
||||
subject:Untrusted-Expired Test End-entity
|
||||
validity:20110101-20130101
|
||||
extension:subjectAlternativeName:untrusted-expired.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
@ -0,0 +1,4 @@
|
||||
issuer:Other test CA
|
||||
subject:Test End-entity with untrusted issuer
|
||||
extension:subjectAlternativeName:untrustedissuer.example.com
|
||||
extension:authorityInformationAccess:http://localhost:8888/
|
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
issuer:Test CA
|
||||
subject:V1 Cert
|
||||
version:1
|
@ -8,13 +8,13 @@
|
||||
// 3. run `[path to]/run-mozilla.sh [path to]/xpcshell \
|
||||
// [path to]/genHPKPStaticpins.js \
|
||||
// [absolute path to]/PreloadedHPKPins.json \
|
||||
// [absolute path to]/default-ee.der \
|
||||
// [an unused argument - see bug 1205406] \
|
||||
// [absolute path to]/StaticHPKPins.h
|
||||
|
||||
if (arguments.length != 3) {
|
||||
throw "Usage: genHPKPStaticPins.js " +
|
||||
"<absolute path to PreloadedHPKPins.json> " +
|
||||
"<absolute path to default-ee.der> " +
|
||||
"<an unused argument - see bug 1205406> " +
|
||||
"<absolute path to StaticHPKPins.h>";
|
||||
}
|
||||
|
||||
@ -68,7 +68,8 @@ const PINSETDEF = "/* Pinsets are each an ordered list by the actual value of th
|
||||
|
||||
// Command-line arguments
|
||||
var gStaticPins = parseJson(arguments[0]);
|
||||
var gTestCertFile = arguments[1];
|
||||
|
||||
// arguments[1] is ignored for now. See bug 1205406.
|
||||
|
||||
// Open the output file.
|
||||
var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
@ -350,7 +351,7 @@ function downloadAndParseChromePins(filename,
|
||||
|
||||
// Returns a pair of maps [certNameToSKD, certSKDToName] between cert
|
||||
// nicknames and digests of the SPKInfo for the mozilla trust store
|
||||
function loadNSSCertinfo(derTestFile, extraCertificates) {
|
||||
function loadNSSCertinfo(extraCertificates) {
|
||||
let allCerts = gCertDB.getCerts();
|
||||
let enumerator = allCerts.getEnumerator();
|
||||
let certNameToSKD = {};
|
||||
@ -374,13 +375,10 @@ function loadNSSCertinfo(derTestFile, extraCertificates) {
|
||||
}
|
||||
|
||||
{
|
||||
// A certificate for *.example.com.
|
||||
let der = readFileToString(derTestFile);
|
||||
let testCert = gCertDB.constructX509(der, der.length);
|
||||
// We can't include this cert in the previous loop, because it skips
|
||||
// non-builtin certs and the nickname is not built-in to the cert.
|
||||
// This is the pinning test certificate. The key hash identifies the
|
||||
// default RSA key from pykey.
|
||||
let name = "End Entity Test Cert";
|
||||
let SKD = testCert.sha256SubjectPublicKeyInfoDigest;
|
||||
let SKD = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
|
||||
certNameToSKD[name] = SKD;
|
||||
certSKDToName[SKD] = name;
|
||||
}
|
||||
@ -599,8 +597,7 @@ function loadExtraCertificates(certStringList) {
|
||||
}
|
||||
|
||||
var extraCertificates = loadExtraCertificates(gStaticPins.extra_certificates);
|
||||
var [ certNameToSKD, certSKDToName ] = loadNSSCertinfo(gTestCertFile,
|
||||
extraCertificates);
|
||||
var [ certNameToSKD, certSKDToName ] = loadNSSCertinfo(extraCertificates);
|
||||
var [ chromeNameToHash, chromeNameToMozName ] = downloadAndParseChromeCerts(
|
||||
gStaticPins.chromium_data.cert_file_url, certSKDToName);
|
||||
var [ chromeImportedPinsets, chromeImportedEntries ] =
|
||||
|
Loading…
Reference in New Issue
Block a user