Merge "Add certificate validation"
This commit is contained in:
commit
ad25a4016c
|
@ -0,0 +1,350 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Support certificate validation."""
|
||||
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
from cryptography.hazmat.primitives.asymmetric import padding
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
from cryptography import x509, exceptions as cryptography_exceptions
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from cursive import exception
|
||||
from cursive import signature_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def is_within_valid_dates(certificate):
|
||||
"""Determine if the certificate is outside its valid date range.
|
||||
|
||||
:param certificate: the cryptography certificate object
|
||||
:return: False if the certificate valid time range does not include
|
||||
now, True otherwise.
|
||||
"""
|
||||
# Get now in UTC, since certificate returns times in UTC
|
||||
now = timeutils.utcnow()
|
||||
|
||||
# Confirm the certificate valid time range includes now
|
||||
if now < certificate.not_valid_before:
|
||||
return False
|
||||
elif now > certificate.not_valid_after:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def is_issuer(issuing_certificate, issued_certificate):
|
||||
"""Determine if the issuing cert is the parent of the issued cert.
|
||||
|
||||
Determine if the issuing certificate is the parent of the issued
|
||||
certificate by:
|
||||
* conducting subject and issuer name matching, and
|
||||
* verifying the signature of the issued certificate with the issuing
|
||||
certificate's public key
|
||||
|
||||
:param issuing_certificate: the cryptography certificate object that
|
||||
is the potential parent of the issued certificate
|
||||
:param issued_certificate: the cryptography certificate object that
|
||||
is the potential child of the issuing certificate
|
||||
:return: True if the issuing certificate is the parent of the issued
|
||||
certificate, False otherwise.
|
||||
"""
|
||||
if (issuing_certificate is None) or (issued_certificate is None):
|
||||
return False
|
||||
elif issuing_certificate.subject != issued_certificate.issuer:
|
||||
return False
|
||||
else:
|
||||
try:
|
||||
verify_certificate_signature(
|
||||
issuing_certificate,
|
||||
issued_certificate
|
||||
)
|
||||
except cryptography_exceptions.InvalidSignature:
|
||||
# If verification fails, an exception is expected.
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def can_sign_certificates(certificate, certificate_uuid=''):
|
||||
"""Determine if the certificate can sign other certificates.
|
||||
|
||||
:param certificate: the cryptography certificate object
|
||||
:param certificate_uuid: the uuid of the certificate
|
||||
:return: False if the certificate cannot sign other certificates,
|
||||
True otherwise.
|
||||
"""
|
||||
try:
|
||||
basic_constraints = certificate.extensions.get_extension_for_oid(
|
||||
x509.oid.ExtensionOID.BASIC_CONSTRAINTS
|
||||
).value
|
||||
except x509.extensions.ExtensionNotFound:
|
||||
LOG.debug(
|
||||
"Certificate '%s' does not have a basic constraints extension.",
|
||||
certificate_uuid)
|
||||
return False
|
||||
|
||||
try:
|
||||
key_usage = certificate.extensions.get_extension_for_oid(
|
||||
x509.oid.ExtensionOID.KEY_USAGE
|
||||
).value
|
||||
except x509.extensions.ExtensionNotFound:
|
||||
LOG.debug(
|
||||
"Certificate '%s' does not have a key usage extension.",
|
||||
certificate_uuid)
|
||||
return False
|
||||
|
||||
if basic_constraints.ca and key_usage.key_cert_sign:
|
||||
return True
|
||||
|
||||
if not basic_constraints.ca:
|
||||
LOG.debug(
|
||||
"Certificate '%s' is not marked as a CA in its basic constraints "
|
||||
"extension.",
|
||||
certificate_uuid)
|
||||
if not key_usage.key_cert_sign:
|
||||
LOG.debug(
|
||||
"Certificate '%s' is not marked for verifying certificate "
|
||||
"signatures in its key usage extension.",
|
||||
certificate_uuid)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def verify_certificate_signature(signing_certificate, certificate):
|
||||
"""Verify that the certificate was signed correctly.
|
||||
|
||||
:param signing_certificate: the cryptography certificate object used to
|
||||
sign the certificate
|
||||
:param certificate: the cryptography certificate object that was signed
|
||||
by the signing certificate
|
||||
:raises: cryptography.exceptions.InvalidSignature if certificate signature
|
||||
verification fails.
|
||||
"""
|
||||
signature_hash_algorithm = certificate.signature_hash_algorithm
|
||||
signature_bytes = certificate.signature
|
||||
signer_public_key = signing_certificate.public_key()
|
||||
|
||||
if isinstance(signer_public_key, rsa.RSAPublicKey):
|
||||
verifier = signer_public_key.verifier(
|
||||
signature_bytes, padding.PKCS1v15(), signature_hash_algorithm
|
||||
)
|
||||
elif isinstance(signer_public_key, ec.EllipticCurvePublicKey):
|
||||
verifier = signer_public_key.verifier(
|
||||
signature_bytes, ec.ECDSA(signature_hash_algorithm)
|
||||
)
|
||||
else:
|
||||
verifier = signer_public_key.verifier(
|
||||
signature_bytes, signature_hash_algorithm
|
||||
)
|
||||
|
||||
verifier.update(certificate.tbs_certificate_bytes)
|
||||
verifier.verify()
|
||||
|
||||
|
||||
def verify_certificate(context, certificate_uuid,
|
||||
trusted_certificate_uuids,
|
||||
enforce_valid_dates=True,
|
||||
enforce_signing_extensions=True,
|
||||
enforce_path_length=True):
|
||||
"""Validate a certificate against a set of trusted certificates.
|
||||
|
||||
From the key manager, load the set of trusted certificates and the
|
||||
certificate to validate. Store the trusted certificates in a certificate
|
||||
verification context. Use the context to verify that the certificate is
|
||||
cryptographically linked to at least one of the trusted certificates.
|
||||
|
||||
:param context: the user context for authentication
|
||||
:param certificate_uuid: the uuid of a certificate to validate, stored in
|
||||
the key manager
|
||||
:param trusted_certificate_uuids: a list containing the uuids of trusted
|
||||
certificates stored in the key manager
|
||||
:param enforce_valid_dates: a boolean indicating whether date checking
|
||||
should be enforced during certificate verification, defaults to
|
||||
True
|
||||
:param enforce_signing_extensions: a boolean indicating whether extension
|
||||
checking should be enforced during certificate verification,
|
||||
defaults to True
|
||||
:param enforce_path_length: a boolean indicating whether path length
|
||||
constraints should be enforced during certificate verification,
|
||||
defaults to True
|
||||
:raises: SignatureVerificationError if the certificate verification fails
|
||||
for any reason.
|
||||
"""
|
||||
trusted_certificates = list()
|
||||
for uuid in trusted_certificate_uuids:
|
||||
try:
|
||||
trusted_certificates.append(
|
||||
(uuid, signature_utils.get_certificate(context, uuid))
|
||||
)
|
||||
except exception.SignatureVerificationError:
|
||||
LOG.warning("Skipping trusted certificate: %(id)s" % {'id': uuid})
|
||||
|
||||
certificate = signature_utils.get_certificate(context, certificate_uuid)
|
||||
certificate_context = CertificateVerificationContext(
|
||||
trusted_certificates,
|
||||
enforce_valid_dates=enforce_valid_dates,
|
||||
enforce_signing_extensions=enforce_signing_extensions,
|
||||
enforce_path_length=enforce_path_length
|
||||
)
|
||||
certificate_context.update(certificate)
|
||||
certificate_context.verify()
|
||||
|
||||
|
||||
class CertificateVerificationContext(object):
|
||||
"""A collection of signing certificates.
|
||||
|
||||
A collection of signing certificates that may be used to verify the
|
||||
signatures of other certificates.
|
||||
"""
|
||||
|
||||
def __init__(self, certificate_tuples, enforce_valid_dates=True,
|
||||
enforce_signing_extensions=True,
|
||||
enforce_path_length=True):
|
||||
self._signing_certificates = []
|
||||
for certificate_tuple in certificate_tuples:
|
||||
certificate_uuid, certificate = certificate_tuple
|
||||
if not isinstance(certificate, x509.Certificate):
|
||||
LOG.error(
|
||||
"A signing certificate must be an x509.Certificate object."
|
||||
)
|
||||
continue
|
||||
|
||||
if enforce_valid_dates:
|
||||
if not is_within_valid_dates(certificate):
|
||||
LOG.warning(
|
||||
"Certificate '%s' is outside its valid date range and "
|
||||
"cannot be used as a signing certificate.",
|
||||
certificate_uuid)
|
||||
continue
|
||||
|
||||
if enforce_signing_extensions:
|
||||
if not can_sign_certificates(certificate, certificate_uuid):
|
||||
LOG.warning(
|
||||
"Certificate '%s' is not configured to act as a "
|
||||
"signing certificate. It will not be used as a "
|
||||
"signing certificate.",
|
||||
certificate_uuid)
|
||||
continue
|
||||
self._signing_certificates.append(certificate_tuple)
|
||||
|
||||
self._signed_certificate = None
|
||||
self._enforce_valid_dates = enforce_valid_dates
|
||||
self._enforce_path_length = enforce_path_length
|
||||
|
||||
def update(self, certificate):
|
||||
"""Process the certificate to be verified.
|
||||
|
||||
Raises an exception if the certificate is invalid. Stores it
|
||||
otherwise.
|
||||
|
||||
:param certificate: the cryptography certificate to be verified
|
||||
:raises: SignatureVerificationError if the certificate is not of the
|
||||
right type or if it is outside its valid date range.
|
||||
"""
|
||||
if not isinstance(certificate, x509.Certificate):
|
||||
raise exception.SignatureVerificationError(
|
||||
"The certificate must be an x509.Certificate object."
|
||||
)
|
||||
|
||||
if self._enforce_valid_dates:
|
||||
if not is_within_valid_dates(certificate):
|
||||
raise exception.SignatureVerificationError(
|
||||
"The certificate is outside its valid date range."
|
||||
)
|
||||
|
||||
self._signed_certificate = certificate
|
||||
|
||||
def verify(self):
|
||||
"""Locate the certificate's signing certificate and verify it.
|
||||
|
||||
Locate the certificate's signing certificate in the context
|
||||
certificate cache, using both subject/issuer name matching and
|
||||
signature verification. If the certificate is self-signed, verify that
|
||||
it is also located in the context's certificate cache. Construct the
|
||||
certificate chain from certificates in the context certificate cache.
|
||||
Verify that the signing certificate can have a sufficient number of
|
||||
child certificates to support the chain.
|
||||
|
||||
:raises: SignatureVerificationError if certificate validation fails
|
||||
for any reason, including mismatched signatures or a failure
|
||||
to find the required signing certificate.
|
||||
"""
|
||||
signed_certificate = self._signed_certificate
|
||||
certificate_chain = [('base', signed_certificate)]
|
||||
|
||||
# Build the certificate chain.
|
||||
while True:
|
||||
signing_certificate_tuple = None
|
||||
|
||||
# Search for the signing certificate
|
||||
for certificate_tuple in self._signing_certificates:
|
||||
_, candidate = certificate_tuple
|
||||
if is_issuer(candidate, signed_certificate):
|
||||
signing_certificate_tuple = certificate_tuple
|
||||
break
|
||||
|
||||
# If a valid signing certificate is found, prepare to find the
|
||||
# next link in the certificate chain. Otherwise, raise an error.
|
||||
if signing_certificate_tuple:
|
||||
# If the certificate is self-signed, the root of the
|
||||
# certificate chain has been found. Otherwise, repeat the
|
||||
# verification process using the newly found signing
|
||||
# certificate.
|
||||
if signed_certificate == signing_certificate_tuple[1]:
|
||||
break
|
||||
else:
|
||||
certificate_chain.insert(0, signing_certificate_tuple)
|
||||
signed_certificate = signing_certificate_tuple[1]
|
||||
else:
|
||||
uuid = certificate_chain[0][0]
|
||||
raise exception.SignatureVerificationError(
|
||||
"Certificate chain building failed. Could not locate the "
|
||||
"signing certificate for %s in the set of trusted "
|
||||
"certificates." %
|
||||
"the base certificate" if uuid == 'base'
|
||||
else "certificate '%s'" % uuid
|
||||
)
|
||||
|
||||
if self._enforce_path_length:
|
||||
# Verify that each certificate's path length constraint allows
|
||||
# for it to support the rest of the certificate chain.
|
||||
for i in range(len(certificate_chain)):
|
||||
certificate = certificate_chain[i][1]
|
||||
|
||||
# No need to check the last certificate in the chain.
|
||||
if certificate == certificate_chain[-1][1]:
|
||||
break
|
||||
|
||||
try:
|
||||
constraints = certificate.extensions.get_extension_for_oid(
|
||||
x509.oid.ExtensionOID.BASIC_CONSTRAINTS
|
||||
).value
|
||||
except x509.extensions.ExtensionNotFound:
|
||||
raise exception.SignatureVerificationError(
|
||||
"Certificate validation failed. The signing "
|
||||
"certificate '%s' does not have a basic constraints "
|
||||
"extension." % certificate_chain[i][0]
|
||||
)
|
||||
|
||||
# Path length only applies to non-self-issued intermediate
|
||||
# certificates. Do not include the current or end certificates
|
||||
# when computing path length.
|
||||
chain_length = len(certificate_chain[i:])
|
||||
chain_length = (chain_length - 2) if chain_length > 2 else 0
|
||||
if constraints.path_length < chain_length:
|
||||
raise exception.SignatureVerificationError(
|
||||
"Certificate validation failed. The signing "
|
||||
"certificate '%s' is not configured to support "
|
||||
"certificate chains of sufficient "
|
||||
"length." % certificate_chain[i][0]
|
||||
)
|
|
@ -26,7 +26,6 @@ from cryptography import x509
|
|||
from oslo_log import log as logging
|
||||
from oslo_serialization import base64
|
||||
from oslo_utils import encodeutils
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from cursive import exception
|
||||
from cursive.i18n import _, _LE
|
||||
|
@ -70,6 +69,7 @@ MASK_GEN_ALGORITHMS = {
|
|||
'MGF1': padding.MGF1,
|
||||
}
|
||||
|
||||
|
||||
# Required image property names
|
||||
(SIGNATURE, HASH_METHOD, KEY_TYPE, CERT_UUID) = (
|
||||
'img_signature',
|
||||
|
@ -336,28 +336,4 @@ def get_certificate(context, signature_certificate_uuid):
|
|||
certificate = x509.load_der_x509_certificate(cert_data,
|
||||
default_backend())
|
||||
|
||||
# verify the certificate
|
||||
verify_certificate(certificate)
|
||||
|
||||
return certificate
|
||||
|
||||
|
||||
def verify_certificate(certificate):
|
||||
"""Verify that the certificate has not expired.
|
||||
|
||||
:param certificate: the cryptography certificate object
|
||||
:raises: SignatureVerificationError if the certificate valid time range
|
||||
does not include now
|
||||
"""
|
||||
# Get now in UTC, since certificate returns times in UTC
|
||||
now = timeutils.utcnow()
|
||||
|
||||
# Confirm the certificate valid time range includes now
|
||||
if now < certificate.not_valid_before:
|
||||
raise exception.SignatureVerificationError(
|
||||
reason=_('Certificate is not valid before: %s UTC')
|
||||
% certificate.not_valid_before)
|
||||
elif now > certificate.not_valid_after:
|
||||
raise exception.SignatureVerificationError(
|
||||
reason=_('Certificate is not valid after: %s UTC')
|
||||
% certificate.not_valid_after)
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 10 (0xa)
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: C=US, ST=Test, L=Test, O=Test, CN=Test Parent
|
||||
Validity
|
||||
Not Before: Oct 3 18:02:45 2017 GMT
|
||||
Not After : Oct 1 18:02:45 2027 GMT
|
||||
Subject: C=US, ST=Test, L=Test, O=Test, CN=Test Child
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:b2:45:31:e4:99:12:1f:0f:c3:5b:78:98:39:a5:
|
||||
d0:da:c6:9f:38:23:09:df:fd:35:b6:95:b6:37:5d:
|
||||
b6:49:f2:a5:f1:62:75:62:41:09:9d:36:e5:53:c8:
|
||||
82:1a:5c:9d:2a:fd:03:9c:a9:00:6d:28:b3:29:bb:
|
||||
cf:f3:eb:0f:5c:c9:81:8d:69:e1:04:f7:9a:1c:09:
|
||||
33:ab:54:c1:ac:0c:d7:d1:11:79:6c:6f:c0:2b:54:
|
||||
9e:c2:86:85:05:a3:e4:70:06:84:42:eb:8b:c0:0e:
|
||||
3a:73:16:cd:13:79:a5:43:e6:89:8b:c3:7f:6b:04:
|
||||
cd:7f:34:6b:4a:47:65:c3:4a:6a:d3:ea:8e:57:34:
|
||||
5d:39:18:fc:d0:8e:e4:f6:ff:74:86:a0:98:06:67:
|
||||
40:0c:8f:a6:5e:46:9d:ed:b9:25:99:7c:4c:62:b8:
|
||||
19:ae:12:1e:33:0b:d3:43:b9:3c:bc:5a:f3:6b:c6:
|
||||
a9:1c:c1:ce:99:1f:64:b7:a3:8d:ed:c8:3e:95:75:
|
||||
19:e5:ce:51:f1:11:f1:c0:58:76:87:ee:42:12:a4:
|
||||
ff:8e:c6:e8:42:3d:b4:df:c7:be:a6:c7:ea:6c:88:
|
||||
04:4b:d3:f3:9b:7f:d4:db:87:21:55:36:2e:3c:1c:
|
||||
c9:21:4a:2f:7f:51:f0:08:d7:21:ea:75:c4:e2:78:
|
||||
91:9d
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Key Identifier:
|
||||
C2:03:EA:FC:7E:70:7F:34:21:C1:BE:33:0E:8A:E0:7E:C6:A2:21:1B
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:7A:BE:7D:09:5A:5F:5C:DE:CC:82:1A:3B:FE:A8:ED:CA:BA:16:58:49
|
||||
|
||||
X509v3 Basic Constraints:
|
||||
CA:TRUE, pathlen:0
|
||||
X509v3 Key Usage:
|
||||
Certificate Sign, CRL Sign
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:example.com, DNS:www.example.com, DNS:mail.example.com, DNS:ftp.example.com
|
||||
Netscape Comment:
|
||||
OpenSSL Generated Certificate
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
10:46:2e:1e:37:b8:10:4a:8c:e3:76:7c:05:57:76:34:05:0b:
|
||||
e2:ed:b3:1b:28:20:2b:56:9b:2d:59:70:e5:4e:5e:ce:a8:11:
|
||||
d5:c1:9b:e7:c8:0e:61:2b:63:ae:d2:1b:ec:cf:75:31:d0:4f:
|
||||
35:86:c2:51:22:64:c3:07:a7:c4:6b:13:57:cc:e5:d9:86:8d:
|
||||
b4:73:45:c5:ca:48:b7:b6:02:1e:c7:de:71:c6:5f:2a:64:7d:
|
||||
b5:5b:16:9a:27:7d:5f:3c:8a:5e:95:38:7f:c0:7e:d4:39:3f:
|
||||
36:60:7d:7d:8e:9f:72:06:d4:69:7a:e5:45:3f:e2:c9:eb:7f:
|
||||
5f:74:1a:6b:6c:b8:a1:08:05:d9:25:ee:d4:97:db:5a:72:1f:
|
||||
4a:06:a9:86:76:41:58:34:0b:5a:39:be:65:ec:26:b1:13:41:
|
||||
6b:86:58:fa:2e:cd:ab:06:d2:59:0e:bb:e4:44:2c:de:21:d1:
|
||||
8c:9c:93:a5:d5:ae:fc:af:37:b0:91:1f:46:61:28:b9:a5:c8:
|
||||
b4:3c:28:33:b1:d9:ca:49:53:fe:14:80:82:de:06:c1:ab:21:
|
||||
e7:44:76:04:d8:85:b4:60:72:30:7a:28:b7:6f:4d:9e:52:70:
|
||||
21:df:4e:71:aa:01:d6:ba:fa:4b:4a:61:75:9c:57:67:a6:b2:
|
||||
e7:ab:24:6c
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID9jCCAt6gAwIBAgIBCjANBgkqhkiG9w0BAQsFADBQMQswCQYDVQQGEwJVUzEN
|
||||
MAsGA1UECAwEVGVzdDENMAsGA1UEBwwEVGVzdDENMAsGA1UECgwEVGVzdDEUMBIG
|
||||
A1UEAwwLVGVzdCBQYXJlbnQwHhcNMTcxMDAzMTgwMjQ1WhcNMjcxMDAxMTgwMjQ1
|
||||
WjBPMQswCQYDVQQGEwJVUzENMAsGA1UECAwEVGVzdDENMAsGA1UEBwwEVGVzdDEN
|
||||
MAsGA1UECgwEVGVzdDETMBEGA1UEAwwKVGVzdCBDaGlsZDCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBALJFMeSZEh8Pw1t4mDml0NrGnzgjCd/9NbaVtjdd
|
||||
tknypfFidWJBCZ025VPIghpcnSr9A5ypAG0osym7z/PrD1zJgY1p4QT3mhwJM6tU
|
||||
wawM19EReWxvwCtUnsKGhQWj5HAGhELri8AOOnMWzRN5pUPmiYvDf2sEzX80a0pH
|
||||
ZcNKatPqjlc0XTkY/NCO5Pb/dIagmAZnQAyPpl5Gne25JZl8TGK4Ga4SHjML00O5
|
||||
PLxa82vGqRzBzpkfZLejje3IPpV1GeXOUfER8cBYdofuQhKk/47G6EI9tN/HvqbH
|
||||
6myIBEvT85t/1NuHIVU2LjwcySFKL39R8AjXIep1xOJ4kZ0CAwEAAaOB2zCB2DAd
|
||||
BgNVHQ4EFgQUwgPq/H5wfzQhwb4zDorgfsaiIRswHwYDVR0jBBgwFoAUer59CVpf
|
||||
XN7Mgho7/qjtyroWWEkwDwYDVR0TBAgwBgEB/wIBADALBgNVHQ8EBAMCAQYwSgYD
|
||||
VR0RBEMwQYILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNvbYIQbWFpbC5leGFt
|
||||
cGxlLmNvbYIPZnRwLmV4YW1wbGUuY29tMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM
|
||||
IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAQEAEEYuHje4
|
||||
EEqM43Z8BVd2NAUL4u2zGyggK1abLVlw5U5ezqgR1cGb58gOYStjrtIb7M91MdBP
|
||||
NYbCUSJkwwenxGsTV8zl2YaNtHNFxcpIt7YCHsfeccZfKmR9tVsWmid9XzyKXpU4
|
||||
f8B+1Dk/NmB9fY6fcgbUaXrlRT/iyet/X3Qaa2y4oQgF2SXu1JfbWnIfSgaphnZB
|
||||
WDQLWjm+ZewmsRNBa4ZY+i7NqwbSWQ675EQs3iHRjJyTpdWu/K83sJEfRmEouaXI
|
||||
tDwoM7HZyklT/hSAgt4Gwash50R2BNiFtGByMHoot29NnlJwId9OcaoB1rr6S0ph
|
||||
dZxXZ6ay56skbA==
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,87 @@
|
|||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 11 (0xb)
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: C=US, ST=Test, L=Test, O=Test, CN=Test Child
|
||||
Validity
|
||||
Not Before: Oct 3 18:09:07 2017 GMT
|
||||
Not After : Oct 1 18:09:07 2027 GMT
|
||||
Subject: C=US, ST=Test, L=Test, O=Test, CN=Test Grandchild
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:bd:3c:4b:2a:e8:03:5d:07:ae:94:f4:19:ed:00:
|
||||
21:20:dd:1c:54:f1:dc:44:d8:bf:66:b4:bf:ce:21:
|
||||
7b:bf:b4:15:7b:b3:4f:0e:d5:ef:fa:f1:31:ab:2a:
|
||||
22:78:72:20:7d:ce:58:c3:45:0d:2f:5c:23:7c:87:
|
||||
07:bf:ee:8c:8c:9f:ae:31:70:19:61:dc:92:b5:8f:
|
||||
fb:36:16:1c:08:d4:2c:c0:0c:86:e0:ee:a8:31:20:
|
||||
21:16:41:b2:78:bc:88:a8:ef:4c:3a:34:4f:a0:08:
|
||||
25:e7:35:e8:bc:66:d3:c3:b5:2a:05:34:91:b0:d0:
|
||||
ae:02:f2:a1:58:22:af:43:42:d8:40:82:0c:e3:26:
|
||||
72:22:06:d2:b1:13:87:04:83:70:f6:b0:99:39:bf:
|
||||
79:26:f6:e2:ff:24:c3:72:48:9f:68:0a:c1:c9:aa:
|
||||
b1:a8:b4:f7:cf:44:38:4a:77:bf:56:20:fa:7e:08:
|
||||
75:26:04:fb:5e:d5:4f:ff:b8:45:1f:80:12:fb:7e:
|
||||
61:7e:52:f0:dc:71:ee:72:91:27:fa:60:93:96:e5:
|
||||
78:1d:d9:fd:5a:b8:00:b9:97:46:12:b5:2a:93:0e:
|
||||
c3:1b:30:6e:b2:67:5d:c5:ca:40:3f:36:0c:7c:4f:
|
||||
d4:48:e0:1f:32:a9:28:0c:37:35:7c:5d:42:f5:cb:
|
||||
54:b9
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Key Identifier:
|
||||
4F:6C:A8:1F:80:F0:A6:EE:41:85:B9:A2:3F:EC:3A:B2:93:B4:0E:86
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:C2:03:EA:FC:7E:70:7F:34:21:C1:BE:33:0E:8A:E0:7E:C6:A2:21:1B
|
||||
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
X509v3 Key Usage:
|
||||
Digital Signature, Key Encipherment
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:example.com, DNS:www.example.com, DNS:mail.example.com, DNS:ftp.example.com
|
||||
Netscape Comment:
|
||||
OpenSSL Generated Certificate
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
ae:a7:62:9e:f6:b7:e3:02:84:0f:fe:c6:7c:c1:0b:74:8e:95:
|
||||
c3:2e:e9:5f:c0:8b:fc:79:45:53:5c:34:9d:b0:de:e6:cf:ed:
|
||||
52:4c:3f:6a:3f:e9:8d:a3:58:d4:ae:4d:31:30:57:d5:31:f9:
|
||||
a2:ed:82:e2:ae:1a:65:a5:ab:de:64:35:c9:0b:d1:86:b0:83:
|
||||
57:8a:e4:ca:21:d5:9a:79:5b:44:42:ff:52:9a:51:b6:f4:6e:
|
||||
f1:da:dd:3b:ca:12:cb:4c:e5:9f:a5:12:4f:13:99:85:79:c8:
|
||||
00:3b:2c:25:7f:02:07:a3:4e:59:0b:4d:8e:f8:43:08:a9:91:
|
||||
30:0a:17:1c:ff:91:c0:16:d5:c0:1e:ec:a5:24:c8:cc:f0:2c:
|
||||
0e:30:b9:bb:34:11:83:e7:4d:02:e4:2d:2a:90:98:eb:d8:ae:
|
||||
7b:2f:19:31:db:63:fc:0c:0b:47:f5:8f:7b:cf:99:0b:30:91:
|
||||
a6:44:19:51:7f:15:4f:ab:8c:08:e2:bd:91:42:e4:e7:88:8e:
|
||||
c0:ea:fd:09:ac:96:c6:14:ef:0e:7d:75:6a:05:b0:b5:4d:43:
|
||||
60:62:31:85:61:cb:c3:0f:81:24:d6:de:10:42:54:ff:c0:63:
|
||||
95:40:3d:89:52:f9:00:2a:a5:74:1c:b1:42:be:a1:2f:de:90:
|
||||
cb:d5:a7:3d
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID9DCCAtygAwIBAgIBCzANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzEN
|
||||
MAsGA1UECAwEVGVzdDENMAsGA1UEBwwEVGVzdDENMAsGA1UECgwEVGVzdDETMBEG
|
||||
A1UEAwwKVGVzdCBDaGlsZDAeFw0xNzEwMDMxODA5MDdaFw0yNzEwMDExODA5MDda
|
||||
MFQxCzAJBgNVBAYTAlVTMQ0wCwYDVQQIDARUZXN0MQ0wCwYDVQQHDARUZXN0MQ0w
|
||||
CwYDVQQKDARUZXN0MRgwFgYDVQQDDA9UZXN0IEdyYW5kY2hpbGQwggEiMA0GCSqG
|
||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9PEsq6ANdB66U9BntACEg3RxU8dxE2L9m
|
||||
tL/OIXu/tBV7s08O1e/68TGrKiJ4ciB9zljDRQ0vXCN8hwe/7oyMn64xcBlh3JK1
|
||||
j/s2FhwI1CzADIbg7qgxICEWQbJ4vIio70w6NE+gCCXnNei8ZtPDtSoFNJGw0K4C
|
||||
8qFYIq9DQthAggzjJnIiBtKxE4cEg3D2sJk5v3km9uL/JMNySJ9oCsHJqrGotPfP
|
||||
RDhKd79WIPp+CHUmBPte1U//uEUfgBL7fmF+UvDcce5ykSf6YJOW5Xgd2f1auAC5
|
||||
l0YStSqTDsMbMG6yZ13FykA/Ngx8T9RI4B8yqSgMNzV8XUL1y1S5AgMBAAGjgdUw
|
||||
gdIwHQYDVR0OBBYEFE9sqB+A8KbuQYW5oj/sOrKTtA6GMB8GA1UdIwQYMBaAFMID
|
||||
6vx+cH80IcG+Mw6K4H7GoiEbMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMEoGA1Ud
|
||||
EQRDMEGCC2V4YW1wbGUuY29tgg93d3cuZXhhbXBsZS5jb22CEG1haWwuZXhhbXBs
|
||||
ZS5jb22CD2Z0cC5leGFtcGxlLmNvbTAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH
|
||||
ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwDQYJKoZIhvcNAQELBQADggEBAK6nYp72t+MC
|
||||
hA/+xnzBC3SOlcMu6V/Ai/x5RVNcNJ2w3ubP7VJMP2o/6Y2jWNSuTTEwV9Ux+aLt
|
||||
guKuGmWlq95kNckL0Yawg1eK5Moh1Zp5W0RC/1KaUbb0bvHa3TvKEstM5Z+lEk8T
|
||||
mYV5yAA7LCV/AgejTlkLTY74QwipkTAKFxz/kcAW1cAe7KUkyMzwLA4wubs0EYPn
|
||||
TQLkLSqQmOvYrnsvGTHbY/wMC0f1j3vPmQswkaZEGVF/FU+rjAjivZFC5OeIjsDq
|
||||
/QmslsYU7w59dWoFsLVNQ2BiMYVhy8MPgSTW3hBCVP/AY5VAPYlS+QAqpXQcsUK+
|
||||
oS/ekMvVpz0=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,34 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIF7jCCA9agAwIBAgIJANHiL5B0pUVmMA0GCSqGSIb3DQEBCwUAMIGDMQswCQYD
|
||||
VQQGEwJVUzENMAsGA1UECAwEVGVzdDENMAsGA1UEBwwEVGVzdDENMAsGA1UECgwE
|
||||
VGVzdDENMAsGA1UECwwEVGVzdDEZMBcGA1UEAwwQVGVzdCBHcmFuZHBhcmVudDEd
|
||||
MBsGCSqGSIb3DQEJARYOZ3BAZXhhbXBsZS5jb20wHhcNMTcxMDAzMTc0NzMyWhcN
|
||||
MTcxMTAyMTc0NzMyWjCBgzELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFRlc3QxDTAL
|
||||
BgNVBAcMBFRlc3QxDTALBgNVBAoMBFRlc3QxDTALBgNVBAsMBFRlc3QxGTAXBgNV
|
||||
BAMMEFRlc3QgR3JhbmRwYXJlbnQxHTAbBgkqhkiG9w0BCQEWDmdwQGV4YW1wbGUu
|
||||
Y29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAn4m1O+fffNTSnGE5
|
||||
MPac07jjMNrKHEjARS4aM222C8wCPiXXrs1diTQlvtxrLFOzc0gtCH6xVl59Zcis
|
||||
H7kBf8oV9wNIHcfy2BmGkP7Wv68p3UsIF1IzGSHPyKJWG+l/xNexuXFaVG9y+siu
|
||||
5Z3bx9DMBPFfXalxwRGoS0fyBOG/tXlqicf/aojF1U3UolML58URQqQ7IvGjEq22
|
||||
iqAfduEwLlLb99iJ8uiFgO6Rl/hwxvy9gmrGWJGHpHQKJ2Dx37Zc8MMcAJ5yos7c
|
||||
GAs3e31TvRJgyEBcPKtl+xmh36wNC+V1KKRYKAfENqB6v7b1GDZrVtH7uHvSPCDQ
|
||||
ccKklF2thomO4cm6UpbCF7/5i50OLwtr1TcUI/YT+nR/YsCuc/PKdyXITpP0CNR9
|
||||
Wcw6pb5LsWgLisFh4my4PzTbwTcPGFUJHq0CUUsRP1YijMNRtiZsoMJwspMZyg9d
|
||||
9Ufxf7HjbugazUfvfIKMfX/s/pIZLiDLx5lV9RbHmjvlCt4OfH3FhqBveguqDLq7
|
||||
LbBC6tYm1E21izUqXy4Zh+oogvZeZGUBQL/JUJ6XOkUnffv1nf2HDsCmlW64NLce
|
||||
9gc25BtXAAf5/tMQL2J3t5SZ+Ladk+nklQXz6eClFcLEbRcd15bZ3QFXCajeLWcP
|
||||
Y5TZFgDQFFr7/FjDhr2bByMOJEkCAwEAAaNjMGEwHQYDVR0OBBYEFKfrobRNKmLV
|
||||
OJDtRPp3f/m66pkEMB8GA1UdIwQYMBaAFKfrobRNKmLVOJDtRPp3f/m66pkEMBIG
|
||||
A1UdEwEB/wQIMAYBAf8CAQEwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IC
|
||||
AQByRvLd0xO238AwgDep4hBshcFH9tcSg5hDPFFeJWRnC4c63vNGXMVV7iEAoPSH
|
||||
LPbuELCIRqiZFYW5A8Olv2MGGZ3kjiFrWYfbLFU0/z1y82/E2NtM65cvOQKYxMk1
|
||||
HBmaGF8s43LdDiGUZ0yFMTwe+da+zWcfDPgSYml36ReCsn2dGFmfkPFhqSf810kI
|
||||
yl2EKQnjEf51AGDfrA6fmEafsQy8eFf0uH6cR8nrsa+0aXIkTHZ9erXrXujD30iL
|
||||
9M4T3uW/0Qk/kqSN3wUgHYWDBRyTKxCDPMiEixXDq21Jm1VzSKJAFE+xEuFHtqXl
|
||||
nfZQCzihdx3ckZnH3qfrJt0V0cu6qSNr6sbyrb7FVO8aCNyumdCDM9VdJ64UFAme
|
||||
Xd/1/195PcoFOVEokoH15EH0mPr+/DDWA39c+FaRHH0A3LmuzX/P5rTRLO3wldpL
|
||||
XiZkLrfG43UNq3PIdh3YZEabpFcQYTmab7N8nZnmoMRM6YoEnHjdqPcDv3xs4gJS
|
||||
U24bVnFqzgSW3V1GfZGnlQyGXFrlrU+wWJ55eJ59ucQn8PDYlrSz7+x9RiqoFZcQ
|
||||
c9L8j7dFMBx6zI4dI5Ddx5q9KNtxPJb4Hk9HEd4C5OQ0qqdBR/hSD9mDjBpqEyc8
|
||||
aXIzmrTpGm7A9lbyXCEaOzN+2Jvdq5KtWh/halEgqgToqQ==
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1 @@
|
|||
This is not a certificate.
|
|
@ -0,0 +1,24 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIID8zCCAtugAwIBAgIJAMDwfYBIkXEGMA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD
|
||||
VQQGEwJVUzERMA8GA1UECAwIVGVzdG9uaWExDTALBgNVBAcMBFRlc3QxJDAiBgNV
|
||||
BAoMG0NvbXByZWhlbnNpdmUgVGVzdGluZywgSW5jLjEaMBgGA1UECwwRVGVzdGlu
|
||||
ZyBPdmVyc2lnaHQxHDAaBgNVBAMME1Rlc3RpbmcgQ2VydGlmaWNhdGUwHhcNMTYw
|
||||
NjMwMTcyOTUwWhcNMTcwNjMwMTcyOTUwWjCBjzELMAkGA1UEBhMCVVMxETAPBgNV
|
||||
BAgMCFRlc3RvbmlhMQ0wCwYDVQQHDARUZXN0MSQwIgYDVQQKDBtDb21wcmVoZW5z
|
||||
aXZlIFRlc3RpbmcsIEluYy4xGjAYBgNVBAsMEVRlc3RpbmcgT3ZlcnNpZ2h0MRww
|
||||
GgYDVQQDDBNUZXN0aW5nIENlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEAm+W78acV27U11m7E3iUUUGb+JXMW0okP8epD9OsLtVHxR+oq
|
||||
iOt19rgNIH/wJzaT+CnJ1jUerjzjFu2RwGhEr8Ph2KrWWQ7vxkhJzuXmKmGBZJm3
|
||||
FJcADrxcmZ8V3Yqxf3zO36Rg27jqDgxSy3uzxgO7ZXrkrJjrgrg+x8wVQ/pkhd8Y
|
||||
gQ/YQ2r1DF1GcpS/tSkCSc3lbIpCCHhORaRmHZXURML5q7vibLmc55Ad90WxtS1d
|
||||
WI8RAsWnQMvP1OmZcRcPKrUlRc/w+nIrxNF9HdeOweQv2tcnNlxBOcr6MwIL+Gle
|
||||
N4TmmthyVYCXxNWhW1VFA3atfEfmyEpiKIcQGwIDAQABo1AwTjAdBgNVHQ4EFgQU
|
||||
IkPrrGyB6+XUlWbd287uFbfCvkkwHwYDVR0jBBgwFoAUIkPrrGyB6+XUlWbd287u
|
||||
FbfCvkkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAMWi3C19pjWs9
|
||||
9hg1rTC0D/5C9K/0nmQ1pstVMXOKn9Z3ndUqRvLzxhHZHhQ/ATQwHKeSM2vpCmKa
|
||||
eV7PGivF6W+CAXJImvgNrsP2fMBnTsg2Q3hBHSIkTgwJxAHlYZ3NXSxWoDSuozvU
|
||||
+qjRY3hMpYLSXpfGFKh73GHBNWXyjlo7pn+I4gAEoHOqDKTelOONz6PiKKi4Un2g
|
||||
j5FqmLZEq9VvzqSEC5VuFLZs4BpGmsKBM16+q+8JWMa025wNcdq4DxuNAkb3Zsty
|
||||
QZkgVYJgIeuEKOCubCQfDOya5W7ik3mtZZm9dFD5dZ3+CDB53a/AlKdi9YUAJOUW
|
||||
xBJzlRBlLg==
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,107 @@
|
|||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 9 (0x9)
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: C=US, ST=Test, L=Test, O=Test, OU=Test, CN=Test Grandparent/emailAddress=gp@example.com
|
||||
Validity
|
||||
Not Before: Oct 3 17:58:30 2017 GMT
|
||||
Not After : Oct 1 17:58:30 2027 GMT
|
||||
Subject: C=US, ST=Test, L=Test, O=Test, CN=Test Parent
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:9f:9d:95:c4:a3:2f:37:52:e4:7c:cf:0b:0e:7f:
|
||||
14:69:63:1e:7a:cc:a8:19:a7:88:59:c8:17:f2:21:
|
||||
13:1b:45:21:fa:cc:93:40:71:cf:77:52:5a:1e:2e:
|
||||
5a:91:16:a9:67:3a:a3:6a:ea:cb:a2:bf:24:9b:8c:
|
||||
08:96:33:19:46:f9:7a:04:f9:c2:ee:87:f3:c3:23:
|
||||
73:37:59:0e:c0:71:f4:cd:0b:ad:23:63:51:0a:4f:
|
||||
dc:d2:9b:ab:ab:8a:99:07:d4:c8:c8:70:fd:18:73:
|
||||
25:0a:48:82:32:0d:64:46:b1:63:84:24:03:0b:3c:
|
||||
b8:17:92:78:6c:2b:4d:21:1b:46:3e:c1:cf:98:0b:
|
||||
a8:43:91:c0:39:48:f5:4e:71:77:c5:43:0e:68:8f:
|
||||
01:c6:fb:59:77:d5:b3:f3:fe:95:27:ea:6e:ae:fc:
|
||||
8e:59:ad:06:97:0c:f7:a6:e7:61:df:23:91:26:d0:
|
||||
bc:80:c6:2b:02:9b:fa:0f:e6:32:69:5a:90:29:c9:
|
||||
9c:34:eb:50:ed:1d:e3:eb:0f:67:88:e3:ec:2b:1a:
|
||||
ab:41:c3:fa:d6:e8:aa:e3:7b:6a:16:3d:d8:da:6b:
|
||||
af:92:81:32:98:2f:f7:c0:bd:c4:25:bb:02:60:43:
|
||||
d5:e6:0c:29:7f:31:5d:09:4b:6a:a9:31:9b:92:24:
|
||||
09:8f
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Key Identifier:
|
||||
7A:BE:7D:09:5A:5F:5C:DE:CC:82:1A:3B:FE:A8:ED:CA:BA:16:58:49
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:A7:EB:A1:B4:4D:2A:62:D5:38:90:ED:44:FA:77:7F:F9:BA:EA:99:04
|
||||
|
||||
X509v3 Basic Constraints:
|
||||
CA:TRUE, pathlen:0
|
||||
X509v3 Key Usage:
|
||||
Certificate Sign, CRL Sign
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:example.com, DNS:www.example.com, DNS:mail.example.com, DNS:ftp.example.com
|
||||
Netscape Comment:
|
||||
OpenSSL Generated Certificate
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
81:55:0d:1d:73:54:1d:72:73:72:dc:cf:ed:c1:47:c8:38:2a:
|
||||
78:33:5e:55:6f:02:cc:c0:6a:6f:7e:c9:fa:4c:3d:a0:5b:25:
|
||||
37:5e:87:69:7f:d8:66:73:4f:58:7d:c7:3e:6d:be:2a:85:43:
|
||||
6a:cb:ff:68:59:1d:72:d2:68:ad:e9:5b:2f:8d:f6:95:31:ba:
|
||||
1d:de:16:45:d9:12:51:85:12:bb:fb:89:fc:3a:7c:f5:e4:75:
|
||||
64:b4:7d:ff:9f:f6:15:fa:1e:cb:18:4a:9d:e8:d8:5e:5a:d7:
|
||||
dd:78:c7:df:3d:21:2d:99:ef:b4:2c:78:2f:fb:fa:a0:7e:f3:
|
||||
cb:3b:05:5a:65:7d:9b:0f:9b:a3:9b:a9:ad:25:f8:32:cb:08:
|
||||
fd:c2:68:d3:92:15:09:59:5f:8b:c4:84:01:5f:75:7b:f0:55:
|
||||
5f:20:39:f1:26:65:3d:d8:a2:19:de:fb:79:a0:27:2a:24:ae:
|
||||
95:02:84:61:72:7a:47:37:4e:9f:af:20:5b:21:ec:c4:bf:ee:
|
||||
80:5b:35:4e:ee:20:46:e6:cb:a6:e2:2f:c6:3e:5a:fa:f9:97:
|
||||
c3:97:09:1d:ce:08:a3:e9:09:cb:c3:59:3f:98:f3:b6:bf:00:
|
||||
8b:a7:40:de:0a:1c:09:88:f7:74:fa:b1:1c:05:44:ff:ba:73:
|
||||
84:3b:93:8d:a8:51:d0:d8:59:e6:cd:a8:79:d3:db:0a:1d:99:
|
||||
3f:7c:a0:f9:d5:9e:dd:13:58:ee:ef:0d:3d:e2:4a:8b:85:18:
|
||||
0c:86:f8:97:4d:18:54:c0:52:b8:10:38:1a:b8:8a:06:71:a5:
|
||||
e7:78:11:00:5b:9f:19:92:34:28:0f:19:3f:b0:57:ea:11:69:
|
||||
29:ca:ed:05:36:08:f6:8d:ec:5d:34:79:92:8e:4c:e0:1c:a4:
|
||||
ad:1a:31:90:b7:16:60:da:e3:8f:ee:ea:66:df:13:e8:46:8d:
|
||||
a3:e2:3b:0a:f5:87:14:3d:4b:14:ea:da:89:c7:ae:e0:60:e3:
|
||||
a0:4c:04:2f:a1:0f:a9:84:5a:5a:f7:3d:4f:7b:d4:7c:e1:cd:
|
||||
ef:8b:28:45:19:ea:a9:4c:9e:59:f8:41:43:10:77:89:09:3e:
|
||||
30:d0:e9:58:96:45:07:50:0e:4d:cc:6a:53:9e:64:c4:8a:e0:
|
||||
51:96:3a:c6:8a:e2:94:af:9c:26:9a:fe:e3:7a:cd:cc:55:60:
|
||||
f0:dc:bf:f3:0d:e8:69:e4:cf:49:e1:f4:d2:87:91:31:cf:42:
|
||||
f7:2c:a7:f7:7b:88:90:e4:17:96:f6:34:d2:bf:a1:66:3c:03:
|
||||
db:aa:07:fa:a6:c3:4b:d3:29:d1:d1:40:6f:a7:88:a5:7f:bd:
|
||||
5f:f5:00:94:db:53:5d:24
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFKzCCAxOgAwIBAgIBCTANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
|
||||
DTALBgNVBAgMBFRlc3QxDTALBgNVBAcMBFRlc3QxDTALBgNVBAoMBFRlc3QxDTAL
|
||||
BgNVBAsMBFRlc3QxGTAXBgNVBAMMEFRlc3QgR3JhbmRwYXJlbnQxHTAbBgkqhkiG
|
||||
9w0BCQEWDmdwQGV4YW1wbGUuY29tMB4XDTE3MTAwMzE3NTgzMFoXDTI3MTAwMTE3
|
||||
NTgzMFowUDELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFRlc3QxDTALBgNVBAcMBFRl
|
||||
c3QxDTALBgNVBAoMBFRlc3QxFDASBgNVBAMMC1Rlc3QgUGFyZW50MIIBIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn52VxKMvN1LkfM8LDn8UaWMeesyoGaeI
|
||||
WcgX8iETG0Uh+syTQHHPd1JaHi5akRapZzqjaurLor8km4wIljMZRvl6BPnC7ofz
|
||||
wyNzN1kOwHH0zQutI2NRCk/c0purq4qZB9TIyHD9GHMlCkiCMg1kRrFjhCQDCzy4
|
||||
F5J4bCtNIRtGPsHPmAuoQ5HAOUj1TnF3xUMOaI8BxvtZd9Wz8/6VJ+purvyOWa0G
|
||||
lwz3pudh3yORJtC8gMYrApv6D+YyaVqQKcmcNOtQ7R3j6w9niOPsKxqrQcP61uiq
|
||||
43tqFj3Y2muvkoEymC/3wL3EJbsCYEPV5gwpfzFdCUtqqTGbkiQJjwIDAQABo4Hb
|
||||
MIHYMB0GA1UdDgQWBBR6vn0JWl9c3syCGjv+qO3KuhZYSTAfBgNVHSMEGDAWgBSn
|
||||
66G0TSpi1TiQ7UT6d3/5uuqZBDAPBgNVHRMECDAGAQH/AgEAMAsGA1UdDwQEAwIB
|
||||
BjBKBgNVHREEQzBBggtleGFtcGxlLmNvbYIPd3d3LmV4YW1wbGUuY29tghBtYWls
|
||||
LmV4YW1wbGUuY29tgg9mdHAuZXhhbXBsZS5jb20wLAYJYIZIAYb4QgENBB8WHU9w
|
||||
ZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMA0GCSqGSIb3DQEBCwUAA4ICAQCB
|
||||
VQ0dc1QdcnNy3M/twUfIOCp4M15VbwLMwGpvfsn6TD2gWyU3Xodpf9hmc09Yfcc+
|
||||
bb4qhUNqy/9oWR1y0mit6VsvjfaVMbod3hZF2RJRhRK7+4n8Onz15HVktH3/n/YV
|
||||
+h7LGEqd6NheWtfdeMffPSEtme+0LHgv+/qgfvPLOwVaZX2bD5ujm6mtJfgyywj9
|
||||
wmjTkhUJWV+LxIQBX3V78FVfIDnxJmU92KIZ3vt5oCcqJK6VAoRhcnpHN06fryBb
|
||||
IezEv+6AWzVO7iBG5sum4i/GPlr6+ZfDlwkdzgij6QnLw1k/mPO2vwCLp0DeChwJ
|
||||
iPd0+rEcBUT/unOEO5ONqFHQ2Fnmzah509sKHZk/fKD51Z7dE1ju7w094kqLhRgM
|
||||
hviXTRhUwFK4EDgauIoGcaXneBEAW58ZkjQoDxk/sFfqEWkpyu0FNgj2jexdNHmS
|
||||
jkzgHKStGjGQtxZg2uOP7upm3xPoRo2j4jsK9YcUPUsU6tqJx67gYOOgTAQvoQ+p
|
||||
hFpa9z1Pe9R84c3viyhFGeqpTJ5Z+EFDEHeJCT4w0OlYlkUHUA5NzGpTnmTEiuBR
|
||||
ljrGiuKUr5wmmv7jes3MVWDw3L/zDehp5M9J4fTSh5Exz0L3LKf3e4iQ5BeW9jTS
|
||||
v6FmPAPbqgf6psNL0ynR0UBvp4ilf71f9QCU21NdJA==
|
||||
-----END CERTIFICATE-----
|
Binary file not shown.
|
@ -0,0 +1,22 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDmTCCAoGgAwIBAgIJAKmiuSJghxIGMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNV
|
||||
BAYTAlVTMQ0wCwYDVQQIEwRUZXN0MQ0wCwYDVQQHEwRUZXN0MQ0wCwYDVQQKEwRU
|
||||
ZXN0MQ0wCwYDVQQLEwRUZXN0MQ0wCwYDVQQDEwRUZXN0MSEwHwYJKoZIhvcNAQkB
|
||||
FhJ0ZXN0QGVtYWlsLmFkZHJlc3MwHhcNMTYwNjMwMTc1NzU1WhcNMTcwNjMwMTc1
|
||||
NzU1WjB7MQswCQYDVQQGEwJVUzENMAsGA1UECBMEVGVzdDENMAsGA1UEBxMEVGVz
|
||||
dDENMAsGA1UEChMEVGVzdDENMAsGA1UECxMEVGVzdDENMAsGA1UEAxMEVGVzdDEh
|
||||
MB8GCSqGSIb3DQEJARYSdGVzdEBlbWFpbC5hZGRyZXNzMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEA4KHdygQZ2/posNLLE/9lR0U57/iQKyFAfzO70RA5
|
||||
9mYZWSQTk8yI4wsDQi75xBjyuhYExsl+9lX6dgV0uEElhkycRemTN9pHmdGLi6of
|
||||
OIpVd5drZGcK19ndPeG5IzFvCpWXfsKuZ2kJf8p9i5XDNhigtYNq5rfLZBOIE3FY
|
||||
HPKBbx9cBaPOL8kjyX8LPwG7tpmNRLAF4XgQZu/AbfWx0jg8UqqJhOKwPQz+YOPY
|
||||
1eJ55BDyDYYiRj70qhQ1jIbfmYbWjg1VOv7LKzzwQWI8gTnKND26+L0D1tAy4joO
|
||||
cV/XM9lWheBCvzWTULqKpy95hyUMTz9mdG3xb5yFEccYwwIDAQABoyAwHjAPBgNV
|
||||
HRMECDAGAQH/AgECMAsGA1UdDwQEAwICBDANBgkqhkiG9w0BAQsFAAOCAQEAPwKA
|
||||
rC4S7P//VbffPNYOdmlu1dOjSSoNgtXC2lwpCy2iuvakasIAaDtseEjHgvcqJ/ty
|
||||
mHeOQu23qAP584ss+GoR7JUjlaTRoXRt/5PQ66HyrJXl/2jWLtT+7yU2+UtOxWSa
|
||||
fE3xUnzZlW4ES0hi+pWCpK+WaEya8q1+ak+i5oF8kQ3nRcT1f0IcOgyYnhvu8GGI
|
||||
Zd7BA8boUhR+L+X52zk6loaOEIwsmsfero9i2pn+JGZKyQfFKI8+bsnYuc7elIbY
|
||||
PER8fGWHid/DoIgQety153LLKtfR/20rYBrlnNtatg3ePTRdFZ1p7lnLPfA+AiV5
|
||||
e1Y6hSfZYXpZRV+Qtw==
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,22 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkzCCAnugAwIBAgIJAKnOrxg9gSXNMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNV
|
||||
BAYTAlVTMQ0wCwYDVQQIEwRUZXN0MQ0wCwYDVQQHEwRUZXN0MQ0wCwYDVQQKEwRU
|
||||
ZXN0MQ0wCwYDVQQLEwRUZXN0MQ0wCwYDVQQDEwRUZXN0MSEwHwYJKoZIhvcNAQkB
|
||||
FhJ0ZXN0QGVtYWlsLmFkZHJlc3MwHhcNMTYwNjMwMTgxOTQyWhcNMTcwNjMwMTgx
|
||||
OTQyWjB7MQswCQYDVQQGEwJVUzENMAsGA1UECBMEVGVzdDENMAsGA1UEBxMEVGVz
|
||||
dDENMAsGA1UEChMEVGVzdDENMAsGA1UECxMEVGVzdDENMAsGA1UEAxMEVGVzdDEh
|
||||
MB8GCSqGSIb3DQEJARYSdGVzdEBlbWFpbC5hZGRyZXNzMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAnhmtSiir3aB5igvVEQlHqIw2K98q336cyjipFq9b
|
||||
Pt1YslTwLfUAagr7224i0tny45PIZ3o1YlBxhEwd/i1tMnCz2+DQyat+p+vVbbiI
|
||||
ceN1ZzRFE4zJV0QjG+H+TOWqzjtdtq04jkdrKMOsp3Lv4NHIuEuLocQLPLuT79wP
|
||||
VUO+BCHlU/0bUQHhAU/Jx9B81GQ1/4lYS400AYtANSEccMR1djUTjFha4wiwSDH2
|
||||
QZQBgmiqmDhf22uoioFgay9+yhOJ3SJx/lIiMavM2LMgNbns1DcbAD8oKGS69Mmo
|
||||
TsQlgOVMQTIDbwsm3WaxIcY8BipUACSe3E+RdqDrP/MTDwIDAQABoxowGDAJBgNV
|
||||
HRMEAjAAMAsGA1UdDwQEAwIDCDANBgkqhkiG9w0BAQsFAAOCAQEACP8ZAbyAtffS
|
||||
sWZ6WbLcm+BT7FFdUm62gGqC2knaIZQud3AV5/wtj2CAw1lXgGbaCqfWNQrTDY9z
|
||||
PpGXyQ5tvNUtBZG23K7nMvid+U1WDh1fhlRC0kxCK2MsPwv9T5BM3tj/YF0MGWuQ
|
||||
3GlFL8wU8UoAP3alUhxQl5qXqfXc6qfMW2ec4Jb3j6nbezL7ttn15LiBCsvoJ6/V
|
||||
Go9bbox81UrbtxnVin5+cYczUdB+Q9+fe23B/6MG99hzWU9arkkU7ZOlnI/bW9Zb
|
||||
fx4+atZfpi18nyd2ljgiTapB6Ex6uxVPrzwuKxpGMt9wU1++ZYc3YDke4EOT+OIX
|
||||
nKc7UFfjyg==
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,22 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDmTCCAoGgAwIBAgIJAKOf0EhCGUdQMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNV
|
||||
BAYTAlVTMQ0wCwYDVQQIEwRUZXN0MQ0wCwYDVQQHEwRUZXN0MQ0wCwYDVQQKEwRU
|
||||
ZXN0MQ0wCwYDVQQLEwRUZXN0MQ0wCwYDVQQDEwRUZXN0MSEwHwYJKoZIhvcNAQkB
|
||||
FhJ0ZXN0QGVtYWlsLmFkZHJlc3MwHhcNMTYwNjMwMTgxNDMwWhcNMTcwNjMwMTgx
|
||||
NDMwWjB7MQswCQYDVQQGEwJVUzENMAsGA1UECBMEVGVzdDENMAsGA1UEBxMEVGVz
|
||||
dDENMAsGA1UEChMEVGVzdDENMAsGA1UECxMEVGVzdDENMAsGA1UEAxMEVGVzdDEh
|
||||
MB8GCSqGSIb3DQEJARYSdGVzdEBlbWFpbC5hZGRyZXNzMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEA575xHdxVuT5CYPom/PbFdDLt0PgG3CZFkiRNxPAG
|
||||
rDN8cG5ouTw0R9RMBFA+nYcTx/4GnPJmSBEBVqMoPSzsB6Rx9k21KymNlaEs2O1W
|
||||
jSMsYd9gW4NlHdyoomYw0nXQjkstmtdJxDNWg0zSZrHMPnkOVh+JNV58i4FXOx5O
|
||||
bxWo4sSyAvNjAEH9GwDwy+Jz0X4RdFGQrGjm+/v+ohvy8JqU5ZKpz2oP2oQURjDj
|
||||
+AH3ghmgNAVAk0syjtSqydEJd9aeMLTmTaUtP+gPnXdj/ZBj+TQH01RNlSECH2l4
|
||||
WrymS3g4+X5xsA7DeLIbiXB4K1xjbJFCSfDYrV52H/fE6QIDAQABoyAwHjAPBgNV
|
||||
HRMECDAGAQH/AgECMAsGA1UdDwQEAwIDCDANBgkqhkiG9w0BAQsFAAOCAQEARNRE
|
||||
XC8y/RoPLUVAVKJ/RwcH4cwaHoSSu6HnygIpg9Qs7Xc7u1aKCL0dRF1NqfmaqHZ6
|
||||
ZjllxDi5t0CFIXPfDQIYchfSzOafhJGEH3gilBwfmN43N4/eCSvdRKfhRbRFOD9j
|
||||
0JHRAHkn2JRcwSTTjJEcJUJJETAIIbX1ovobJZuJOY0faI1O/Z2KILYrwdmcfnZ5
|
||||
3i0kUps5BWrBrcs70gBsDBugeM24ANa7hJzFk+9TztfLWF1AUfjpZ4Bj/rb21+Gp
|
||||
08FRjvn80Y5bGlNh0Q7Qbu8NS8VbAHHF3t3PUVRymJhIycpvBBBS7dcQqHf+v1gs
|
||||
Z/UpzuobJvnhq+7mcQ==
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,21 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDiDCCAnCgAwIBAgIJAOYNT7MuoypuMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNV
|
||||
BAYTAlVTMQ0wCwYDVQQIEwRUZXN0MQ0wCwYDVQQHEwRUZXN0MQ0wCwYDVQQKEwRU
|
||||
ZXN0MQ0wCwYDVQQLEwRUZXN0MQ0wCwYDVQQDEwRUZXN0MSEwHwYJKoZIhvcNAQkB
|
||||
FhJ0ZXN0QGVtYWlsLmFkZHJlc3MwHhcNMTYwNjMwMTgyMTMyWhcNMTcwNjMwMTgy
|
||||
MTMyWjB7MQswCQYDVQQGEwJVUzENMAsGA1UECBMEVGVzdDENMAsGA1UEBxMEVGVz
|
||||
dDENMAsGA1UEChMEVGVzdDENMAsGA1UECxMEVGVzdDENMAsGA1UEAxMEVGVzdDEh
|
||||
MB8GCSqGSIb3DQEJARYSdGVzdEBlbWFpbC5hZGRyZXNzMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEA3qypxOJ2X0k47SIEkRGvA/ECqzVAX3nsC0yPnbF3
|
||||
14SGe7xFBzi0VMAXOcpVj0BL+G5TL95O5loVN/UnU5/xtjSa712HOOlJfvnqmv63
|
||||
BLq9cMS2strwufeOK3YUtQExtJdxMjcEYuCMt+NlQ3Hl+xNfBc0LXWNBdlusP4fs
|
||||
6sLEgyD4ywSLC9oHzyzgDxi0pr52itu+KnZv2iET/Wotg/8Aiw5Q5fiTc8DoysdZ
|
||||
MF1ix56oGo1SFFGFf+n2iwYbImtNGt6//jKEDP8P4iLdLAxHxmfsXXnl+Zs/6VoA
|
||||
RrnS3Xt7F5xj4CWuoZy4CLo8YXhXdznRQZ2r5Qha65cFNwIDAQABow8wDTALBgNV
|
||||
HQ8EBAMCAwgwDQYJKoZIhvcNAQELBQADggEBALOBnrWz3xMg4Yh92zsXfrSm2uAL
|
||||
P8jgXQtQdsYWSEWcfYNYOSlmLnICweDnAn0V5Kzp0E5wZSHP8Ut4IYEKwe+IF7HA
|
||||
pv3mpg1CYtwVbVsN0dhlLHDVuF27i0r8LuOv9yh0wxY3hPYrd2WvQ/qTP8NO0EoD
|
||||
fM8w2fjNeTu2jB+lYWhGWOHfzEvltosxMZIPWBJxrh3PbYdbuJJZlm/NPqj5Urxx
|
||||
nRB89AEBHKEKHlmNIMMOM3mQ+ShssgGrbRV6U6iJ5qv4H5RdaZtmXMGhjt8dFJrD
|
||||
A2YZYW15QLQDEyud4flSztaw6UMHJi+4FChBAnuJuOcNRZA83v3szuM9t64=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,21 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDXTCCAkWgAwIBAgIJAI20mCsVbBjpMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
|
||||
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
|
||||
aWRnaXRzIFB0eSBMdGQwHhcNMTYwNjMwMTM0NTU5WhcNMTcwNjMwMTM0NTU5WjBF
|
||||
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
|
||||
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||
CgKCAQEA5NjoTq0D6LM6z7V16E1+Eul25L6X1BSLcppsHhVMB/NM1e7hjoUtAODv
|
||||
71L/bAAgV4ky4aphOfwYQLfeAP8nkq4CU30LaAyAQwrT4RyW1NG7AA00xylauebt
|
||||
sc2GUUy06gQ0Z6OjjEfA5HA4W+HYfeyuNzQpWXHWz/6K8xcKb9w10qAjDhNilHbj
|
||||
3RVtL6u6rsZgQi0DlMxpHsp6gLezIRMN72B/AOKrzaobw4nY4hOVkqbRlOHB/tsk
|
||||
4BJLUuW5WM30TVpfsKe07jCBgqUwb9XD9lZa1alkFRsSTZoWijeQBM6kiLD/VFNC
|
||||
YlIKBrN7HZtfOlqhftMknCsoyrWsjQIDAQABo1AwTjAdBgNVHQ4EFgQUnDu25deh
|
||||
bIOsCaj3LAcE9r2gx0QwHwYDVR0jBBgwFoAUnDu25dehbIOsCaj3LAcE9r2gx0Qw
|
||||
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAowntOCmRXKgz7M6hnbQc
|
||||
sEyIt5tN3QILHSeprVO7/ONVIiPJMCfB+S8gJKJ0d5R0xXDYN/6+HyYlgfaL33Gt
|
||||
HY75y8MRnfqpgbEWhXWsBkxgeuqWiM/OFMTqLtgkVbxsVzoUl6V+tHsZaaM9yuyb
|
||||
iUBM9McAPGIgodpMGG86BV6qg07VjqWjl5pBUU4B2zvvzZjwrC8jqUYksVESHB9U
|
||||
WBzwfPLXoj0PUfAog34ZtT33UXX8M3oXTw+yb/hx0rContYMc78Lnlk6mV9gGG+X
|
||||
+3gSwAHn0SMZNNkKc3gdb1CLfluvHw2Od2jat0yfHHawh1JBtnfHrAU0px3Kzw5U
|
||||
0A==
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,26 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIEWzCCA0OgAwIBAgIBATANBgkqhkiG9w0BAQsFADB7MQswCQYDVQQGEwJVUzEN
|
||||
MAsGA1UECBMEVGVzdDENMAsGA1UEBxMEVGVzdDENMAsGA1UEChMEVGVzdDENMAsG
|
||||
A1UECxMEVGVzdDENMAsGA1UEAxMEVGVzdDEhMB8GCSqGSIb3DQEJARYSdGVzdEBl
|
||||
bWFpbC5hZGRyZXNzMB4XDTE2MDYzMDE5NDA1N1oXDTE3MDYzMDE5NDA1N1owbzEL
|
||||
MAkGA1UEBhMCVVMxDTALBgNVBAgMBFRlc3QxDTALBgNVBAoMBFRlc3QxDTALBgNV
|
||||
BAsMBFRlc3QxDzANBgNVBAMMBkNsaWVudDEiMCAGCSqGSIb3DQEJARYTdGVzdEBj
|
||||
bGllbnQuYWRkcmVzczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALOK
|
||||
dKWvu8NLDee4KvHf5WmmJsNeqrfZt+5EBXlp9wEJ3i//6vRpZe9Gr/k3xfbQPVng
|
||||
PS8LUBancZ/zPos6ZibUuJi+ZjgVXUm61S18536wq4S1LH4Hkb4RgJW+IKqlqi0z
|
||||
RVC3xeNcUhGprcH9JtjinOusQ1HLWy4mSr5aaCfCVshj3YEN5uCrfDOXPkS5B1kd
|
||||
kpnEZJt2tAUPLlIKD4Ytjq9A84bL6wHTrUg5NmZ8j+yfXfD0qE1rN69AZFQ2V72R
|
||||
uKUbxvvx2T8ObJh1VpiSlMLLEeoEY1OUCZWB+Xz6GX9uL9B9zeD0+f9WcswI3UCw
|
||||
9WEFgDHYWxgFciu7IYsCAwEAAaOB9TCB8jAJBgNVHRMEAjAAMCwGCWCGSAGG+EIB
|
||||
DQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUDs4X
|
||||
d7VArujtnCJ3Ppht7hSfdL0wgZcGA1UdIwSBjzCBjKF/pH0wezELMAkGA1UEBhMC
|
||||
VVMxDTALBgNVBAgTBFRlc3QxDTALBgNVBAcTBFRlc3QxDTALBgNVBAoTBFRlc3Qx
|
||||
DTALBgNVBAsTBFRlc3QxDTALBgNVBAMTBFRlc3QxITAfBgkqhkiG9w0BCQEWEnRl
|
||||
c3RAZW1haWwuYWRkcmVzc4IJAKmiuSJghxIGMA0GCSqGSIb3DQEBCwUAA4IBAQBm
|
||||
f2VVj4Eqb+5pAgimkejDrYRzDgDQ4Eyr45vdUtu7JoGovGmkxg5z3izW/UKKj8GC
|
||||
04aXIJiIu8d7mn5ZxuaIS0/mtVN167tVVI0wBlkQRK5dJNjn47fTixymEy4lwdUl
|
||||
0iSb1JP6beVmSMIywD5lFxGPiW/MEJSvDCdlOT2Ojiv/Sbn9Q09PsXei0fAmNGZn
|
||||
FEUSnlqgWkeGIIv3+//kY8pHlZ1RyYSShQ+3Vb8Qifx0lbiFQWDP82EgETu7JKWn
|
||||
fKCoogSDybcLqB/WeGOQ0myXgEth5Lhkdo0n08J/FYL/bA1thADVnV66ZpERgb3h
|
||||
38P4rEcobzZdVPcS4zwP
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,403 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
import mock
|
||||
import os
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography import x509
|
||||
|
||||
from cursive import certificate_utils
|
||||
from cursive import exception
|
||||
from cursive.tests import base
|
||||
|
||||
|
||||
class TestCertificateUtils(base.TestCase):
|
||||
"""Test methods for the certificate verification context and utilities"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestCertificateUtils, self).setUp()
|
||||
|
||||
self.cert_path = os.path.join(
|
||||
os.path.dirname(os.path.realpath(__file__)),
|
||||
'data'
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
super(TestCertificateUtils, self).tearDown()
|
||||
|
||||
def load_certificate(self, cert_name):
|
||||
# Load the raw certificate file data.
|
||||
path = os.path.join(self.cert_path, cert_name)
|
||||
with open(path, 'rb') as cert_file:
|
||||
data = cert_file.read()
|
||||
|
||||
# Convert the raw certificate data into a certificate object, first
|
||||
# as a PEM-encoded certificate and, if that fails, then as a
|
||||
# DER-encoded certificate. If both fail, the certificate cannot be
|
||||
# loaded.
|
||||
try:
|
||||
return x509.load_pem_x509_certificate(data, default_backend())
|
||||
except Exception:
|
||||
try:
|
||||
return x509.load_der_x509_certificate(data, default_backend())
|
||||
except Exception:
|
||||
raise exception.SignatureVerificationError(
|
||||
"Failed to load certificate: %s" % path
|
||||
)
|
||||
|
||||
def load_certificates(self, cert_names):
|
||||
certs = list()
|
||||
for cert_name in cert_names:
|
||||
cert = self.load_certificate(cert_name)
|
||||
certs.append(cert)
|
||||
return certs
|
||||
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_is_within_valid_dates(self, mock_utcnow):
|
||||
# Verify a certificate is valid at a time within its valid date range
|
||||
cert = self.load_certificate('self_signed_cert.pem')
|
||||
mock_utcnow.return_value = datetime.datetime(2017, 1, 1)
|
||||
result = certificate_utils.is_within_valid_dates(cert)
|
||||
self.assertEqual(True, result)
|
||||
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_is_before_valid_dates(self, mock_utcnow):
|
||||
# Verify a certificate is invalid at a time before its valid date range
|
||||
cert = self.load_certificate('self_signed_cert.pem')
|
||||
mock_utcnow.return_value = datetime.datetime(2000, 1, 1)
|
||||
result = certificate_utils.is_within_valid_dates(cert)
|
||||
self.assertEqual(False, result)
|
||||
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_is_after_valid_dates(self, mock_utcnow):
|
||||
# Verify a certificate is invalid at a time after its valid date range
|
||||
cert = self.load_certificate('self_signed_cert.pem')
|
||||
mock_utcnow.return_value = datetime.datetime(2100, 1, 1)
|
||||
result = certificate_utils.is_within_valid_dates(cert)
|
||||
self.assertEqual(False, result)
|
||||
|
||||
def test_is_issuer(self):
|
||||
# Test issuer and subject name matching for a self-signed certificate.
|
||||
cert = self.load_certificate('self_signed_cert.pem')
|
||||
result = certificate_utils.is_issuer(cert, cert)
|
||||
self.assertEqual(True, result)
|
||||
|
||||
def test_is_not_issuer(self):
|
||||
# Test issuer and subject name mismatching.
|
||||
cert = self.load_certificate('self_signed_cert.pem')
|
||||
alt = self.load_certificate('orphaned_cert.pem')
|
||||
result = certificate_utils.is_issuer(cert, alt)
|
||||
self.assertEqual(False, result)
|
||||
|
||||
def test_is_issuer_with_invalid_certs(self):
|
||||
# Test issuer check with invalid certificates
|
||||
cert = self.load_certificate('self_signed_cert.pem')
|
||||
result = certificate_utils.is_issuer(cert, None)
|
||||
self.assertEqual(False, result)
|
||||
result = certificate_utils.is_issuer(None, cert)
|
||||
self.assertEqual(False, result)
|
||||
|
||||
def test_can_sign_certificates(self):
|
||||
# Test that a well-formatted certificate can sign
|
||||
cert = self.load_certificate('self_signed_cert.pem')
|
||||
result = certificate_utils.can_sign_certificates(cert, 'test-ID')
|
||||
self.assertEqual(True, result)
|
||||
|
||||
def test_cannot_sign_certificates_without_basic_constraints(self):
|
||||
# Verify a certificate without basic constraints cannot sign
|
||||
cert = self.load_certificate(
|
||||
'self_signed_cert_missing_ca_constraint.pem'
|
||||
)
|
||||
result = certificate_utils.can_sign_certificates(cert, 'test-ID')
|
||||
self.assertEqual(False, result)
|
||||
|
||||
def test_cannot_sign_certificates_with_invalid_basic_constraints(self):
|
||||
# Verify a certificate with invalid basic constraints cannot sign
|
||||
cert = self.load_certificate(
|
||||
'self_signed_cert_invalid_ca_constraint.pem'
|
||||
)
|
||||
result = certificate_utils.can_sign_certificates(cert, 'test-ID')
|
||||
self.assertEqual(False, result)
|
||||
|
||||
def test_cannot_sign_certificates_without_key_usage(self):
|
||||
# Verify a certificate without key usage cannot sign
|
||||
cert = self.load_certificate('self_signed_cert_missing_key_usage.pem')
|
||||
result = certificate_utils.can_sign_certificates(cert, 'test-ID')
|
||||
self.assertEqual(False, result)
|
||||
|
||||
def test_cannot_sign_certificates_with_invalid_key_usage(self):
|
||||
# Verify a certificate with invalid key usage cannot sign
|
||||
cert = self.load_certificate('self_signed_cert_invalid_key_usage.pem')
|
||||
result = certificate_utils.can_sign_certificates(cert, 'test-ID')
|
||||
self.assertEqual(False, result)
|
||||
|
||||
def test_verify_signing_certificate(self):
|
||||
signing_certificate = self.load_certificate('self_signed_cert.pem')
|
||||
signed_certificate = self.load_certificate('signed_cert.pem')
|
||||
|
||||
certificate_utils.verify_certificate_signature(
|
||||
signing_certificate,
|
||||
signed_certificate
|
||||
)
|
||||
|
||||
@mock.patch('cursive.signature_utils.get_certificate')
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_verify_valid_certificate(self, mock_utcnow, mock_get_cert):
|
||||
mock_utcnow.return_value = datetime.datetime(2017, 1, 1)
|
||||
certs = self.load_certificates(
|
||||
['self_signed_cert.pem', 'self_signed_cert.der',
|
||||
'signed_cert.pem']
|
||||
)
|
||||
mock_get_cert.side_effect = certs
|
||||
cert_uuid = '3'
|
||||
trusted_cert_uuids = ['1', '2']
|
||||
certificate_utils.verify_certificate(
|
||||
None, cert_uuid, trusted_cert_uuids
|
||||
)
|
||||
|
||||
@mock.patch('cursive.signature_utils.get_certificate')
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_verify_invalid_certificate(self, mock_utcnow, mock_get_cert):
|
||||
mock_utcnow.return_value = datetime.datetime(2017, 1, 1)
|
||||
certs = self.load_certificates(
|
||||
['self_signed_cert.pem', 'self_signed_cert.der',
|
||||
'orphaned_cert.pem']
|
||||
)
|
||||
mock_get_cert.side_effect = certs
|
||||
cert_uuid = '3'
|
||||
trusted_cert_uuids = ['1', '2']
|
||||
self.assertRaisesRegex(
|
||||
exception.SignatureVerificationError,
|
||||
"Certificate chain building failed. Could not locate the "
|
||||
"signing certificate for the base certificate in the set of "
|
||||
"trusted certificates.",
|
||||
certificate_utils.verify_certificate,
|
||||
None,
|
||||
cert_uuid,
|
||||
trusted_cert_uuids
|
||||
)
|
||||
|
||||
@mock.patch('cursive.signature_utils.get_certificate')
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_verify_valid_certificate_with_no_root(self, mock_utcnow,
|
||||
mock_get_cert):
|
||||
mock_utcnow.return_value = datetime.datetime(2017, 1, 1)
|
||||
|
||||
# Test verifying a valid certificate against an empty list of trusted
|
||||
# certificates.
|
||||
certs = self.load_certificates(['signed_cert.pem'])
|
||||
mock_get_cert.side_effect = certs
|
||||
cert_uuid = '3'
|
||||
trusted_cert_uuids = []
|
||||
self.assertRaisesRegex(
|
||||
exception.SignatureVerificationError,
|
||||
"Certificate chain building failed. Could not locate the "
|
||||
"signing certificate for the base certificate in the set of "
|
||||
"trusted certificates.",
|
||||
certificate_utils.verify_certificate,
|
||||
None,
|
||||
cert_uuid,
|
||||
trusted_cert_uuids
|
||||
)
|
||||
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_context_init(self, mock_utcnow):
|
||||
# Test constructing a context object with a valid set of certificates
|
||||
mock_utcnow.return_value = datetime.datetime(2017, 1, 1)
|
||||
certs = self.load_certificates(
|
||||
['self_signed_cert.pem', 'self_signed_cert.der']
|
||||
)
|
||||
cert_tuples = [('1', certs[0]), ('2', certs[1])]
|
||||
context = certificate_utils.CertificateVerificationContext(
|
||||
cert_tuples
|
||||
)
|
||||
self.assertEqual(2, len(context._signing_certificates))
|
||||
for t in cert_tuples:
|
||||
path, cert = t
|
||||
self.assertIn(cert, [x[1] for x in context._signing_certificates])
|
||||
|
||||
@mock.patch('cursive.certificate_utils.LOG')
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_context_init_with_invalid_certificate(self, mock_utcnow,
|
||||
mock_log):
|
||||
# Test constructing a context object with an invalid certificate
|
||||
mock_utcnow.return_value = datetime.datetime(2017, 1, 1)
|
||||
alt_cert_tuples = [('path', None)]
|
||||
context = certificate_utils.CertificateVerificationContext(
|
||||
alt_cert_tuples
|
||||
)
|
||||
self.assertEqual(0, len(context._signing_certificates))
|
||||
self.assertEqual(1, mock_log.error.call_count)
|
||||
|
||||
@mock.patch('cursive.certificate_utils.LOG')
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_context_init_with_non_signing_certificate(self, mock_utcnow,
|
||||
mock_log):
|
||||
# Test constructing a context object with an non-signing certificate
|
||||
mock_utcnow.return_value = datetime.datetime(2017, 1, 1)
|
||||
non_signing_cert = self.load_certificate(
|
||||
'self_signed_cert_missing_key_usage.pem'
|
||||
)
|
||||
alt_cert_tuples = [('path', non_signing_cert)]
|
||||
context = certificate_utils.CertificateVerificationContext(
|
||||
alt_cert_tuples
|
||||
)
|
||||
self.assertEqual(0, len(context._signing_certificates))
|
||||
self.assertEqual(1, mock_log.warning.call_count)
|
||||
|
||||
@mock.patch('cursive.certificate_utils.LOG')
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_context_init_with_out_of_date_certificate(self, mock_utcnow,
|
||||
mock_log):
|
||||
# Test constructing a context object with out-of-date certificates
|
||||
mock_utcnow.return_value = datetime.datetime(2100, 1, 1)
|
||||
certs = self.load_certificates(
|
||||
['self_signed_cert.pem', 'self_signed_cert.der']
|
||||
)
|
||||
cert_tuples = [('1', certs[0]), ('2', certs[1])]
|
||||
context = certificate_utils.CertificateVerificationContext(cert_tuples)
|
||||
self.assertEqual(0, len(context._signing_certificates))
|
||||
self.assertEqual(2, mock_log.warning.call_count)
|
||||
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_context_update_with_valid_certificate(self, mock_utcnow):
|
||||
# Test updating the context with a valid certificate
|
||||
mock_utcnow.return_value = datetime.datetime(2017, 1, 1)
|
||||
certs = self.load_certificates(
|
||||
['self_signed_cert.pem', 'self_signed_cert.der']
|
||||
)
|
||||
cert_tuples = [('1', certs[0]), ('2', certs[1])]
|
||||
context = certificate_utils.CertificateVerificationContext(cert_tuples)
|
||||
cert = self.load_certificate('orphaned_cert.pem')
|
||||
context.update(cert)
|
||||
self.assertEqual(cert, context._signed_certificate)
|
||||
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_context_update_with_date_invalid_certificate(self, mock_utcnow):
|
||||
# Test updating the context with an out-of-date certificate
|
||||
mock_utcnow.return_value = datetime.datetime(2017, 1, 1)
|
||||
certs = self.load_certificates(
|
||||
['self_signed_cert.pem', 'self_signed_cert.der']
|
||||
)
|
||||
cert_tuples = [('1', certs[0]), ('2', certs[1])]
|
||||
context = certificate_utils.CertificateVerificationContext(cert_tuples)
|
||||
cert = self.load_certificate('orphaned_cert.pem')
|
||||
mock_utcnow.return_value = datetime.datetime(2100, 1, 1)
|
||||
self.assertRaisesRegex(
|
||||
exception.SignatureVerificationError,
|
||||
"The certificate is outside its valid date range.",
|
||||
context.update,
|
||||
cert
|
||||
)
|
||||
|
||||
def test_context_update_with_invalid_certificate(self):
|
||||
# Test updating the context with an invalid certificate
|
||||
certs = self.load_certificates(
|
||||
['self_signed_cert.pem', 'self_signed_cert.der']
|
||||
)
|
||||
cert_tuples = [('1', certs[0]), ('2', certs[1])]
|
||||
context = certificate_utils.CertificateVerificationContext(
|
||||
cert_tuples
|
||||
)
|
||||
|
||||
self.assertRaisesRegex(
|
||||
exception.SignatureVerificationError,
|
||||
"The certificate must be an x509.Certificate object.",
|
||||
context.update,
|
||||
None
|
||||
)
|
||||
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_context_verify(self, mock_utcnow):
|
||||
mock_utcnow.return_value = datetime.datetime(2017, 1, 1)
|
||||
certs = self.load_certificates(
|
||||
['self_signed_cert.pem', 'self_signed_cert.der']
|
||||
)
|
||||
cert_tuples = [('1', certs[0]), ('2', certs[1])]
|
||||
|
||||
# Test verification with a two-link certificate chain.
|
||||
context = certificate_utils.CertificateVerificationContext(
|
||||
cert_tuples
|
||||
)
|
||||
cert = self.load_certificate('signed_cert.pem')
|
||||
context.update(cert)
|
||||
context.verify()
|
||||
|
||||
# Test verification with a single-link certificate chain.
|
||||
context = certificate_utils.CertificateVerificationContext(
|
||||
cert_tuples
|
||||
)
|
||||
context.update(certs[0])
|
||||
context.verify()
|
||||
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_context_verify_disable_checks(self, mock_utcnow):
|
||||
mock_utcnow.return_value = datetime.datetime(2017, 1, 1)
|
||||
certs = self.load_certificates(
|
||||
['self_signed_cert.pem', 'self_signed_cert.der']
|
||||
)
|
||||
cert_tuples = [('1', certs[0]), ('2', certs[1])]
|
||||
|
||||
# Test verification with a two-link certificate chain.
|
||||
context = certificate_utils.CertificateVerificationContext(
|
||||
cert_tuples,
|
||||
enforce_valid_dates=False,
|
||||
enforce_signing_extensions=False,
|
||||
enforce_path_length=False
|
||||
)
|
||||
cert = self.load_certificate('signed_cert.pem')
|
||||
context.update(cert)
|
||||
context.verify()
|
||||
|
||||
# Test verification with a single-link certificate chain.
|
||||
context = certificate_utils.CertificateVerificationContext(
|
||||
cert_tuples,
|
||||
enforce_valid_dates=False,
|
||||
enforce_signing_extensions=False,
|
||||
enforce_path_length=False
|
||||
)
|
||||
context.update(certs[0])
|
||||
context.verify()
|
||||
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_context_verify_invalid_chain_length(self, mock_utcnow):
|
||||
mock_utcnow.return_value = datetime.datetime(2017, 11, 1)
|
||||
certs = self.load_certificates(
|
||||
['grandparent_cert.pem', 'parent_cert.pem', 'child_cert.pem']
|
||||
)
|
||||
cert_tuples = [
|
||||
('1', certs[0]),
|
||||
('2', certs[1]),
|
||||
('3', certs[2])
|
||||
]
|
||||
cert = self.load_certificate('grandchild_cert.pem')
|
||||
|
||||
context = certificate_utils.CertificateVerificationContext(
|
||||
cert_tuples
|
||||
)
|
||||
context.update(cert)
|
||||
self.assertRaisesRegex(
|
||||
exception.SignatureVerificationError,
|
||||
"Certificate validation failed. The signing certificate '1' is "
|
||||
"not configured to support certificate chains of sufficient "
|
||||
"length.",
|
||||
context.verify
|
||||
)
|
||||
|
||||
context = certificate_utils.CertificateVerificationContext(
|
||||
cert_tuples,
|
||||
enforce_path_length=False
|
||||
)
|
||||
context.update(cert)
|
||||
context.verify()
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
import base64
|
||||
import datetime
|
||||
import mock
|
||||
|
||||
from castellan.common.exception import KeyManagerError
|
||||
import cryptography.exceptions as crypto_exceptions
|
||||
|
@ -20,7 +21,6 @@ from cryptography.hazmat.primitives.asymmetric import dsa
|
|||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
from cryptography.hazmat.primitives.asymmetric import padding
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
import mock
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from cursive import exception
|
||||
|
@ -110,6 +110,12 @@ class BadPublicKey(object):
|
|||
class TestSignatureUtils(base.TestCase):
|
||||
"""Test methods of signature_utils"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestSignatureUtils, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestSignatureUtils, self).tearDown()
|
||||
|
||||
def test_should_create_verifier(self):
|
||||
image_props = {CERT_UUID: 'CERT_UUID',
|
||||
HASH_METHOD: 'HASH_METHOD',
|
||||
|
@ -283,7 +289,8 @@ class TestSignatureUtils(base.TestCase):
|
|||
'RSB-PSS')
|
||||
|
||||
@mock.patch('cursive.signature_utils.get_certificate')
|
||||
def test_get_public_key_rsa(self, mock_get_cert):
|
||||
@mock.patch('cursive.certificate_utils.verify_certificate')
|
||||
def test_get_public_key_rsa(self, mock_verify_cert, mock_get_cert):
|
||||
fake_cert = FakeCryptoCertificate()
|
||||
mock_get_cert.return_value = fake_cert
|
||||
sig_key_type = signature_utils.SignatureKeyType.lookup(
|
||||
|
@ -294,7 +301,8 @@ class TestSignatureUtils(base.TestCase):
|
|||
self.assertEqual(fake_cert.public_key(), result_pub_key)
|
||||
|
||||
@mock.patch('cursive.signature_utils.get_certificate')
|
||||
def test_get_public_key_ecc(self, mock_get_cert):
|
||||
@mock.patch('cursive.certificate_utils.verify_certificate')
|
||||
def test_get_public_key_ecc(self, mock_verify_cert, mock_get_cert):
|
||||
fake_cert = FakeCryptoCertificate(TEST_ECC_PRIVATE_KEY.public_key())
|
||||
mock_get_cert.return_value = fake_cert
|
||||
sig_key_type = signature_utils.SignatureKeyType.lookup('ECC_SECP521R1')
|
||||
|
@ -303,7 +311,8 @@ class TestSignatureUtils(base.TestCase):
|
|||
self.assertEqual(fake_cert.public_key(), result_pub_key)
|
||||
|
||||
@mock.patch('cursive.signature_utils.get_certificate')
|
||||
def test_get_public_key_dsa(self, mock_get_cert):
|
||||
@mock.patch('cursive.certificate_utils.verify_certificate')
|
||||
def test_get_public_key_dsa(self, mock_verify_cert, mock_get_cert):
|
||||
fake_cert = FakeCryptoCertificate(TEST_DSA_PRIVATE_KEY.public_key())
|
||||
mock_get_cert.return_value = fake_cert
|
||||
sig_key_type = signature_utils.SignatureKeyType.lookup(
|
||||
|
@ -314,7 +323,9 @@ class TestSignatureUtils(base.TestCase):
|
|||
self.assertEqual(fake_cert.public_key(), result_pub_key)
|
||||
|
||||
@mock.patch('cursive.signature_utils.get_certificate')
|
||||
def test_get_public_key_invalid_key(self, mock_get_certificate):
|
||||
@mock.patch('cursive.certificate_utils.verify_certificate')
|
||||
def test_get_public_key_invalid_key(self, mock_verify_certificate,
|
||||
mock_get_certificate):
|
||||
bad_pub_key = 'A' * 256
|
||||
mock_get_certificate.return_value = FakeCryptoCertificate(bad_pub_key)
|
||||
sig_key_type = signature_utils.SignatureKeyType.lookup(
|
||||
|
@ -335,34 +346,6 @@ class TestSignatureUtils(base.TestCase):
|
|||
self.assertEqual(x509_cert,
|
||||
signature_utils.get_certificate(None, cert_uuid))
|
||||
|
||||
@mock.patch('cryptography.x509.load_der_x509_certificate')
|
||||
@mock.patch('castellan.key_manager.API', return_value=FakeKeyManager())
|
||||
def test_get_expired_certificate(self, mock_key_manager_API,
|
||||
mock_load_cert):
|
||||
cert_uuid = 'valid_format_cert'
|
||||
x509_cert = FakeCryptoCertificate(
|
||||
not_valid_after=timeutils.utcnow() -
|
||||
datetime.timedelta(hours=1))
|
||||
mock_load_cert.return_value = x509_cert
|
||||
self.assertRaisesRegex(exception.SignatureVerificationError,
|
||||
'Certificate is not valid after: .*',
|
||||
signature_utils.get_certificate, None,
|
||||
cert_uuid)
|
||||
|
||||
@mock.patch('cryptography.x509.load_der_x509_certificate')
|
||||
@mock.patch('castellan.key_manager.API', return_value=FakeKeyManager())
|
||||
def test_get_not_yet_valid_certificate(self, mock_key_manager_API,
|
||||
mock_load_cert):
|
||||
cert_uuid = 'valid_format_cert'
|
||||
x509_cert = FakeCryptoCertificate(
|
||||
not_valid_before=timeutils.utcnow() +
|
||||
datetime.timedelta(hours=1))
|
||||
mock_load_cert.return_value = x509_cert
|
||||
self.assertRaisesRegex(exception.SignatureVerificationError,
|
||||
'Certificate is not valid before: .*',
|
||||
signature_utils.get_certificate, None,
|
||||
cert_uuid)
|
||||
|
||||
@mock.patch('castellan.key_manager.API', return_value=FakeKeyManager())
|
||||
def test_get_certificate_key_manager_fail(self, mock_key_manager_API):
|
||||
bad_cert_uuid = 'fea14bc2-d75f-4ba5-bccc-b5c924ad0695'
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
prelude: >
|
||||
The cursive library supports the verification of digital signatures.
|
||||
However, there is no way currently to validate the certificate used to
|
||||
generate a given signature. Adding certificate validation improves the
|
||||
security of signature verification when each is used together.
|
||||
features:
|
||||
- Adds a variety of certificate utility functions that inspect certificate
|
||||
attributes and extensions for different settings.
|
||||
- Adds the CertificateVerificationContext class which uses a set of
|
||||
trusted certificates to conduct certificate validation, verifying that a
|
||||
given certificate is part of a certificate chain rooted with a trusted
|
||||
certificate.
|
||||
- Adds a verify_certificate method that loads all certificates needed for
|
||||
certificate validation from the key manager and uses them to create a
|
||||
CertificateVerificationContext object. The context is then used to
|
||||
determine if a certificate is valid.
|
||||
upgrade:
|
||||
- The addition of certificate validation as a separate operation from the
|
||||
signature verification process preserves backwards compatibility.
|
||||
Signatures previously verifiable with cursive will still be verifiable.
|
||||
However, their signing certificates may not be valid. Each signing
|
||||
certificate should be checked for validity before it is used to conduct
|
||||
signature verification.
|
||||
security:
|
||||
- The usage of certificate validation with the signature verification
|
||||
process improves the security of signature verification. A signature
|
||||
should not be considered valid unless its corresponding certificate is
|
||||
also valid.
|
||||
other:
|
||||
- The CertificateVerificationContext is built using a set of trusted
|
||||
certificates. However, to conduct certificate verification the context
|
||||
builds the full certificate chain, starting with the certificate to
|
||||
validate and ending with the self-signed root certificate. If this
|
||||
self-signed root certificate is not present in the context, or if one
|
||||
of the intermediate certificates is not present in the context, the
|
||||
certificate chain cannot be built and certificate validation will fail.
|
Loading…
Reference in New Issue