зеркало из https://github.com/mozilla/gecko-dev.git
bug 1166976 - generate some PSM xpcshell test certificates at build time r=Cykesiopka,mgoodwin,froydnj
This commit is contained in:
Родитель
f23dffbae1
Коммит
a83c753047
|
@ -25,6 +25,8 @@ packages.txt:testing/mozbase/packages.txt
|
||||||
objdir:build
|
objdir:build
|
||||||
gyp.pth:media/webrtc/trunk/tools/gyp/pylib
|
gyp.pth:media/webrtc/trunk/tools/gyp/pylib
|
||||||
pyasn1.pth:python/pyasn1
|
pyasn1.pth:python/pyasn1
|
||||||
|
pyasn1_modules.pth:python/pyasn1-modules
|
||||||
bitstring.pth:python/bitstring
|
bitstring.pth:python/bitstring
|
||||||
redo.pth:python/redo
|
redo.pth:python/redo
|
||||||
requests.pth:python/requests
|
requests.pth:python/requests
|
||||||
|
rsa.pth:python/rsa
|
||||||
|
|
|
@ -88,6 +88,23 @@ const certificateUsageStatusResponder = 0x0400;
|
||||||
|
|
||||||
const NO_FLAGS = 0;
|
const NO_FLAGS = 0;
|
||||||
|
|
||||||
|
// Commonly certificates are represented as PEM. The format is roughly as
|
||||||
|
// follows:
|
||||||
|
//
|
||||||
|
// -----BEGIN CERTIFICATE-----
|
||||||
|
// [some lines of base64, each typically 64 characters long]
|
||||||
|
// -----END CERTIFICATE-----
|
||||||
|
//
|
||||||
|
// However, nsIX509CertDB.constructX509FromBase64 and related functions do not
|
||||||
|
// handle input of this form. Instead, they require a single string of base64
|
||||||
|
// with no newlines or BEGIN/END headers. This is a helper function to convert
|
||||||
|
// PEM to the format that nsIX509CertDB requires.
|
||||||
|
function pemToBase64(pem) {
|
||||||
|
return pem.replace(/-----BEGIN CERTIFICATE-----/, "")
|
||||||
|
.replace(/-----END CERTIFICATE-----/, "")
|
||||||
|
.replace(/[\r\n]/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
function readFile(file) {
|
function readFile(file) {
|
||||||
let fstream = Cc["@mozilla.org/network/file-input-stream;1"]
|
let fstream = Cc["@mozilla.org/network/file-input-stream;1"]
|
||||||
.createInstance(Ci.nsIFileInputStream);
|
.createInstance(Ci.nsIFileInputStream);
|
||||||
|
@ -99,8 +116,16 @@ function readFile(file) {
|
||||||
|
|
||||||
function addCertFromFile(certdb, filename, trustString) {
|
function addCertFromFile(certdb, filename, trustString) {
|
||||||
let certFile = do_get_file(filename, false);
|
let certFile = do_get_file(filename, false);
|
||||||
let der = readFile(certFile);
|
let certBytes = readFile(certFile);
|
||||||
certdb.addCert(der, trustString, null);
|
let successful = false;
|
||||||
|
try {
|
||||||
|
certdb.addCert(certBytes, trustString, null);
|
||||||
|
successful = true;
|
||||||
|
} catch (e) {}
|
||||||
|
if (!successful) {
|
||||||
|
// It might be PEM instead of DER.
|
||||||
|
certdb.addCertFromBase64(pemToBase64(certBytes), trustString, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function constructCertFromFile(filename) {
|
function constructCertFromFile(filename) {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
DIRS += ['tlsserver']
|
DIRS += ['tlsserver']
|
||||||
|
TEST_DIRS += ['test_intermediate_basic_usage_constraints']
|
||||||
|
|
||||||
if not CONFIG['MOZ_NO_SMART_CARDS']:
|
if not CONFIG['MOZ_NO_SMART_CARDS']:
|
||||||
DIRS += ['pkcs11testmodule']
|
DIRS += ['pkcs11testmodule']
|
||||||
|
|
|
@ -0,0 +1,398 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# 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/.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Reads a certificate specification from stdin or a file and outputs a
|
||||||
|
signed x509 certificate with the desired properties.
|
||||||
|
|
||||||
|
The input format is as follows:
|
||||||
|
|
||||||
|
issuer:<string to use as the issuer common name>
|
||||||
|
subject:<string to use as the subject common name>
|
||||||
|
[extension:<extension name:<extension-specific data>>]
|
||||||
|
[...]
|
||||||
|
|
||||||
|
Known extensions are:
|
||||||
|
basicConstraints:[cA],[pathLenConstraint]
|
||||||
|
keyUsage:[digitalSignature,nonRepudiation,keyEncipherment,
|
||||||
|
dataEncipherment,keyAgreement,keyCertSign,cRLSign]
|
||||||
|
extKeyUsage:[serverAuth,clientAuth]
|
||||||
|
|
||||||
|
In the future it will be possible to specify other properties of the
|
||||||
|
generated certificate (for example, its validity period, signature
|
||||||
|
algorithm, etc.). For now, those fields have reasonable default values.
|
||||||
|
Currently one shared RSA key is used for all signatures.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pyasn1.codec.der import decoder
|
||||||
|
from pyasn1.codec.der import encoder
|
||||||
|
from pyasn1.type import constraint, namedtype, tag, univ, useful
|
||||||
|
from pyasn1_modules import rfc2459
|
||||||
|
import base64
|
||||||
|
import binascii
|
||||||
|
import datetime
|
||||||
|
import hashlib
|
||||||
|
import sys
|
||||||
|
import rsa
|
||||||
|
|
||||||
|
class UnknownBaseError(Exception):
|
||||||
|
"""Base class for handling unexpected input in this module."""
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
self.category = 'input'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Unknown %s type "%s"' % (self.category, repr(self.value))
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownAlgorithmTypeError(UnknownBaseError):
|
||||||
|
"""Helper exception type to handle unknown algorithm types."""
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
UnknownBaseError.__init__(self, value)
|
||||||
|
self.category = 'algorithm'
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownParameterTypeError(UnknownBaseError):
|
||||||
|
"""Helper exception type to handle unknown input parameters."""
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
UnknownBaseError.__init__(self, value)
|
||||||
|
self.category = 'parameter'
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownExtensionTypeError(UnknownBaseError):
|
||||||
|
"""Helper exception type to handle unknown input extensions."""
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
UnknownBaseError.__init__(self, value)
|
||||||
|
self.category = 'extension'
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownKeyPurposeTypeError(UnknownBaseError):
|
||||||
|
"""Helper exception type to handle unknown key purposes."""
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
UnknownBaseError.__init__(self, value)
|
||||||
|
self.category = 'keyPurpose'
|
||||||
|
|
||||||
|
|
||||||
|
def getASN1Tag(asn1Type):
|
||||||
|
"""Helper function for returning the base tag value of a given
|
||||||
|
type from the pyasn1 package"""
|
||||||
|
return asn1Type.baseTagSet.getBaseTag().asTuple()[2]
|
||||||
|
|
||||||
|
def stringToAlgorithmIdentifier(string):
|
||||||
|
"""Helper function that converts a description of an algorithm
|
||||||
|
to a representation usable by the pyasn1 package"""
|
||||||
|
algorithmIdentifier = rfc2459.AlgorithmIdentifier()
|
||||||
|
algorithm = None
|
||||||
|
if string == 'sha256WithRSAEncryption':
|
||||||
|
algorithm = univ.ObjectIdentifier('1.2.840.113549.1.1.11')
|
||||||
|
# In the future, more algorithms will be supported.
|
||||||
|
if algorithm == None:
|
||||||
|
raise UnknownAlgorithmTypeError(string)
|
||||||
|
algorithmIdentifier.setComponentByName('algorithm', algorithm)
|
||||||
|
return algorithmIdentifier
|
||||||
|
|
||||||
|
def stringToCommonName(string):
|
||||||
|
"""Helper function for taking a string and building an x520 name
|
||||||
|
representation usable by the pyasn1 package. Currently returns one
|
||||||
|
RDN with one AVA consisting of a Common Name encoded as a
|
||||||
|
UTF8String."""
|
||||||
|
commonName = rfc2459.X520CommonName()
|
||||||
|
commonName.setComponentByName('utf8String', string)
|
||||||
|
ava = rfc2459.AttributeTypeAndValue()
|
||||||
|
ava.setComponentByName('type', rfc2459.id_at_commonName)
|
||||||
|
ava.setComponentByName('value', commonName)
|
||||||
|
rdn = rfc2459.RelativeDistinguishedName()
|
||||||
|
rdn.setComponentByPosition(0, ava)
|
||||||
|
rdns = rfc2459.RDNSequence()
|
||||||
|
rdns.setComponentByPosition(0, rdn)
|
||||||
|
name = rfc2459.Name()
|
||||||
|
name.setComponentByPosition(0, rdns)
|
||||||
|
return name
|
||||||
|
|
||||||
|
def datetimeToTime(dt):
|
||||||
|
"""Takes a datetime object and returns an rfc2459.Time object with
|
||||||
|
that time as its value as a GeneralizedTime"""
|
||||||
|
time = rfc2459.Time()
|
||||||
|
time.setComponentByName('generalTime', useful.GeneralizedTime(dt.strftime('%Y%m%d%H%M%SZ')))
|
||||||
|
return time
|
||||||
|
|
||||||
|
def byteStringToHexifiedBitString(string):
|
||||||
|
"""Takes a string of bytes and returns a hex string representing
|
||||||
|
those bytes for use with pyasn1.type.univ.BitString. It must be of
|
||||||
|
the form "'<hex bytes>'H", where the trailing 'H' indicates to
|
||||||
|
pyasn1 that the input is a hex string."""
|
||||||
|
return "'%s'H" % binascii.hexlify(string)
|
||||||
|
|
||||||
|
class RSAPublicKey(univ.Sequence):
|
||||||
|
"""Helper type for encoding an RSA public key"""
|
||||||
|
componentType = namedtype.NamedTypes(
|
||||||
|
namedtype.NamedType('N', univ.Integer()),
|
||||||
|
namedtype.NamedType('E', univ.Integer()))
|
||||||
|
|
||||||
|
|
||||||
|
class Certificate:
|
||||||
|
"""Utility class for reading a certificate specification and
|
||||||
|
generating a signed x509 certificate"""
|
||||||
|
|
||||||
|
sharedRSA_N = long(
|
||||||
|
'00ba8851a8448e16d641fd6eb6880636103d3c13d9eae4354ab4ecf56857'
|
||||||
|
'6c247bc1c725a8e0d81fbdb19c069b6e1a86f26be2af5a756b6a6471087a'
|
||||||
|
'a55aa74587f71cd5249c027ecd43fc1e69d038202993ab20c349e4dbb94c'
|
||||||
|
'c26b6c0eed15820ff17ead691ab1d3023a8b2a41eea770e00f0d8dfd660b'
|
||||||
|
'2bb02492a47db988617990b157903dd23bc5e0b8481fa837d38843ef2716'
|
||||||
|
'd855b7665aaa7e02902f3a7b10800624cc1c6c97ad96615bb7e29612c075'
|
||||||
|
'31a30c91ddb4caf7fcad1d25d309efb9170ea768e1b37b2f226f69e3b48a'
|
||||||
|
'95611dee26d6259dab91084e36cb1c24042cbf168b2fe5f18f991731b8b3'
|
||||||
|
'fe4923fa7251c431d503acda180a35ed8d', 16)
|
||||||
|
sharedRSA_E = 65537L
|
||||||
|
sharedRSA_D = long(
|
||||||
|
'009ecbce3861a454ecb1e0fe8f85dd43c92f5825ce2e997884d0e1a949da'
|
||||||
|
'a2c5ac559b240450e5ac9fe0c3e31c0eefa6525a65f0c22194004ee1ab46'
|
||||||
|
'3dde9ee82287cc93e746a91929c5e6ac3d88753f6c25ba5979e73e5d8fb2'
|
||||||
|
'39111a3cdab8a4b0cdf5f9cab05f1233a38335c64b5560525e7e3b92ad7c'
|
||||||
|
'7504cf1dc7cb005788afcbe1e8f95df7402a151530d5808346864eb370aa'
|
||||||
|
'79956a587862cb533791307f70d91c96d22d001a69009b923c683388c9f3'
|
||||||
|
'6cb9b5ebe64302041c78d908206b87009cb8cabacad3dbdb2792fb911b2c'
|
||||||
|
'f4db6603585be9ae0ca3b8e6417aa04b06e470ea1a3b581ca03a6781c931'
|
||||||
|
'5b62b30e6011f224725946eec57c6d9441', 16)
|
||||||
|
sharedRSA_P = long(
|
||||||
|
'00dd6e1d4fffebf68d889c4d114cdaaa9caa63a59374286c8a5c29a717bb'
|
||||||
|
'a60375644d5caa674c4b8bc7326358646220e4550d7608ac27d55b6db74f'
|
||||||
|
'8d8127ef8fa09098b69147de065573447e183d22fe7d885aceb513d9581d'
|
||||||
|
'd5e07c1a90f5ce0879de131371ecefc9ce72e9c43dc127d238190de81177'
|
||||||
|
'3ca5d19301f48c742b', 16)
|
||||||
|
sharedRSA_Q = long(
|
||||||
|
'00d7a773d9ebc380a767d2fec0934ad4e8b5667240771acdebb5ad796f47'
|
||||||
|
'8fec4d45985efbc9532968289c8d89102fadf21f34e2dd4940eba8c09d6d'
|
||||||
|
'1f16dcc29729774c43275e9251ddbe4909e1fd3bf1e4bedf46a39b8b3833'
|
||||||
|
'28ef4ae3b95b92f2070af26c9e7c5c9b587fedde05e8e7d86ca57886fb16'
|
||||||
|
'5810a77b9845bc3127', 16)
|
||||||
|
|
||||||
|
def __init__(self, paramStream, now=datetime.datetime.utcnow()):
|
||||||
|
self.version = 'v3'
|
||||||
|
self.signature = 'sha256WithRSAEncryption'
|
||||||
|
self.issuer = 'Default Issuer'
|
||||||
|
oneYear = datetime.timedelta(days=365)
|
||||||
|
self.notBefore = now - oneYear
|
||||||
|
self.notAfter = now + oneYear
|
||||||
|
self.subject = 'Default Subject'
|
||||||
|
self.signatureAlgorithm = 'sha256WithRSAEncryption'
|
||||||
|
self.extensions = None
|
||||||
|
self.decodeParams(paramStream)
|
||||||
|
self.serialNumber = self.generateSerialNumber()
|
||||||
|
|
||||||
|
def generateSerialNumber(self):
|
||||||
|
"""Generates a serial number for this certificate based on its
|
||||||
|
contents. Intended to be reproducible for compatibility with
|
||||||
|
the build system on OS X (see the comment above main, later in
|
||||||
|
this file)."""
|
||||||
|
hasher = hashlib.sha256()
|
||||||
|
hasher.update(self.version)
|
||||||
|
hasher.update(self.signature)
|
||||||
|
hasher.update(self.issuer)
|
||||||
|
hasher.update(str(self.notBefore))
|
||||||
|
hasher.update(str(self.notAfter))
|
||||||
|
hasher.update(self.subject)
|
||||||
|
hasher.update(self.signatureAlgorithm)
|
||||||
|
if self.extensions:
|
||||||
|
for extension in self.extensions:
|
||||||
|
hasher.update(str(extension))
|
||||||
|
serialBytes = [ord(c) for c in hasher.digest()[:20]]
|
||||||
|
# Ensure that the most significant bit isn't set (which would
|
||||||
|
# indicate a negative number, which isn't valid for serial
|
||||||
|
# numbers).
|
||||||
|
serialBytes[0] &= 0x7f
|
||||||
|
# Also ensure that the least significant bit on the most
|
||||||
|
# significant byte is set (to prevent a leading zero byte,
|
||||||
|
# which also wouldn't be valid).
|
||||||
|
serialBytes[0] |= 0x01
|
||||||
|
# Now prepend the ASN.1 INTEGER tag and length bytes.
|
||||||
|
serialBytes.insert(0, len(serialBytes))
|
||||||
|
serialBytes.insert(0, getASN1Tag(univ.Integer))
|
||||||
|
return ''.join(chr(b) for b in serialBytes)
|
||||||
|
|
||||||
|
def decodeParams(self, paramStream):
|
||||||
|
for line in paramStream.readlines():
|
||||||
|
self.decodeParam(line.strip())
|
||||||
|
|
||||||
|
def decodeParam(self, line):
|
||||||
|
param = line.split(':')[0]
|
||||||
|
value = ':'.join(line.split(':')[1:])
|
||||||
|
if param == 'subject':
|
||||||
|
self.subject = value
|
||||||
|
elif param == 'issuer':
|
||||||
|
self.issuer = value
|
||||||
|
elif param == 'extension':
|
||||||
|
self.decodeExtension(value)
|
||||||
|
else:
|
||||||
|
raise UnknownParameterTypeError(param)
|
||||||
|
|
||||||
|
def decodeExtension(self, extension):
|
||||||
|
extensionType = extension.split(':')[0]
|
||||||
|
value = ':'.join(extension.split(':')[1:])
|
||||||
|
if extensionType == 'basicConstraints':
|
||||||
|
self.addBasicConstraints(value)
|
||||||
|
elif extensionType == 'keyUsage':
|
||||||
|
self.addKeyUsage(value)
|
||||||
|
elif extensionType == 'extKeyUsage':
|
||||||
|
self.addExtKeyUsage(value)
|
||||||
|
else:
|
||||||
|
raise UnknownExtensionTypeError(extensionType)
|
||||||
|
|
||||||
|
def addExtension(self, extensionType, extensionValue):
|
||||||
|
if not self.extensions:
|
||||||
|
self.extensions = []
|
||||||
|
encapsulated = univ.OctetString(encoder.encode(extensionValue))
|
||||||
|
extension = rfc2459.Extension()
|
||||||
|
extension.setComponentByName('extnID', extensionType)
|
||||||
|
extension.setComponentByName('extnValue', encapsulated)
|
||||||
|
self.extensions.append(extension)
|
||||||
|
|
||||||
|
def addBasicConstraints(self, basicConstraints):
|
||||||
|
cA = basicConstraints.split(',')[0]
|
||||||
|
pathLenConstraint = basicConstraints.split(',')[1]
|
||||||
|
basicConstraintsExtension = rfc2459.BasicConstraints()
|
||||||
|
basicConstraintsExtension.setComponentByName('cA', cA == 'cA')
|
||||||
|
if pathLenConstraint:
|
||||||
|
pathLenConstraintValue = \
|
||||||
|
univ.Integer(int(pathLenConstraint)).subtype(
|
||||||
|
subtypeSpec=constraint.ValueRangeConstraint(0, 64))
|
||||||
|
basicConstraintsExtension.setComponentByName('pathLenConstraint',
|
||||||
|
pathLenConstraintValue)
|
||||||
|
self.addExtension(rfc2459.id_ce_basicConstraints, basicConstraintsExtension)
|
||||||
|
|
||||||
|
def addKeyUsage(self, keyUsage):
|
||||||
|
keyUsageExtension = rfc2459.KeyUsage(keyUsage)
|
||||||
|
self.addExtension(rfc2459.id_ce_keyUsage, keyUsageExtension)
|
||||||
|
|
||||||
|
def keyPurposeToOID(self, keyPurpose):
|
||||||
|
if keyPurpose == 'serverAuth':
|
||||||
|
# the OID for id_kp_serverAuth is incorrect in the
|
||||||
|
# pyasn1-modules implementation
|
||||||
|
return univ.ObjectIdentifier('1.3.6.1.5.5.7.3.1')
|
||||||
|
if keyPurpose == 'clientAuth':
|
||||||
|
return rfc2459.id_kp_clientAuth
|
||||||
|
raise UnknownKeyPurposeTypeError(keyPurpose)
|
||||||
|
|
||||||
|
def addExtKeyUsage(self, extKeyUsage):
|
||||||
|
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)
|
||||||
|
|
||||||
|
def getVersion(self):
|
||||||
|
return rfc2459.Version(self.version).subtype(
|
||||||
|
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))
|
||||||
|
|
||||||
|
def getSerialNumber(self):
|
||||||
|
return decoder.decode(self.serialNumber)[0]
|
||||||
|
|
||||||
|
def getSignature(self):
|
||||||
|
return stringToAlgorithmIdentifier(self.signature)
|
||||||
|
|
||||||
|
def getIssuer(self):
|
||||||
|
return stringToCommonName(self.issuer)
|
||||||
|
|
||||||
|
def getValidity(self):
|
||||||
|
validity = rfc2459.Validity()
|
||||||
|
validity.setComponentByName('notBefore', self.getNotBefore())
|
||||||
|
validity.setComponentByName('notAfter', self.getNotAfter())
|
||||||
|
return validity
|
||||||
|
|
||||||
|
def getNotBefore(self):
|
||||||
|
return datetimeToTime(self.notBefore)
|
||||||
|
|
||||||
|
def getNotAfter(self):
|
||||||
|
return datetimeToTime(self.notAfter)
|
||||||
|
|
||||||
|
def getSubject(self):
|
||||||
|
return stringToCommonName(self.subject)
|
||||||
|
|
||||||
|
def getSignatureAlgorithm(self):
|
||||||
|
return stringToAlgorithmIdentifier(self.signature)
|
||||||
|
|
||||||
|
def getSubjectPublicKey(self):
|
||||||
|
rsaKey = RSAPublicKey()
|
||||||
|
rsaKey.setComponentByName('N', univ.Integer(self.sharedRSA_N))
|
||||||
|
rsaKey.setComponentByName('E', univ.Integer(self.sharedRSA_E))
|
||||||
|
return univ.BitString(byteStringToHexifiedBitString(encoder.encode(rsaKey)))
|
||||||
|
|
||||||
|
def getSubjectPublicKeyInfo(self):
|
||||||
|
algorithmIdentifier = rfc2459.AlgorithmIdentifier()
|
||||||
|
algorithmIdentifier.setComponentByName('algorithm', rfc2459.rsaEncryption)
|
||||||
|
algorithmIdentifier.setComponentByName('parameters', univ.Null())
|
||||||
|
spki = rfc2459.SubjectPublicKeyInfo()
|
||||||
|
spki.setComponentByName('algorithm', algorithmIdentifier)
|
||||||
|
spki.setComponentByName('subjectPublicKey', self.getSubjectPublicKey())
|
||||||
|
return spki
|
||||||
|
|
||||||
|
def toDER(self):
|
||||||
|
tbsCertificate = rfc2459.TBSCertificate()
|
||||||
|
tbsCertificate.setComponentByName('version', self.getVersion())
|
||||||
|
tbsCertificate.setComponentByName('serialNumber', self.getSerialNumber())
|
||||||
|
tbsCertificate.setComponentByName('signature', self.getSignature())
|
||||||
|
tbsCertificate.setComponentByName('issuer', self.getIssuer())
|
||||||
|
tbsCertificate.setComponentByName('validity', self.getValidity())
|
||||||
|
tbsCertificate.setComponentByName('subject', self.getSubject())
|
||||||
|
tbsCertificate.setComponentByName('subjectPublicKeyInfo', self.getSubjectPublicKeyInfo())
|
||||||
|
if self.extensions:
|
||||||
|
extensions = rfc2459.Extensions().subtype(
|
||||||
|
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))
|
||||||
|
count = 0
|
||||||
|
for extension in self.extensions:
|
||||||
|
extensions.setComponentByPosition(count, extension)
|
||||||
|
count += 1
|
||||||
|
tbsCertificate.setComponentByName('extensions', extensions)
|
||||||
|
tbsDER = encoder.encode(tbsCertificate)
|
||||||
|
rsaPrivateKey = rsa.PrivateKey(self.sharedRSA_N, self.sharedRSA_E, self.sharedRSA_D,
|
||||||
|
self.sharedRSA_P, self.sharedRSA_Q)
|
||||||
|
signature = rsa.sign(tbsDER, rsaPrivateKey, 'SHA-256')
|
||||||
|
certificate = rfc2459.Certificate()
|
||||||
|
certificate.setComponentByName('tbsCertificate', tbsCertificate)
|
||||||
|
certificate.setComponentByName('signatureAlgorithm', self.getSignatureAlgorithm())
|
||||||
|
certificate.setComponentByName('signatureValue', byteStringToHexifiedBitString(signature))
|
||||||
|
return encoder.encode(certificate)
|
||||||
|
|
||||||
|
def toPEM(self):
|
||||||
|
output = '-----BEGIN CERTIFICATE-----'
|
||||||
|
der = self.toDER()
|
||||||
|
b64 = base64.b64encode(der)
|
||||||
|
while b64:
|
||||||
|
output += '\n' + b64[:64]
|
||||||
|
b64 = b64[64:]
|
||||||
|
output += '\n-----END CERTIFICATE-----'
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
# The build harness will call this function with an output file-like
|
||||||
|
# object, a path to a file containing a specification, and the path to
|
||||||
|
# the directory containing the buildid file. This will read the
|
||||||
|
# specification and output the certificate as PEM. The purpose of the
|
||||||
|
# buildid file is to provide a single definition of 'now'. This is
|
||||||
|
# particularly important when building on OS X, where we generate
|
||||||
|
# everything twice for unified builds. During the unification step, if
|
||||||
|
# any pair of input files differ, the build system throws an error.
|
||||||
|
# While it would make the most sense to provide the path to the buildid
|
||||||
|
# file itself, since it doesn't exist when processing moz.build files
|
||||||
|
# (but it does exist when actually running this script), the build
|
||||||
|
# system won't let us pass it in directly.
|
||||||
|
def main(output, inputPath, buildIDPath):
|
||||||
|
with open('%s/buildid' % buildIDPath) as buildidFile:
|
||||||
|
buildid = buildidFile.read().strip()
|
||||||
|
now = datetime.datetime.strptime(buildid, '%Y%m%d%H%M%S')
|
||||||
|
with open(inputPath) as configStream:
|
||||||
|
output.write(Certificate(configStream, now=now).toPEM())
|
||||||
|
|
||||||
|
# When run as a standalone program, this will read a specification from
|
||||||
|
# stdin and output the certificate as PEM to stdout.
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print Certificate(sys.stdin).toPEM()
|
|
@ -7,7 +7,7 @@ let certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||||
.getService(Ci.nsIX509CertDB);
|
.getService(Ci.nsIX509CertDB);
|
||||||
|
|
||||||
function load_cert(cert, trust) {
|
function load_cert(cert, trust) {
|
||||||
let file = "test_intermediate_basic_usage_constraints/" + cert + ".der";
|
let file = "test_intermediate_basic_usage_constraints/" + cert + ".pem";
|
||||||
addCertFromFile(certDB, file, trust);
|
addCertFromFile(certDB, file, trust);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,9 +25,9 @@ function getDERString(cert)
|
||||||
function run_test() {
|
function run_test() {
|
||||||
load_cert("ca", "CTu,CTu,CTu");
|
load_cert("ca", "CTu,CTu,CTu");
|
||||||
load_cert("int-limited-depth", "CTu,CTu,CTu");
|
load_cert("int-limited-depth", "CTu,CTu,CTu");
|
||||||
let file = "test_intermediate_basic_usage_constraints/ee-int-limited-depth.der";
|
let file = "test_intermediate_basic_usage_constraints/ee-int-limited-depth.pem";
|
||||||
let cert_der = readFile(do_get_file(file));
|
let cert_pem = readFile(do_get_file(file));
|
||||||
let ee = certDB.constructX509(cert_der, cert_der.length);
|
let ee = certDB.constructX509FromBase64(pemToBase64(cert_pem));
|
||||||
checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
|
checkCertErrorGeneric(certDB, ee, PRErrorCodeSuccess,
|
||||||
certificateUsageSSLServer);
|
certificateUsageSSLServer);
|
||||||
// Change the already existing intermediate certificate's trust using
|
// Change the already existing intermediate certificate's trust using
|
||||||
|
|
|
@ -1,22 +1,11 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
/* To regenerate the certificates for this test:
|
|
||||||
*
|
|
||||||
* cd security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints
|
|
||||||
* ./generate.py
|
|
||||||
* cd ../../../../../..
|
|
||||||
* make -C $OBJDIR/security/manager/ssl/tests
|
|
||||||
*
|
|
||||||
* Check in the generated files. These steps are not done as part of the build
|
|
||||||
* because we do not want to add a build-time dependency on the OpenSSL or NSS
|
|
||||||
* tools or libraries built for the host platform.
|
|
||||||
*/
|
|
||||||
|
|
||||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||||
.getService(Ci.nsIX509CertDB);
|
.getService(Ci.nsIX509CertDB);
|
||||||
|
|
||||||
function load_cert(name, trust) {
|
function load_cert(name, trust) {
|
||||||
let filename = "test_intermediate_basic_usage_constraints/" + name + ".der";
|
let filename = "test_intermediate_basic_usage_constraints/" + name + ".pem";
|
||||||
addCertFromFile(certdb, filename, trust);
|
addCertFromFile(certdb, filename, trust);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,10 +13,10 @@ function test_cert_for_usages(certChainNicks, expected_usages_string) {
|
||||||
let certs = [];
|
let certs = [];
|
||||||
for (let i in certChainNicks) {
|
for (let i in certChainNicks) {
|
||||||
let certNick = certChainNicks[i];
|
let certNick = certChainNicks[i];
|
||||||
let certDER = readFile(do_get_file(
|
let certPEM = readFile(
|
||||||
"test_intermediate_basic_usage_constraints/"
|
do_get_file("test_intermediate_basic_usage_constraints/"
|
||||||
+ certNick + ".der"), false);
|
+ certNick + ".pem"), false);
|
||||||
certs.push(certdb.constructX509(certDER, certDER.length));
|
certs.push(certdb.constructX509FromBase64(pemToBase64(certPEM)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let cert = certs[0];
|
let cert = certs[0];
|
||||||
|
@ -39,12 +28,7 @@ function test_cert_for_usages(certChainNicks, expected_usages_string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function run_test() {
|
function run_test() {
|
||||||
// mozilla::pkix doesn't support the obsolete Netscape object signing
|
|
||||||
// extension, but NSS does.
|
|
||||||
let ee_usage1 = 'Client,Server,Sign,Encrypt,Object Signer';
|
let ee_usage1 = 'Client,Server,Sign,Encrypt,Object Signer';
|
||||||
|
|
||||||
// mozilla::pkix doesn't validate CA certificates for non-CA uses, but
|
|
||||||
// NSS does.
|
|
||||||
let ca_usage1 = "SSL CA";
|
let ca_usage1 = "SSL CA";
|
||||||
|
|
||||||
// Load the ca into mem
|
// Load the ca into mem
|
||||||
|
@ -85,9 +69,6 @@ function run_test() {
|
||||||
// int-limited-depth (cA==true, pathLenConstraint==0)
|
// int-limited-depth (cA==true, pathLenConstraint==0)
|
||||||
// int-limited-depth-invalid (cA==true)
|
// int-limited-depth-invalid (cA==true)
|
||||||
//
|
//
|
||||||
// XXX: It seems the NSS code does not consider the path length of the
|
|
||||||
// certificate we're validating, but mozilla::pkix does. mozilla::pkix's
|
|
||||||
// behavior is correct.
|
|
||||||
test_cert_for_usages(["int-limited-depth-invalid", "int-limited-depth"], "");
|
test_cert_for_usages(["int-limited-depth-invalid", "int-limited-depth"], "");
|
||||||
test_cert_for_usages(["ee-int-limited-depth-invalid",
|
test_cert_for_usages(["ee-int-limited-depth-invalid",
|
||||||
"int-limited-depth-invalid",
|
"int-limited-depth-invalid",
|
||||||
|
@ -102,7 +83,7 @@ function run_test() {
|
||||||
// int-bad-ku-no-eku has basicConstraints.cA==true and has a KU extension
|
// int-bad-ku-no-eku has basicConstraints.cA==true and has a KU extension
|
||||||
// but the KU extension is missing keyCertSign. Note that mozilla::pkix
|
// but the KU extension is missing keyCertSign. Note that mozilla::pkix
|
||||||
// doesn't validate certificates with basicConstraints.Ca==true for non-CA
|
// doesn't validate certificates with basicConstraints.Ca==true for non-CA
|
||||||
// uses, but NSS does.
|
// uses.
|
||||||
test_cert_for_usages(["int-bad-ku-no-eku"], "");
|
test_cert_for_usages(["int-bad-ku-no-eku"], "");
|
||||||
test_cert_for_usages(["ee-int-bad-ku-no-eku", "int-bad-ku-no-eku"], "");
|
test_cert_for_usages(["ee-int-bad-ku-no-eku", "int-bad-ku-no-eku"], "");
|
||||||
|
|
||||||
|
|
Двоичный файл не отображается.
|
@ -0,0 +1,3 @@
|
||||||
|
issuer:ca
|
||||||
|
subject:ca
|
||||||
|
extension:basicConstraints:cA,
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:int-bad-ku-no-eku
|
||||||
|
subject:ee-int-bad-ku-no-eku
|
||||||
|
extension:basicConstraints:,
|
||||||
|
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:int-bad-ku-server-eku
|
||||||
|
subject:ee-int-bad-ku-server-eku
|
||||||
|
extension:basicConstraints:,
|
||||||
|
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:int-cA-FALSE-asserts-keyCertSign
|
||||||
|
subject:ee-int-cA-FALSE-asserts-keyCertSign
|
||||||
|
extension:basicConstraints:,
|
||||||
|
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:int-limited-depth-invalid
|
||||||
|
subject:ee-int-limited-depth-invalid
|
||||||
|
extension:basicConstraints:,
|
||||||
|
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:int-limited-depth
|
||||||
|
subject:ee-int-limited-depth
|
||||||
|
extension:basicConstraints:,
|
||||||
|
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:int-no-extensions
|
||||||
|
subject:ee-int-no-extensions
|
||||||
|
extension:basicConstraints:,
|
||||||
|
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:int-no-ku-no-eku
|
||||||
|
subject:ee-int-no-ku-no-eku
|
||||||
|
extension:basicConstraints:,
|
||||||
|
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:int-no-ku-server-eku
|
||||||
|
subject:ee-int-no-ku-server-eku
|
||||||
|
extension:basicConstraints:,
|
||||||
|
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:int-not-a-ca
|
||||||
|
subject:ee-int-not-a-ca
|
||||||
|
extension:basicConstraints:,
|
||||||
|
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:int-valid-ku-no-eku
|
||||||
|
subject:ee-int-valid-ku-no-eku
|
||||||
|
extension:basicConstraints:,
|
||||||
|
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:int-valid-ku-server-eku
|
||||||
|
subject:ee-int-valid-ku-server-eku
|
||||||
|
extension:basicConstraints:,
|
||||||
|
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
|
|
@ -1,102 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# 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/.
|
|
||||||
|
|
||||||
# requires openssl >= 1.0.0
|
|
||||||
|
|
||||||
import tempfile, os, sys, random
|
|
||||||
libpath = os.path.abspath('../psm_common_py')
|
|
||||||
|
|
||||||
sys.path.append(libpath)
|
|
||||||
|
|
||||||
import CertUtils
|
|
||||||
|
|
||||||
|
|
||||||
srcdir = os.getcwd()
|
|
||||||
db = tempfile.mkdtemp()
|
|
||||||
|
|
||||||
CA_basic_constraints = "basicConstraints = critical, CA:TRUE\n"
|
|
||||||
CA_limited_basic_constraints = "basicConstraints = critical,CA:TRUE, pathlen:0\n"
|
|
||||||
EE_basic_constraints = "basicConstraints = CA:FALSE\n"
|
|
||||||
|
|
||||||
CA_min_ku = "keyUsage = critical, keyCertSign\n"
|
|
||||||
CA_bad_ku = "keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, cRLSign\n"
|
|
||||||
all_ku = "keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, cRLSign\n"
|
|
||||||
EE_full_ku ="keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement\n"
|
|
||||||
|
|
||||||
Server_eku = "extendedKeyUsage = critical, serverAuth, clientAuth\n "
|
|
||||||
|
|
||||||
key_type = 'rsa'
|
|
||||||
|
|
||||||
def generate_int_and_ee2(ca_key, ca_cert, suffix, int_ext_text, ee_ext_text):
|
|
||||||
int_name = "int-" + suffix;
|
|
||||||
ee_name = "ee-int-" + suffix;
|
|
||||||
int_serial = random.randint(100, 40000000);
|
|
||||||
ee_serial = random.randint(100, 40000000);
|
|
||||||
[int_key, int_cert] = CertUtils.generate_cert_generic(db,
|
|
||||||
srcdir,
|
|
||||||
int_serial,
|
|
||||||
key_type,
|
|
||||||
int_name,
|
|
||||||
int_ext_text,
|
|
||||||
ca_key,
|
|
||||||
ca_cert);
|
|
||||||
[ee_key, ee_cert] = CertUtils.generate_cert_generic(db,
|
|
||||||
srcdir,
|
|
||||||
ee_serial,
|
|
||||||
key_type,
|
|
||||||
ee_name,
|
|
||||||
ee_ext_text,
|
|
||||||
int_key,
|
|
||||||
int_cert);
|
|
||||||
return [int_key, int_cert, ee_key, ee_cert]
|
|
||||||
|
|
||||||
def generate_certs():
|
|
||||||
ca_name = "ca"
|
|
||||||
[ca_key, ca_cert ] = CertUtils.generate_cert_generic(db,
|
|
||||||
srcdir,
|
|
||||||
1,
|
|
||||||
key_type,
|
|
||||||
ca_name,
|
|
||||||
CA_basic_constraints)
|
|
||||||
ee_ext_text = EE_basic_constraints + EE_full_ku
|
|
||||||
|
|
||||||
#now the intermediates
|
|
||||||
generate_int_and_ee2(ca_key, ca_cert, "no-extensions", "", ee_ext_text)
|
|
||||||
generate_int_and_ee2(ca_key, ca_cert, "not-a-ca", EE_basic_constraints,
|
|
||||||
ee_ext_text)
|
|
||||||
generate_int_and_ee2(ca_key, ca_cert, "cA-FALSE-asserts-keyCertSign",
|
|
||||||
EE_basic_constraints + all_ku, ee_ext_text)
|
|
||||||
|
|
||||||
[int_key, int_cert, a, b] = generate_int_and_ee2(ca_key, ca_cert,
|
|
||||||
"limited-depth",
|
|
||||||
CA_limited_basic_constraints,
|
|
||||||
ee_ext_text);
|
|
||||||
#and a child using this one
|
|
||||||
generate_int_and_ee2(int_key, int_cert, "limited-depth-invalid",
|
|
||||||
CA_basic_constraints, ee_ext_text);
|
|
||||||
|
|
||||||
# now we do it again for valid basic constraints but strange eku/ku at the
|
|
||||||
# intermediate layer
|
|
||||||
generate_int_and_ee2(ca_key, ca_cert, "valid-ku-no-eku",
|
|
||||||
CA_basic_constraints + CA_min_ku, ee_ext_text);
|
|
||||||
generate_int_and_ee2(ca_key, ca_cert, "bad-ku-no-eku",
|
|
||||||
CA_basic_constraints + CA_bad_ku, ee_ext_text);
|
|
||||||
generate_int_and_ee2(ca_key, ca_cert, "no-ku-no-eku",
|
|
||||||
CA_basic_constraints, ee_ext_text);
|
|
||||||
|
|
||||||
generate_int_and_ee2(ca_key, ca_cert, "valid-ku-server-eku",
|
|
||||||
CA_basic_constraints + CA_min_ku + Server_eku,
|
|
||||||
ee_ext_text);
|
|
||||||
generate_int_and_ee2(ca_key, ca_cert, "bad-ku-server-eku",
|
|
||||||
CA_basic_constraints + CA_bad_ku + Server_eku,
|
|
||||||
ee_ext_text);
|
|
||||||
generate_int_and_ee2(ca_key, ca_cert, "no-ku-server-eku",
|
|
||||||
CA_basic_constraints + Server_eku, ee_ext_text);
|
|
||||||
|
|
||||||
|
|
||||||
generate_certs()
|
|
||||||
|
|
||||||
|
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:ca
|
||||||
|
subject:int-bad-ku-no-eku
|
||||||
|
extension:basicConstraints:cA,
|
||||||
|
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,cRLSign
|
Двоичный файл не отображается.
|
@ -0,0 +1,5 @@
|
||||||
|
issuer:ca
|
||||||
|
subject:int-bad-ku-server-eku
|
||||||
|
extension:basicConstraints:cA,
|
||||||
|
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,cRLSign
|
||||||
|
extension:extKeyUsage:serverAuth,clientAuth
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:ca
|
||||||
|
subject:int-cA-FALSE-asserts-keyCertSign
|
||||||
|
extension:basicConstraints:,
|
||||||
|
extension:keyUsage:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign
|
Двоичный файл не отображается.
|
@ -0,0 +1,3 @@
|
||||||
|
issuer:int-limited-depth
|
||||||
|
subject:int-limited-depth-invalid
|
||||||
|
extension:basicConstraints:cA,
|
Двоичный файл не отображается.
|
@ -0,0 +1,3 @@
|
||||||
|
issuer:ca
|
||||||
|
subject:int-limited-depth
|
||||||
|
extension:basicConstraints:cA,0
|
Двоичный файл не отображается.
|
@ -0,0 +1,2 @@
|
||||||
|
issuer:ca
|
||||||
|
subject:int-no-extensions
|
Двоичный файл не отображается.
|
@ -0,0 +1,3 @@
|
||||||
|
issuer:ca
|
||||||
|
subject:int-no-ku-no-eku
|
||||||
|
extension:basicConstraints:cA,
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:ca
|
||||||
|
subject:int-no-ku-server-eku
|
||||||
|
extension:basicConstraints:cA,
|
||||||
|
extension:extKeyUsage:serverAuth,clientAuth
|
Двоичный файл не отображается.
|
@ -0,0 +1,3 @@
|
||||||
|
issuer:ca
|
||||||
|
subject:int-not-a-ca
|
||||||
|
extension:basicConstraints:,
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
||||||
|
issuer:ca
|
||||||
|
subject:int-valid-ku-no-eku
|
||||||
|
extension:basicConstraints:cA,
|
||||||
|
extension:keyUsage:keyCertSign
|
Двоичный файл не отображается.
|
@ -0,0 +1,5 @@
|
||||||
|
issuer:ca
|
||||||
|
subject:int-valid-ku-server-eku
|
||||||
|
extension:basicConstraints:cA,
|
||||||
|
extension:keyUsage:keyCertSign
|
||||||
|
extension:extKeyUsage:serverAuth,clientAuth
|
|
@ -0,0 +1,39 @@
|
||||||
|
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||||
|
# vim: set filetype=python:
|
||||||
|
# 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/.
|
||||||
|
|
||||||
|
test_certificates = (
|
||||||
|
'ca.pem',
|
||||||
|
'ee-int-bad-ku-no-eku.pem',
|
||||||
|
'ee-int-bad-ku-server-eku.pem',
|
||||||
|
'ee-int-cA-FALSE-asserts-keyCertSign.pem',
|
||||||
|
'ee-int-limited-depth.pem',
|
||||||
|
'ee-int-limited-depth-invalid.pem',
|
||||||
|
'ee-int-no-extensions.pem',
|
||||||
|
'ee-int-no-ku-no-eku.pem',
|
||||||
|
'ee-int-no-ku-server-eku.pem',
|
||||||
|
'ee-int-not-a-ca.pem',
|
||||||
|
'ee-int-valid-ku-no-eku.pem',
|
||||||
|
'ee-int-valid-ku-server-eku.pem',
|
||||||
|
'int-bad-ku-no-eku.pem',
|
||||||
|
'int-bad-ku-server-eku.pem',
|
||||||
|
'int-cA-FALSE-asserts-keyCertSign.pem',
|
||||||
|
'int-limited-depth.pem',
|
||||||
|
'int-limited-depth-invalid.pem',
|
||||||
|
'int-no-extensions.pem',
|
||||||
|
'int-no-ku-no-eku.pem',
|
||||||
|
'int-no-ku-server-eku.pem',
|
||||||
|
'int-not-a-ca.pem',
|
||||||
|
'int-valid-ku-no-eku.pem',
|
||||||
|
'int-valid-ku-server-eku.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, TOPOBJDIR + '/config']
|
||||||
|
TEST_HARNESS_FILES.xpcshell.security.manager.ssl.tests.unit.test_intermediate_basic_usage_constraints += ['!%s' % test_certificate]
|
Загрузка…
Ссылка в новой задаче