Fix unit tests certificates to have correct chains and private keys

In preparation for certificate integrity-checking: invalid certificate
chains and mismatching private keys will no longer be allowed anywhere
in Lemur code.

The test vector certs were generated using the Lemur "cryptography"
authority plugin.

* Certificates are now more similar to real-world usage: long serial
  numbers, etc.
* Private key is included for all certs, so it's easy to re-generate
  anything if needed.
This commit is contained in:
Marti Raudsepp 2018-06-25 18:42:18 +03:00
parent acd2701fa2
commit 1f0f432327
13 changed files with 310 additions and 182 deletions

View File

@ -1,7 +1,7 @@
import pytest
from moto import mock_iam, mock_sts
from lemur.tests.vectors import EXTERNAL_VALID_STR, PRIVATE_KEY_STR
from lemur.tests.vectors import EXTERNAL_VALID_STR, SAN_CERT_KEY
def test_get_name_from_arn():
@ -15,6 +15,6 @@ def test_get_name_from_arn():
@mock_iam()
def test_get_all_server_certs(app):
from lemur.plugins.lemur_aws.iam import upload_cert, get_all_certificates
upload_cert('123456789012', 'testCert', EXTERNAL_VALID_STR, PRIVATE_KEY_STR)
upload_cert('123456789012', 'testCert', EXTERNAL_VALID_STR, SAN_CERT_KEY)
certs = get_all_certificates('123456789012')
assert len(certs) == 1

View File

@ -16,7 +16,7 @@ def test_formatting(certificate):
},
{
'short': True,
'value': u'Wednesday, January 1, 2020',
'value': u'Tuesday, December 31, 2047',
'title': 'Expires'
}, {
'short': True,

View File

@ -23,7 +23,8 @@ LEMUR_ENCRYPTION_KEYS = 'o61sBLNBSGtAckngtNrfVNd8xy8Hp9LBGDstTbMbqCY='
# List of domain regular expressions that non-admin users can issue
LEMUR_WHITELISTED_DOMAINS = [
'^[a-zA-Z0-9-]+\.example\.com$'
'^[a-zA-Z0-9-]+\.example\.com$',
'^[a-zA-Z0-9-]+\.example\.org$',
]
# Mail Server

View File

@ -11,7 +11,7 @@ from flask_principal import identity_changed, Identity
from lemur import create_app
from lemur.database import db as _db
from lemur.auth.service import create_token
from lemur.tests.vectors import PRIVATE_KEY_STR
from lemur.tests.vectors import SAN_CERT_KEY
from .factories import ApiKeyFactory, AuthorityFactory, NotificationFactory, DestinationFactory, \
CertificateFactory, UserFactory, RoleFactory, SourceFactory, EndpointFactory, \
@ -228,7 +228,7 @@ def logged_in_admin(session, app):
@pytest.fixture
def private_key():
return load_pem_private_key(PRIVATE_KEY_STR.encode(), password=None, backend=default_backend())
return load_pem_private_key(SAN_CERT_KEY.encode(), password=None, backend=default_backend())
@pytest.fixture

View File

@ -19,7 +19,8 @@ from lemur.endpoints.models import Policy, Endpoint
from lemur.policies.models import RotationPolicy
from lemur.api_keys.models import ApiKey
from .vectors import INTERNAL_VALID_SAN_STR, PRIVATE_KEY_STR, CSR_STR
from .vectors import SAN_CERT_STR, SAN_CERT_KEY, CSR_STR, INTERMEDIATE_CERT_STR, ROOTCA_CERT_STR, INTERMEDIATE_KEY, \
WILDCARD_CERT_KEY
class BaseFactory(SQLAlchemyModelFactory):
@ -34,9 +35,9 @@ class BaseFactory(SQLAlchemyModelFactory):
class CertificateFactory(BaseFactory):
"""Certificate factory."""
name = Sequence(lambda n: 'certificate{0}'.format(n))
chain = INTERNAL_VALID_SAN_STR
body = INTERNAL_VALID_SAN_STR
private_key = PRIVATE_KEY_STR
chain = INTERMEDIATE_CERT_STR
body = SAN_CERT_STR
private_key = SAN_CERT_KEY
owner = 'joe@example.com'
status = FuzzyChoice(['valid', 'revoked', 'unknown'])
deleted = False
@ -119,13 +120,19 @@ class CertificateFactory(BaseFactory):
self.roles.append(domain)
class CACertificateFactory(CertificateFactory):
chain = ROOTCA_CERT_STR
body = INTERMEDIATE_CERT_STR
private_key = INTERMEDIATE_KEY
class AuthorityFactory(BaseFactory):
"""Authority factory."""
name = Sequence(lambda n: 'authority{0}'.format(n))
owner = 'joe@example.com'
plugin = {'slug': 'test-issuer'}
description = FuzzyText(length=128)
authority_certificate = SubFactory(CertificateFactory)
authority_certificate = SubFactory(CACertificateFactory)
class Meta:
"""Factory configuration."""
@ -299,8 +306,8 @@ class PendingCertificateFactory(BaseFactory):
name = Sequence(lambda n: 'pending_certificate{0}'.format(n))
external_id = 12345
csr = CSR_STR
chain = INTERNAL_VALID_SAN_STR
private_key = PRIVATE_KEY_STR
chain = INTERMEDIATE_CERT_STR
private_key = WILDCARD_CERT_KEY
owner = 'joe@example.com'
status = FuzzyChoice(['valid', 'revoked', 'unknown'])
deleted = False

View File

@ -1,6 +1,6 @@
from lemur.plugins.bases import IssuerPlugin
from lemur.tests.vectors import INTERNAL_VALID_SAN_STR, INTERNAL_VALID_LONG_STR
from lemur.tests.vectors import SAN_CERT_STR, INTERMEDIATE_CERT_STR
class TestIssuerPlugin(IssuerPlugin):
@ -15,12 +15,13 @@ class TestIssuerPlugin(IssuerPlugin):
super(TestIssuerPlugin, self).__init__(*args, **kwargs)
def create_certificate(self, csr, issuer_options):
return INTERNAL_VALID_LONG_STR, INTERNAL_VALID_SAN_STR, None
# body, chain, external_id
return SAN_CERT_STR, INTERMEDIATE_CERT_STR, None
@staticmethod
def create_authority(options):
role = {'username': '', 'password': '', 'name': 'test'}
return INTERNAL_VALID_SAN_STR, "", [role]
return SAN_CERT_STR, "", [role]
class TestAsyncIssuerPlugin(IssuerPlugin):
@ -38,12 +39,12 @@ class TestAsyncIssuerPlugin(IssuerPlugin):
return "", "", 12345
def get_ordered_certificate(self, pending_cert):
return INTERNAL_VALID_LONG_STR, INTERNAL_VALID_SAN_STR, 54321
return INTERMEDIATE_CERT_STR, SAN_CERT_STR, 54321
@staticmethod
def create_authority(options):
role = {'username': '', 'password': '', 'name': 'test'}
return INTERNAL_VALID_SAN_STR, "", [role]
return SAN_CERT_STR, "", [role]
def cancel_ordered_certificate(self, pending_certificate, **kwargs):
return True

View File

@ -18,25 +18,27 @@ from lemur.domains.models import Domain
from lemur.tests.vectors import VALID_ADMIN_API_TOKEN, VALID_ADMIN_HEADER_TOKEN, VALID_USER_HEADER_TOKEN, CSR_STR, \
INTERNAL_VALID_LONG_STR, INTERNAL_VALID_SAN_STR, PRIVATE_KEY_STR
INTERMEDIATE_CERT_STR, SAN_CERT_STR, SAN_CERT_KEY
def test_get_or_increase_name(session, certificate):
from lemur.certificates.models import get_or_increase_name
from lemur.tests.factories import CertificateFactory
assert get_or_increase_name(certificate.name, certificate.serial) == '{0}-3E9'.format(certificate.name)
serial = 'AFF2DB4F8D2D4D8E80FA382AE27C2333'
assert get_or_increase_name(certificate.name, certificate.serial) == '{0}-{1}'.format(certificate.name, serial)
certificate.name = 'test-cert-11111111'
assert get_or_increase_name(certificate.name, certificate.serial) == 'test-cert-11111111-3E9'
assert get_or_increase_name(certificate.name, certificate.serial) == 'test-cert-11111111-' + serial
certificate.name = 'test-cert-11111111-1'
assert get_or_increase_name('test-cert-11111111-1', certificate.serial) == 'test-cert-11111111-1-3E9'
assert get_or_increase_name('test-cert-11111111-1', certificate.serial) == 'test-cert-11111111-1-' + serial
cert2 = CertificateFactory(name='certificate1-3E9')
cert2 = CertificateFactory(name='certificate1-' + serial)
session.commit()
assert get_or_increase_name('certificate1', 1001) == 'certificate1-3E9-1'
assert get_or_increase_name('certificate1', int(serial, 16)) == 'certificate1-{}-1'.format(serial)
def test_get_certificate_primitives(certificate):
@ -59,7 +61,7 @@ def test_certificate_output_schema(session, certificate, issuer_plugin):
# Make sure serialization parses the cert only once (uses cached 'parsed_cert' attribute)
with patch('lemur.common.utils.parse_certificate', side_effect=utils.parse_certificate) as wrapper:
data, errors = CertificateOutputSchema().dump(certificate)
assert data['issuer'] == 'Example'
assert data['issuer'] == 'LemurTrustEnterprisesLtd'
assert wrapper.call_count == 1
@ -149,8 +151,8 @@ def test_certificate_input_schema(client, authority):
'owner': 'jim@example.com',
'authority': {'id': authority.id},
'description': 'testtestest',
'validityEnd': arrow.get(2016, 11, 9).isoformat(),
'validityStart': arrow.get(2015, 11, 9).isoformat(),
'validityStart': arrow.get(2018, 11, 9).isoformat(),
'validityEnd': arrow.get(2019, 11, 9).isoformat(),
'dnsProvider': None,
}
@ -445,16 +447,16 @@ def test_get_account_number(client):
def test_mint_certificate(issuer_plugin, authority):
from lemur.certificates.service import mint
cert_body, private_key, chain, external_id, csr = mint(authority=authority, csr=CSR_STR)
assert cert_body == INTERNAL_VALID_LONG_STR, INTERNAL_VALID_SAN_STR
assert cert_body == SAN_CERT_STR
def test_create_certificate(issuer_plugin, authority, user):
from lemur.certificates.service import create
cert = create(authority=authority, csr=CSR_STR, owner='joe@example.com', creator=user['user'])
assert str(cert.not_after) == '2040-01-01T20:30:52+00:00'
assert str(cert.not_before) == '2015-06-26T20:30:52+00:00'
assert cert.issuer == 'Example'
assert cert.name == 'long.lived.com-Example-20150626-20400101'
assert str(cert.not_after) == '2047-12-31T22:00:00+00:00'
assert str(cert.not_before) == '2017-12-31T22:00:00+00:00'
assert cert.issuer == 'LemurTrustEnterprisesLtd'
assert cert.name == 'SAN-san.example.org-LemurTrustEnterprisesLtd-20171231-20471231-AFF2DB4F8D2D4D8E80FA382AE27C2333'
cert = create(authority=authority, csr=CSR_STR, owner='joe@example.com', name='ACustomName1', creator=user['user'])
assert cert.name == 'ACustomName1'
@ -481,33 +483,33 @@ def test_create_csr():
def test_import(user):
from lemur.certificates.service import import_certificate
cert = import_certificate(body=INTERNAL_VALID_LONG_STR, chain=INTERNAL_VALID_SAN_STR, private_key=PRIVATE_KEY_STR, creator=user['user'])
assert str(cert.not_after) == '2040-01-01T20:30:52+00:00'
assert str(cert.not_before) == '2015-06-26T20:30:52+00:00'
assert cert.issuer == 'Example'
assert cert.name == 'long.lived.com-Example-20150626-20400101-2'
cert = import_certificate(body=SAN_CERT_STR, chain=INTERMEDIATE_CERT_STR, private_key=SAN_CERT_KEY, creator=user['user'])
assert str(cert.not_after) == '2047-12-31T22:00:00+00:00'
assert str(cert.not_before) == '2017-12-31T22:00:00+00:00'
assert cert.issuer == 'LemurTrustEnterprisesLtd'
assert cert.name == 'SAN-san.example.org-LemurTrustEnterprisesLtd-20171231-20471231-AFF2DB4F8D2D4D8E80FA382AE27C2333-2'
cert = import_certificate(body=INTERNAL_VALID_LONG_STR, chain=INTERNAL_VALID_SAN_STR, private_key=PRIVATE_KEY_STR, owner='joe@example.com', name='ACustomName2', creator=user['user'])
cert = import_certificate(body=SAN_CERT_STR, chain=INTERMEDIATE_CERT_STR, private_key=SAN_CERT_KEY, owner='joe@example.com', name='ACustomName2', creator=user['user'])
assert cert.name == 'ACustomName2'
@pytest.mark.skip
def test_upload(user):
from lemur.certificates.service import upload
cert = upload(body=INTERNAL_VALID_LONG_STR, chain=INTERNAL_VALID_SAN_STR, private_key=PRIVATE_KEY_STR, owner='joe@example.com', creator=user['user'])
cert = upload(body=SAN_CERT_STR, chain=INTERMEDIATE_CERT_STR, private_key=SAN_CERT_KEY, owner='joe@example.com', creator=user['user'])
assert str(cert.not_after) == '2040-01-01T20:30:52+00:00'
assert str(cert.not_before) == '2015-06-26T20:30:52+00:00'
assert cert.issuer == 'Example'
assert cert.name == 'long.lived.com-Example-20150626-20400101-3'
cert = upload(body=INTERNAL_VALID_LONG_STR, chain=INTERNAL_VALID_SAN_STR, private_key=PRIVATE_KEY_STR, owner='joe@example.com', name='ACustomName', creator=user['user'])
cert = upload(body=SAN_CERT_STR, chain=INTERMEDIATE_CERT_STR, private_key=SAN_CERT_KEY, owner='joe@example.com', name='ACustomName', creator=user['user'])
assert 'ACustomName' in cert.name
# verify upload with a private key as a str
def test_upload_private_key_str(user):
from lemur.certificates.service import upload
cert = upload(body=INTERNAL_VALID_LONG_STR, chain=INTERNAL_VALID_SAN_STR, private_key=PRIVATE_KEY_STR, owner='joe@example.com', name='ACustomName', creator=user['user'])
cert = upload(body=SAN_CERT_STR, chain=INTERMEDIATE_CERT_STR, private_key=SAN_CERT_KEY, owner='joe@example.com', name='ACustomName', creator=user['user'])
assert cert
@ -533,8 +535,8 @@ def test_certificate_get(client, token, status):
def test_certificate_get_body(client):
response_body = client.get(api.url_for(Certificates, certificate_id=1), headers=VALID_USER_HEADER_TOKEN).json
assert response_body['serial'] == '1001'
assert response_body['serialHex'] == '3E9'
assert response_body['serial'] == '211983098819107449768450703123665283596'
assert response_body['serialHex'] == '9F7A75B39DAE4C3F9524C68B06DA6A0C'
@pytest.mark.parametrize("token,status", [

View File

@ -1,45 +1,41 @@
from .vectors import SAN_CERT, WILDCARD_CERT, INTERMEDIATE_CERT
def test_cert_get_cn(client):
from .vectors import INTERNAL_VALID_LONG_CERT
from lemur.common.defaults import common_name
assert common_name(INTERNAL_VALID_LONG_CERT) == 'long.lived.com'
assert common_name(SAN_CERT) == 'san.example.org'
def test_cert_sub_alt_domains(client):
from .vectors import INTERNAL_VALID_SAN_CERT, INTERNAL_VALID_LONG_CERT
from lemur.common.defaults import domains
assert domains(INTERNAL_VALID_LONG_CERT) == []
assert domains(INTERNAL_VALID_SAN_CERT) == ['example2.long.com', 'example3.long.com']
assert domains(INTERMEDIATE_CERT) == []
assert domains(SAN_CERT) == ['san.example.org', 'san2.example.org', 'daniel-san.example.org']
def test_cert_is_san(client):
from .vectors import INTERNAL_VALID_SAN_CERT, INTERNAL_VALID_LONG_CERT
from lemur.common.defaults import san
assert not san(INTERNAL_VALID_LONG_CERT)
assert san(INTERNAL_VALID_SAN_CERT)
assert san(SAN_CERT)
# Wildcard cert has just one SAN record that matches the common name
assert not san(WILDCARD_CERT)
def test_cert_is_wildcard(client):
from .vectors import INTERNAL_VALID_WILDCARD_CERT, INTERNAL_VALID_LONG_CERT
from lemur.common.defaults import is_wildcard
assert is_wildcard(INTERNAL_VALID_WILDCARD_CERT)
assert not is_wildcard(INTERNAL_VALID_LONG_CERT)
assert is_wildcard(WILDCARD_CERT)
assert not is_wildcard(INTERMEDIATE_CERT)
def test_cert_bitstrength(client):
from .vectors import INTERNAL_VALID_LONG_CERT
from lemur.common.defaults import bitstrength
assert bitstrength(INTERNAL_VALID_LONG_CERT) == 2048
assert bitstrength(INTERMEDIATE_CERT) == 2048
def test_cert_issuer(client):
from .vectors import INTERNAL_VALID_LONG_CERT
from lemur.common.defaults import issuer
assert issuer(INTERNAL_VALID_LONG_CERT) == 'Example'
assert issuer(INTERMEDIATE_CERT) == 'LemurTrustEnterprisesLtd'
def test_text_to_slug(client):

View File

@ -2,7 +2,8 @@ import json
import pytest
from .vectors import CSR_STR, INTERNAL_VALID_LONG_STR, VALID_ADMIN_API_TOKEN, VALID_ADMIN_HEADER_TOKEN, VALID_USER_HEADER_TOKEN
from .vectors import CSR_STR, INTERMEDIATE_CERT_STR, VALID_ADMIN_API_TOKEN, VALID_ADMIN_HEADER_TOKEN, \
VALID_USER_HEADER_TOKEN, WILDCARD_CERT_STR
from lemur.pending_certificates.views import * # noqa
@ -23,8 +24,8 @@ def test_create_pending_certificate(async_issuer_plugin, async_authority, user):
def test_create_pending(pending_certificate, user, session):
import copy
from lemur.pending_certificates.service import create_certificate, get
cert = {'body': INTERNAL_VALID_LONG_STR,
'chain': None,
cert = {'body': WILDCARD_CERT_STR,
'chain': INTERMEDIATE_CERT_STR,
'external_id': 54321}
# Weird copy because the session behavior. pending_certificate is a valid object but the

View File

@ -2,7 +2,8 @@ import pytest
from lemur.sources.views import * # noqa
from .vectors import VALID_ADMIN_API_TOKEN, VALID_ADMIN_HEADER_TOKEN, VALID_USER_HEADER_TOKEN, INTERNAL_PRIVATE_KEY_A_STR, INTERNAL_VALID_WILDCARD_STR
from .vectors import VALID_ADMIN_API_TOKEN, VALID_ADMIN_HEADER_TOKEN, VALID_USER_HEADER_TOKEN, WILDCARD_CERT_STR, \
WILDCARD_CERT_KEY
def validate_source_schema(client):
@ -25,8 +26,8 @@ def test_create_certificate(user, source):
certificate_create({}, source)
data = {
'body': INTERNAL_VALID_WILDCARD_STR,
'private_key': INTERNAL_PRIVATE_KEY_A_STR,
'body': WILDCARD_CERT_STR,
'private_key': WILDCARD_CERT_KEY,
'owner': 'bob@example.com',
'creator': user['user']
}

View File

@ -1,13 +1,13 @@
import pytest
from datetime import datetime
from .vectors import PRIVATE_KEY_STR
from .vectors import SAN_CERT_KEY
from marshmallow.exceptions import ValidationError
def test_private_key(session):
from lemur.common.validators import private_key
private_key(PRIVATE_KEY_STR)
private_key(SAN_CERT_KEY)
with pytest.raises(ValidationError):
private_key('invalid_private_key')

View File

@ -5,15 +5,16 @@ from cryptography.hazmat.primitives import serialization, hashes
from cryptography.x509 import UniformResourceIdentifier
from lemur.certificates.verify import verify_string, crl_verify
from lemur.tests.vectors import INTERNAL_VALID_LONG_STR
from lemur.utils import mktempfile
from .vectors import INTERMEDIATE_CERT_STR
def test_verify_simple_cert():
"""Simple certificate without CRL or OCSP."""
# Verification raises an exception for "unknown" if there are no means to verify it
with pytest.raises(Exception, match="Failed to verify"):
verify_string(INTERNAL_VALID_LONG_STR, '')
verify_string(INTERMEDIATE_CERT_STR, '')
def test_verify_crl_unknown_scheme(cert_builder, private_key):

View File

@ -18,35 +18,242 @@ VALID_ADMIN_API_TOKEN = {
}
INTERNAL_VALID_LONG_STR = """
#: CN=LemurTrust Unittests Root CA 2018
ROOTCA_CERT_STR = """\
-----BEGIN CERTIFICATE-----
MIID1zCCAr+gAwIBAgIBATANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UEBhMCVVMx
CzAJBgNVBAgMAkNBMRAwDgYDVQQHDAdBIHBsYWNlMRcwFQYDVQQDDA5sb25nLmxp
dmVkLmNvbTEQMA4GA1UECgwHRXhhbXBsZTETMBEGA1UECwwKT3BlcmF0aW9uczEe
MBwGCSqGSIb3DQEJARYPamltQGV4YW1wbGUuY29tMB4XDTE1MDYyNjIwMzA1MloX
DTQwMDEwMTIwMzA1MlowgYwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEQMA4G
A1UEBwwHQSBwbGFjZTEXMBUGA1UEAwwObG9uZy5saXZlZC5jb20xEDAOBgNVBAoM
B0V4YW1wbGUxEzARBgNVBAsMCk9wZXJhdGlvbnMxHjAcBgkqhkiG9w0BCQEWD2pp
bUBleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKeg
sqb0HI10i2eRSx3pLeA7JoGdUpud7hy3bGws/1HgOSpRMin9Y65DEpVq2Ia9oir7
XOJLpSTEIulnBkgDHNOsdKVYHDR6k0gUisnIKSl2C3IgKHpCouwiOvvVPwd3PExg
17+d7KLBIu8LpG28wkXKFU8vSz5i7H4i/XCEChnKJ4oGJuGAJJM4Zn022U156pco
97aEAc9ZXR/1dm2njr4XxCXmrnKCYTElfRhLkmxtv+mCi6eV//5d12z7mY3dTBkQ
EG2xpb5DQ+ITQ8BzsKcPX80rz8rTzgYFwaV3gUg38+bgka/JGJq8HgBuNnHv5CeT
1T/EoZTRYW2oPfOgQK8CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
Af8EBAMCAQYwHQYDVR0OBBYEFIuDY73dQIhj2nnd4DG2SvseHVVaMA0GCSqGSIb3
DQEBCwUAA4IBAQBk/WwfoWYdS0M8rz5tJda/cMdYFSugUbTn6JJdmHuw6RmiKzKG
8NzfSqBR6m8MWdSTuAZ/chsUZH9YEIjS9tAH9/FfUFBrsUE7TXaUgpNBm4DBLLfl
fj5xDmEyj17JPN/C36amQ9eU5BNesdCx9EkdWLyVJaM50HFRo71W0/FrpKZyKK68
XPhd1z9w/xgfCfYhe7PjEmrmNPN5Tgk5TyXW+UUhOepDctAv2DBetptcx+gHrtW+
Ygk1wptlt/tg7uUmstmXZA4vTPx83f4P3KSS3XHIYFIyGFWUDs23C20K6mmW1iXa
h0S8LN4iv/+vNFPNiM1z9X/SZgfbwZXrLsSi
MIIEFjCCAv6gAwIBAgIQbIbX/Ap0Roqzf5HeN5akmzANBgkqhkiG9w0BAQsFADCB
pDEqMCgGA1UEAwwhTGVtdXJUcnVzdCBVbml0dGVzdHMgUm9vdCBDQSAyMDE4MSMw
IQYDVQQKDBpMZW11clRydXN0IEVudGVycHJpc2VzIEx0ZDEmMCQGA1UECwwdVW5p
dHRlc3RpbmcgT3BlcmF0aW9ucyBDZW50ZXIxCzAJBgNVBAYTAkVFMQwwCgYDVQQI
DANOL0ExDjAMBgNVBAcMBUVhcnRoMB4XDTE3MTIzMTIyMDAwMFoXDTQ3MTIzMTIy
MDAwMFowgaQxKjAoBgNVBAMMIUxlbXVyVHJ1c3QgVW5pdHRlc3RzIFJvb3QgQ0Eg
MjAxODEjMCEGA1UECgwaTGVtdXJUcnVzdCBFbnRlcnByaXNlcyBMdGQxJjAkBgNV
BAsMHVVuaXR0ZXN0aW5nIE9wZXJhdGlvbnMgQ2VudGVyMQswCQYDVQQGEwJFRTEM
MAoGA1UECAwDTi9BMQ4wDAYDVQQHDAVFYXJ0aDCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAL8laXtLXyM64t5dz2B9q+4VvOsChefBi2PlGudqxDuRN3l0
Kmcfun6x2Gng24pTlGdtmiTEWA0a2F8HRLv4YBWhuYleVeBPtf1fF1/SuYgkJOWT
7S5qk/od/tUOLHS0Y067st3FydnFQTKpAuYveEkxleFrMS8hX8cuEgbER+8ybiXK
n4GsyM/om6lsTyBoaLp5yTAoQb4jAWDbiz1xcjPSkvH2lm7rLGtKoylCYwxRsMh2
nZcRr1OXVhYHXwpYHVB/jVAjy7PAWQ316hi6mpPYbBV+yfn2GUfGuytqyoXLEsrM
3iEEAkU0mJjQmYsCDM3r7ONHTM+UFEk47HCZJccCAwEAAaNCMEAwDwYDVR0TAQH/
BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFFL12SFeOTTDdGKsHKoz
eByGHY6nMA0GCSqGSIb3DQEBCwUAA4IBAQAJfe0/uAHobkxth38dqrSFmTo+D5/T
MlRt3hdgjlah6sD2+/DObCyut/XhQWCgTNWyRi4xTKgLh5KSoeJ9EMkADGEgDkU2
vjBg5FmGZsxg6bqjxehK+2HvASJoTH8r41xmTioav7a2i3wNhaNSntw2QRTQBQED
OIzHRpPDQ2quErjA8nSifE2xmAAr3g+FuookTTJuv37s2cS59zRYsg+WC3+TtPpR
ssvobJ6Xe2D4cCVjUmsqtFEztMgdqgmlcWyGdUKeXdi7CMoeTb4uO+9qRQq46wYW
n7K1z+W0Kp5yhnnPAoOioAP4vjASDx3z3RnLaZvMmcO7YdCIwhE5oGV0
-----END CERTIFICATE-----
"""
INTERNAL_VALID_LONG_CERT = parse_certificate(INTERNAL_VALID_LONG_STR)
ROOTCA_KEY = """\
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAvyVpe0tfIzri3l3PYH2r7hW86wKF58GLY+Ua52rEO5E3eXQq
Zx+6frHYaeDbilOUZ22aJMRYDRrYXwdEu/hgFaG5iV5V4E+1/V8XX9K5iCQk5ZPt
LmqT+h3+1Q4sdLRjTruy3cXJ2cVBMqkC5i94STGV4WsxLyFfxy4SBsRH7zJuJcqf
gazIz+ibqWxPIGhounnJMChBviMBYNuLPXFyM9KS8faWbussa0qjKUJjDFGwyHad
lxGvU5dWFgdfClgdUH+NUCPLs8BZDfXqGLqak9hsFX7J+fYZR8a7K2rKhcsSysze
IQQCRTSYmNCZiwIMzevs40dMz5QUSTjscJklxwIDAQABAoIBAAyVzwMiLEpqhyNy
88N7osVTQxQKH3zp3l6eaA4SlocBgbCKeHw/t4y98uzNtEbASAYjTkHbd5ytRs/C
78Cckt75vfiQcIELXoUnLKfPfQ28q30+JyCmPcX7EZs/iqfIdL1rWFSHwEmJVkia
nik/uODA1gh4gU2EGgVIQEGXzNCv2RgTgmuyY+/4LbgEnUdMF+/umDhQd+o+nnL3
Ie0eJ7mTNPq78Dw6/21OcpE3j+yBIHGf5ZOHf5Qy+kBAytR7n+wzorkVYhbTvb4s
aWzHzmNBViQcum2SOaa/5I/HiG/Z4R2vnD53+bbjeLAsT/4OgUMdWziKOQbGbWwp
z+j/tekCgYEA8cfyOrbvkTLQHpC/1PC0GyrPGW+/5HKv34N+lCK4U+j6q5x7T7ia
kIacvW3/gPsmW0zcdty1RfgEKQXOT7sK7YN1yMwfRwHX7Ea9TW9ZPW/gnOlhwVJ0
Fx2SNESLmubi2cjEMayI9I++pDzwPMTLWNj53kgBhB/Qhw6+N74ScL0CgYEAymMm
JKVu3eNzooVIjS0wwlEpsteQZa1PI26QOyN/sr8wgbVrb/6P/dNc7Bl3YUMe0ZyR
ejyFo1bLsFemsWCZKWdgVOCQG1DqtHOPQSqkZPfYKfoMY9LWemyPk61CQDWzL3tg
L742V0iVPtYmtysKqagFFNeVML91duLWiobDwtMCgYAkl+2Kg2uI31bueVv/X5ry
zazgnbA+ZDlIK/+5bfPWB1oBJULokvkZzLXmWcKlA94PTXfEqazp9Rq0FsPd/2It
BouKI5LMTXQft6kpEiRAjzFArnX0K4WUhg49yO4UOMO20JMZLZLg6OyisPJvUB2y
ycwvn1hTZflKp6mUiDkERQKBgBUDyJEjkGh/1qD4f/kQyTBUJyVH1tmH7mC6eUV6
wSa5TXsacGZ3o1Hy4YIufsPdqVSQklaD9EhqmcncwBVI935iGpGVo8ECXOyR1z0o
BVvqlEp/iUvQN68MmLf31JpAOTPj9q/ea1wS0FRu/iQk1v2Y0bZBUF94ceT/VtGZ
frg7AoGBAI3iNhiZMQrq6j8kaEgDea+T1Ui0rGYIeD60TAuHfJ0a50Ga4rPp0u2p
G92Mk0sk2VGzZCkV6YRd/DJBXsqDAGeaEKzEnXiDBObUORDIo9SL3YhzosH191Ce
45ZXINAgovSzBcZfwStWjebUDw4v10Arc6ipkHGBPbK556S6wXGK
-----END RSA PRIVATE KEY-----
"""
INTERNAL_INVALID_STR = """
#: CN=LemurTrust Unittests Class 1 CA 2018
INTERMEDIATE_CERT_STR = """\
-----BEGIN CERTIFICATE-----
MIIEGjCCAwKgAwIBAgIRAJ96dbOdrkw/lSTGiwbaagwwDQYJKoZIhvcNAQELBQAw
gaQxKjAoBgNVBAMMIUxlbXVyVHJ1c3QgVW5pdHRlc3RzIFJvb3QgQ0EgMjAxODEj
MCEGA1UECgwaTGVtdXJUcnVzdCBFbnRlcnByaXNlcyBMdGQxJjAkBgNVBAsMHVVu
aXR0ZXN0aW5nIE9wZXJhdGlvbnMgQ2VudGVyMQswCQYDVQQGEwJFRTEMMAoGA1UE
CAwDTi9BMQ4wDAYDVQQHDAVFYXJ0aDAeFw0xNzEyMzEyMjAwMDBaFw00NzEyMzEy
MjAwMDBaMIGnMS0wKwYDVQQDDCRMZW11clRydXN0IFVuaXR0ZXN0cyBDbGFzcyAx
IENBIDIwMTgxIzAhBgNVBAoMGkxlbXVyVHJ1c3QgRW50ZXJwcmlzZXMgTHRkMSYw
JAYDVQQLDB1Vbml0dGVzdGluZyBPcGVyYXRpb25zIENlbnRlcjELMAkGA1UEBhMC
RUUxDDAKBgNVBAgMA04vQTEOMAwGA1UEBwwFRWFydGgwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQDR+qNdfNsLhGvgw3IgCQNakL2B9dpQtkVnvAXhdRZq
JETm/tHLkGvONWTXAwGdoiKv6+0j3I5InUsW+wzUPewcfj+PLNu4mFMq8jH/gPhT
ElKiAztPRdm8QKchvrqiaU6uEbia8ClM6uPpIi8StxE1aJRYL03p0WeMJjJPrsl6
eSSdpR4qL69GTd1n5je9OuWAcn5utXXnt/jO4vNeFRjlGp/0n3JmTDd9w4vtAyY9
UrdGgo37eBmi6mXt5J9i//NenhaiOVU81RqxZM2Jt1kkg2WSjcqcIQfBEWp9StG4
6VmHLaL+9/v2XAV3tL1VilJGj6PoFMb4gY5MXthfGSiXAgMBAAGjQjBAMA8GA1Ud
EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQstpQr0iMBVfv0
lODIsMgT9+9oezANBgkqhkiG9w0BAQsFAAOCAQEASYQbv1Qwb5zES6Gb5LEhrAcH
81ZB2uIpKd3Ki6AS4fLJVymMGkUs0RZjt39Ep4qX1zf0hn82Yh9YwRalrkgu+tzK
rp0JgegNe6+gyFRrJC0SIGA4zc3M02m/n4tdaouU2lp6jhmWruL3g25ZkgbQ8LO2
zjpSMtblR2euvR2+bI7TepklyG71qx5y6/N8x5PT+hnTlleiZeE/ji9D96MZlpWB
4kBihekWmxuptED22z/tpQtac+hPBNgt8z1uFVEYN2rKEcCE7V6Qk7icS+M4Vb7M
3D8kLyWDubs9Yy3l0EWjOXQXxEhTaKEm4gSuY/j+Y35bBVkA2Fcyuq7msiTgrw==
-----END CERTIFICATE-----
"""
INTERMEDIATE_CERT = parse_certificate(INTERMEDIATE_CERT_STR)
INTERMEDIATE_KEY = """\
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA0fqjXXzbC4Rr4MNyIAkDWpC9gfXaULZFZ7wF4XUWaiRE5v7R
y5BrzjVk1wMBnaIir+vtI9yOSJ1LFvsM1D3sHH4/jyzbuJhTKvIx/4D4UxJSogM7
T0XZvECnIb66omlOrhG4mvApTOrj6SIvErcRNWiUWC9N6dFnjCYyT67JenkknaUe
Ki+vRk3dZ+Y3vTrlgHJ+brV157f4zuLzXhUY5Rqf9J9yZkw3fcOL7QMmPVK3RoKN
+3gZoupl7eSfYv/zXp4WojlVPNUasWTNibdZJINlko3KnCEHwRFqfUrRuOlZhy2i
/vf79lwFd7S9VYpSRo+j6BTG+IGOTF7YXxkolwIDAQABAoIBAQC8dTuSeLEQUTWR
cVlIr043RpkPv1zF/BGm3PZaOAB6GztMJ4CcN27KkNmEsMoOdKq1QgaAnT+GpMX0
RjZpd3omyJi7JAPAVdavQNjm/RXjWRqZFlVw/LxDXbOjcc+IXQOk73rEdLBcvKT5
ZRjirzPev5IE49AF/0/0VYPqSHHEXL1HMWy5Q7KZU/C4Yp8em2l3UAh1/nLI2L+U
iw6DxBhBbdsc2vD4dd4UUQmznBfvdBOiejKs9DYIDzmTrGI2lH0VUU6PVzb9LKJ3
UtlIsjOO0FdJxXhkjsDCcF4eEMhO4qOfVJDcl0YYsPLjM0t4IVfe2C0b3Hd37hhF
b3ux0YoBAoGBAPWCPBepUdtiiMM21dLFPuy/d9/C3k8xTD23aO8zupwnGD1zz8OY
1GzsCtR9me0nIbHGxT+Unovuxh2JYQgrFpAFsG/izL8SpkDeT3hJDPY8PLrhGqMS
RBcYYgZ+1aNZTPZRKDjTG7PlwkcDt8VzQYYl87MBtDpPmdYkWYPnS+5XAoGBANrz
uSjbbTEX4a3WGsot9WzyhML11WgsdMgbqSWLMEmj2guwm4jn3XdqA+6nZAUJHgPI
Ir5l2E3zWTdw5pZ0+IkQnj/OJP2OLqS+msVMl89PHJjtPyB2LVjCg+Z/vfm2ar5S
RnQ/AoR5cSXctiL9wJbJBidfZeEpXBSeKN/SW6/BAoGAXaQ4EXpWq4wQyAzRT9xG
HP0G1wU30BLolp2vW5Vqdwb+Wuoic+OGGqmJk/T4Uhlb47gCIjcopg0D6d4tcXUl
3Pcejf5+w950JUfmHeYXGJBvRYR4qXxdFkYJlZqpF+4Gyei4o7v51Astp/KGFLza
YDV3l25t9NPJxIEG16XQM28CgYEAyT3yFYd42QKmPuznOqT7SuOs+rSRLWqO+83Q
rd08yLJ9Gvl8O11BxRv/+T6JQ8eZeshchrt9EEh22+o9RlTEitZnXSXQAezJGkrG
XkmDzttb4YNN3jxAebBvI1COABKWEc/1SasQWUp1oOM31Pl+JhkmOtIIBefJ5nlo
ADCMbQECgYBdpg/2J58JOB0NhFFUDh3+6+bzZIciT7BYZ8zYBej5DR6kd4Inkvvl
JxOlYIKSew5uyi7i2po7fBFRhKuyfpNMBYK01ObrgJNZELbqVgYvKw1HEqqtgExa
eMVHHbWm1CpGO294R+vMBv4jcuhIBOx63KZE4VaoJuaazF6TE5czDw==
-----END RSA PRIVATE KEY-----
"""
#: CN=san.example.org, issued by LemurTrust Unittests Class 1 CA 2018
SAN_CERT_STR = """\
-----BEGIN CERTIFICATE-----
MIIESjCCAzKgAwIBAgIRAK/y20+NLU2OgPo4KuJ8IzMwDQYJKoZIhvcNAQELBQAw
gacxLTArBgNVBAMMJExlbXVyVHJ1c3QgVW5pdHRlc3RzIENsYXNzIDEgQ0EgMjAx
ODEjMCEGA1UECgwaTGVtdXJUcnVzdCBFbnRlcnByaXNlcyBMdGQxJjAkBgNVBAsM
HVVuaXR0ZXN0aW5nIE9wZXJhdGlvbnMgQ2VudGVyMQswCQYDVQQGEwJFRTEMMAoG
A1UECAwDTi9BMQ4wDAYDVQQHDAVFYXJ0aDAeFw0xNzEyMzEyMjAwMDBaFw00NzEy
MzEyMjAwMDBaMHgxGDAWBgNVBAMMD3Nhbi5leGFtcGxlLm9yZzEYMBYGA1UECgwP
RGFuaWVsIFNhbiAmIGNvMRcwFQYDVQQLDA5LYXJhdGUgTGVzc29uczELMAkGA1UE
BhMCRUUxDDAKBgNVBAgMA04vQTEOMAwGA1UEBwwFRWFydGgwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQDImvQXKcqWVFPcSaJJ83RKfgHr0BPd10gMpSJV
44vNGZWEv0/5lVrbuoTcM9iCQwRYepz2h09VHfwCOGGpwzGvnxeCicc5ZCj22Krl
seBDo02drBQQQor8MZaNUqPK+R3+DWfRMLuACJmt85pPnc8SU6Z1m0yBSRrAxi8C
TvYrurqn+/VXWJBhCwrrKt3chdo9gzQ4hh6EXEGBTDIQykermJgk2L8I39PrH+pN
c5NhCtV/mVlMoz/jZdjQem6S9E8nRe+X7qZVkTnM3HojugSjuGE9rjT3ReAQB6f5
EApKp48ORQl+zzjUU+ME1vwIw5LeVjoGPgAfdM0AT8b11m1DAgMBAAGjgZ4wgZsw
DAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDATAOBgNVHQ8BAf8EBAMC
BaAwHQYDVR0OBBYEFPMfkyOR6taOKARGUn1zyauOeOhAMEcGA1UdEQEB/wQ9MDuC
D3Nhbi5leGFtcGxlLm9yZ4IQc2FuMi5leGFtcGxlLm9yZ4IWZGFuaWVsLXNhbi5l
eGFtcGxlLm9yZzANBgkqhkiG9w0BAQsFAAOCAQEAJer6tDWlcc4gDvZEbPNpFPKY
kPqww6WtVKrsyPQyucmP7arFx+kUulkZN6GY6FyIao7zQPrHU3GqtPXt/lR++wzz
bnj+iHONNoAY5TZLycPXAW7pn8UCvdQzkyhMzCB1aRkRS/Tr0/sC0T5lYux42dQG
rTUxVG7Umr4jq8hKEElNIwxF+3kkfzztICZXJtzmVRAz4XpmXmyMcZOOXh3F7z04
kePn3ztNEJNuGK0qMnTJlL7T2a9v+Q29YhIiNqCFdoALJbzJmEj3+QgcLFJh3KjY
J4WEmpGK7FylxmZLrya12SxPMA8A60hMPeWH90xRS8SJfd57K5oCluGK14X+og==
-----END CERTIFICATE-----
"""
SAN_CERT = parse_certificate(SAN_CERT_STR)
SAN_CERT_KEY = """\
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAyJr0FynKllRT3EmiSfN0Sn4B69AT3ddIDKUiVeOLzRmVhL9P
+ZVa27qE3DPYgkMEWHqc9odPVR38AjhhqcMxr58XgonHOWQo9tiq5bHgQ6NNnawU
EEKK/DGWjVKjyvkd/g1n0TC7gAiZrfOaT53PElOmdZtMgUkawMYvAk72K7q6p/v1
V1iQYQsK6yrd3IXaPYM0OIYehFxBgUwyEMpHq5iYJNi/CN/T6x/qTXOTYQrVf5lZ
TKM/42XY0HpukvRPJ0Xvl+6mVZE5zNx6I7oEo7hhPa4090XgEAen+RAKSqePDkUJ
fs841FPjBNb8CMOS3lY6Bj4AH3TNAE/G9dZtQwIDAQABAoIBAQCxN3J7JAg8VbLf
4IzmF5ScWkUINYHXcN/Ni/SRO7u9LOTRqNDWBAOIKXZFseeK6/li0K7pew+yehKv
Q2/DsRSruTfjsiO1p64oo7AVytX76sAekm4HD0IJGSWPI3pfTUQZs24Ld6msqexZ
p+Kigx7zacKcEt27OQHRW0McHvWKGpCzc+G9o8hlYumtnTnR8kP4bYG4MpCVtZdt
ZuQr9QHEH7omQzWedLHICqGLP8WBu+lMY3bPM/gLgBSy2f8CP5MBy7xUUSTgolCc
ZZIt2H2cCStfb3y61WvDHX/bZ7B/a0lDWKHUK2f9Du5ENOWAAsaIUCPGrFwMFM1n
ANPtYIUBAoGBAP7SXzTcsHx0Iy1TMqluQxZNL7Up6dHksZFEO8zAwmg6Z3VHsXjc
3ovst1gQRWUzEhc2Soun8KbZ4ZVhApHpkxg+lLio2A4mLm7xf6ASsPwkwUCwUBYP
zSt56oopQ6BIc84ZDNe5QZY9OziRyHRc0SgVhuoK1i2t832kUii/aWmTAoGBAMmI
aA6vDlojHnyhvNCS/v+aOEjNyW7LJjDhNK6qTKZF7FeCSjTLxzJJ6XddQjLXnjVa
aF1I0dYPLQfjbeDaM6pKyg4l0pnN70qh9YgFCCIxU0dIqL2v0a057JILwlC4ZU8z
rmQEP3DROGGi50r74/SoYMBVm6r/6opYkThF+HuRAoGBAIHxrXM7hxQv9TBL2O3l
uHhK7CUqNn4+bP5zGTuUoI6eGdwIr0u+9g3MrMJPqdOtc3A601DcVy/+s7aFPdZC
kiwu3ZA9KdAtUEhrBnYOkgpCg/oE7xIRBMNC7IN//2hhCgzzYUUwx21h1C1Iyjvs
iQwzzhTTadzpc92CShNVaN/ZAoGBAKwG+fv+xdt/OtjcHpZTw8NfW0gaESW31yPG
OPgXelI8QZ/5IWqrv59XpCg1vPo1P2D/iTKHpEZ6sc+X/QUAfTWRnaQx+PE87lPg
p/uxf93gCNxCU3eHiw248g1AaGAK5r+St/u7/INKtDvzmEdTeKQwzlWfPb/br9Lk
AyHr6E1hAoGAN375PaykO+webBV9GkUwCcs1wTmDFjWKuaCVk9qvj8qavr1HOarb
ZolDBFYQSUUcOJHE9QRg7zDWTjI+Av670rXtTsREs0yMkdHhF/aRD7FJoBvO/7v/
tqdgqMHlJ0YPL/8/6sTMasepIqmAkQgFINzDskHubBBEPfHKqF0KQA4=
-----END RSA PRIVATE KEY-----
"""
WILDCARD_CERT_STR = """\
-----BEGIN CERTIFICATE-----
MIIEJDCCAwygAwIBAgIPK/QvcZhAY7VPU7Ek/nCDMA0GCSqGSIb3DQEBCwUAMIGn
MS0wKwYDVQQDDCRMZW11clRydXN0IFVuaXR0ZXN0cyBDbGFzcyAxIENBIDIwMTgx
IzAhBgNVBAoMGkxlbXVyVHJ1c3QgRW50ZXJwcmlzZXMgTHRkMSYwJAYDVQQLDB1V
bml0dGVzdGluZyBPcGVyYXRpb25zIENlbnRlcjELMAkGA1UEBhMCRUUxDDAKBgNV
BAgMA04vQTEOMAwGA1UEBwwFRWFydGgwHhcNMTcxMjMxMjIwMDAwWhcNNDcxMjMx
MjIwMDAwWjB9MRswGQYDVQQDDBIqLndpbGQuZXhhbXBsZS5vcmcxETAPBgNVBAoM
CFBsYXl0ZWNoMRkwFwYDVQQLDBBJbmZyYSBPcGVyYXRpb25zMQswCQYDVQQGEwJF
RTERMA8GA1UECAwISGFyanVtYWExEDAOBgNVBAcMB1RhbGxpbm4wggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCoT8Ak5kynUzosBvP8hCnP4hGMAtgHLcHG
UBWug4BofAhxxBrZW3UteoQzNznK5jz0hy2azqnz3/9q5N/FKwHxfMY/VEHPXyYK
QsZuSdVceJ/EHL+MLx+uisIRJstV8fC5oYRfg74m07ZED7NM4EerJTxKZAy7UuSM
L65i/LEChPzjLN46GcUEuC2O03nZtFTPvN9j7vzen9/qIzs1TGQukOn4z5l2GuAx
RCEfBl3IrnvSY+npGARPJsXSymXCCP3ntzq6I6iRHuZf+QETZtiMR1TCNZRTqcc2
LxWn+W5N18yyXvUcVMfrg4jzEWKHuhwInoiH1pu/myyKrnoIi4nTAgMBAAGjdjB0
MBMGA1UdJQQMMAoGCCsGAQUFBwMBMA4GA1UdDwEB/wQEAwIFoDAMBgNVHRMBAf8E
AjAAMB0GA1UdDgQWBBRR9Q9DHJRPt69Qm8lir4iJfOmJ4TAgBgNVHREBAf8EFjAU
ghIqLndpbGQuZXhhbXBsZS5vcmcwDQYJKoZIhvcNAQELBQADggEBAMm2DiYfGLve
r/gCtYgXKkRmbuv57PmAUm52w5l4hjxssdUwq4Wn4T+K0+Sqp3IzcNhEaIqPB+bG
8rIbJLBiiDPbSUZC0DbvlXihk7FHjqmrbVFwNmkWNywLhB1qOlp0kQH+w9lDWA1p
y99P0Bxcot66scbiaag0i0AUpkRKbUG+v+VGXdPrJrWE+63ROhWQMmQNiUlZ6QGO
45tUSn//MuUpJiJVkUVR1fSbCpHQj2mHiuhShOmatmh5e1ISwVP19cX64Gr6djlY
wKJqcmw7WDjl+T+y7luJWw4UqI7s7hY6Y9RQVh61L4eV8CIma3NmTaQCSgR3tCxh
d4FCKAE8+Lw=
-----END CERTIFICATE-----
"""
WILDCARD_CERT = parse_certificate(WILDCARD_CERT_STR)
WILDCARD_CERT_KEY = """\
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAqE/AJOZMp1M6LAbz/IQpz+IRjALYBy3BxlAVroOAaHwIccQa
2Vt1LXqEMzc5yuY89Ictms6p89//auTfxSsB8XzGP1RBz18mCkLGbknVXHifxBy/
jC8frorCESbLVfHwuaGEX4O+JtO2RA+zTOBHqyU8SmQMu1LkjC+uYvyxAoT84yze
OhnFBLgtjtN52bRUz7zfY+783p/f6iM7NUxkLpDp+M+ZdhrgMUQhHwZdyK570mPp
6RgETybF0splwgj957c6uiOokR7mX/kBE2bYjEdUwjWUU6nHNi8Vp/luTdfMsl71
HFTH64OI8xFih7ocCJ6Ih9abv5ssiq56CIuJ0wIDAQABAoIBAHpE3SexKbRQMK01
K9+gPyOmberRUg/8/IzNNsL9ArZkjFnhBUQrPXeZThpKnzA3i8ZzwPx571qbudf0
hl6cfJ/qbbYpxlkYHPFNSwtplZbEhgOYgsoanaBVat+81/AKfz7LB/e/I87e88SD
x1QshcPdm+vKvLkEYcU5Ci0ctpZFyjgqWAVdsaEmstSpygOsU/CExiiq20MuGXQV
lfRpYqmA0D1LicN6t0rGRNLUHWzhZS5s1ZHD8oR5bgtlcxvOSDm81ROfV1obAQRo
RyCeYG9Juo2BisyuG5RsKuzfWvP6goxXdGD2uTOj7rdMYRfnUzsz4QXkzdA+IEE9
qmv9gsECgYEA0gYoSVwF+koYL8SURMLbQPdmVBiTSxZQytSaFTl9WWYUvyFJ/R0c
xmuMjfVvnxuMUa6qHcaOt9Gjq0pAp2T10/8B+fB8XAJ0bxl6DKArxIONx7W1T8RX
SdEAWF77eRlSPAD4dfAyFIjPzCH4l98nX84sRk+GiusLGhm5MdwTS2ECgYEAzSgB
H33YIfPMW7Mh9R7QpfQRyda9Ikb8pGDegprTLp9SDLU0zCZ3aPmSN3iVrGThwcf1
olnx5g8ZK9qiLLIUctxJWeK/EO2HAii/fmasJfq4zI0xBflkX25V+BbZRqU8GDa0
dLpOcr1cIEFAqpZ182O1uXAJdGzkVv4LN5Iq9bMCgYBuYAIIG66gjRQM9pidUnJ7
wAktJQUzrvSiw/x+LwprUzSQBeSmewhGVvs1F8mjqoyh2NNadqFGhYwoVwuHbY2r
7haRzgrtJ/Uc9hyoSfz2d9SpIhu5YgwlpQszZiduyxnmovPwt1z6YbQjKa9F0WcV
+HpYMS8aDtB01RP42hnhwQKBgHDg8PU9zZyowqk1v5pZ8R1OVDdE4t2oRzu+XM9p
loaRfJinXzxwccUdhFjnDRtEin6PodRJPvKBHi1l51NGTEACeo1tWAldV6pVdz96
CIABGorZqL6LwLFNSRnuoG/hXFZKSzHqjF1PWRAaNxVlIdLf6s30Gg+oFl7S+qMB
1odHAoGAQqPWDTSBVhbMIzXXoGGjIx08WG9xuNqRyQ6fjekSporXisoej1XB+pYA
wZF7+p71qUsrVrg+j7SRm8pFsR79nvshQImzaLGOCLUsdHZfcKjfy8D7wB6T7AmF
gt+hqNmTFkpLkvaze7sBEwRWRU0/RWpZLDmx3+zvRXPw1lQmB1Q=
-----END RSA PRIVATE KEY-----
"""
INVALID_CERT_STR = """
-----BEGIN CERTIFICATE-----
MIIEFTCCAv2gAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwgYwxCzAJBgNVBAYTAlVT
MQswCQYDVQQIDAJDQTEQMA4GA1UEBwwHQSBwbGFjZTEXMBUGA1UEAwwObG9uZy5s
@ -72,66 +279,7 @@ T7W3s8mm5bVHhQM7J9tV6dz/sVDmpOSuzL8oZkqeKP+lWU6ytaohFFpbdzaxWipU
kP+oGWtHvhteUAe8Gloo5NchZJ0/BqlYRCD5aAHcmbXRsDid9mO4ADU=
-----END CERTIFICATE-----
"""
INTERNAL_INVALID_CERT = parse_certificate(INTERNAL_INVALID_STR)
INTERNAL_VALID_SAN_STR = """
-----BEGIN CERTIFICATE-----
MIIESjCCAzKgAwIBAgICA+kwDQYJKoZIhvcNAQELBQAwgYwxCzAJBgNVBAYTAlVT
MQswCQYDVQQIDAJDQTEQMA4GA1UEBwwHQSBwbGFjZTEXMBUGA1UEAwwObG9uZy5s
aXZlZC5jb20xEDAOBgNVBAoMB0V4YW1wbGUxEzARBgNVBAsMCk9wZXJhdGlvbnMx
HjAcBgkqhkiG9w0BCQEWD2ppbUBleGFtcGxlLmNvbTAeFw0xNTA2MjYyMDU5MDZa
Fw0yMDAxMDEyMDU5MDZaMG0xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4G
A1UEBxMHQSBwbGFjZTEQMA4GA1UEChMHRXhhbXBsZTETMBEGA1UECxMKT3BlcmF0
aW9uczEYMBYGA1UEAxMPc2FuLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA2Nq5zFh2WiqtNIPssdSwQ9/00j370VcKPlOATLqK24Q+
dr2hWP1WlZJ0NOoPefhoIysccs2tRivosTpViRAzNJXigBHhxe8ger0QhVW6AXIp
ov327N689TgY4GzRrwqavjz8cqussIcnEUr4NLLsU5AvXE7e3WxYkkskzO497UOI
uCBtWdCXZ4cAGhtVkkA5uQHfPsLmgRVoUmdMDt5ZmA8HhLX4X6vkT3oGIhdGCw6T
W+Cu7PfYlSaggSBbBniU0YKTFLfGLkYFZN/b6bxzvt6CTJLoVFAYXyLJwUvd3EAm
u23HgUflIyZNG3xVPml/lah0OIX7RtSigXUSLm7lYwIDAQABo4HTMIHQMAwGA1Ud
EwEB/wQCMAAwDgYDVR0PAQH/BAQDAgWgMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMB
MC8GA1UdEQQoMCaCEWV4YW1wbGUyLmxvbmcuY29tghFleGFtcGxlMy5sb25nLmNv
bTAdBgNVHQ4EFgQUiiIyclcBIfJ5PE3OCcTXwzJAM+0wSAYDVR0fBEEwPzA9oDug
OYY3aHR0cDovL3Rlc3QuY2xvdWRjYS5jcmwubmV0ZmxpeC5jb20vbG9uZ2xpdmVk
Q0EvY3JsLnBlbTANBgkqhkiG9w0BAQsFAAOCAQEAgcTioq70B/aPWovNTy+84wLw
VX1q6bCdH3FJwAv2rc28CHp5mCGdR6JqfT/H/CbfRwT1Yh/5i7T5kEVyz+Dp3+p+
AJ2xauHrTvWn0QHQYbUWICwkuZ7VTI9nd0Fry1FQI1EeKiCmyrzNljiN2l+GZw6i
NJUpVNtwRyWRzB+yIx2E9wyydqDFH+sROuQok7EgzlQileitPrF4RrkfIhQp2/ki
YBrY/duF15YpoMKAlFhDBh6R9/nb5kI2n3pY6I5h6LEYfLStazXbIu61M8zu9TM/
+t5Oz6rmcjohL22+sEmmRz86dQZlrBBUxX0kCQj6OAFB4awtRd4fKtkCkZhvhQ==
-----END CERTIFICATE-----
"""
INTERNAL_VALID_SAN_CERT = parse_certificate(INTERNAL_VALID_SAN_STR)
INTERNAL_VALID_WILDCARD_STR = """
-----BEGIN CERTIFICATE-----
MIIEHDCCAwSgAwIBAgICA+owDQYJKoZIhvcNAQELBQAwgYwxCzAJBgNVBAYTAlVT
MQswCQYDVQQIDAJDQTEQMA4GA1UEBwwHQSBwbGFjZTEXMBUGA1UEAwwObG9uZy5s
aXZlZC5jb20xEDAOBgNVBAoMB0V4YW1wbGUxEzARBgNVBAsMCk9wZXJhdGlvbnMx
HjAcBgkqhkiG9w0BCQEWD2ppbUBleGFtcGxlLmNvbTAeFw0xNTA2MjYyMTEzMTBa
Fw0yMDAxMDEyMTEzMTBaMHAxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4G
A1UEBxMHQSBwbGFjZTEQMA4GA1UEChMHRXhhbXBsZTETMBEGA1UECxMKT3BlcmF0
aW9uczEbMBkGA1UEAxQSKi50ZXN0LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEA0T7OEY9FxMIdhe1CwLc+TbDeSfDN6KRHlp0I9MwK
3Pre7A1+1vmRzLiS5qAdOh3Oexelmgdkn/fZUFI+IqEVJwmeUiq13Kib3BFnVtbB
N1RdT7rZF24Bqwygf1DHAekEBYdvu4dGD/gYKsLYsSMD7g6glUuhTbgR871updcV
USYJ801y640CcHjai8UCLxpqtkP/Alob+/KDczUHbhdxYgmH34aQgxC8zg+uzuq6
bIqUAc6SctI+6ArXOqri7wSMgZUnogpF4R5QbCnlDfSzNcNxJFtGp8cy7CNWebMd
IWgBYwee8i8S6Q90B2QUFD9EGG2pEZldpudTxWUpq0tWmwIDAQABo4GiMIGfMAwG
A1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgWgMBYGA1UdJQEB/wQMMAoGCCsGAQUF
BwMBMB0GA1UdDgQWBBTH2KIECrqPHMbsVysGv7ggkYYZGDBIBgNVHR8EQTA/MD2g
O6A5hjdodHRwOi8vdGVzdC5jbG91ZGNhLmNybC5uZXRmbGl4LmNvbS9sb25nbGl2
ZWRDQS9jcmwucGVtMA0GCSqGSIb3DQEBCwUAA4IBAQBjjfur2B6BcdIQIouwhXGk
IFE5gUYMK5S8Crf/lpMxwHdWK8QM1BpJu9gIo6VoM8uFVa8qlY8LN0SyNyWw+qU5
Jc8X/qCeeJwXEyXY3dIYRT/1aj7FCc7EFn1j6pcHPD6/0M2z0Zmj+1rWNBJdcYor
pCy27OgRoJKZ6YhEYekzwIPeFPL6irIN9xKPnfH0b2cnYa/g56DyGmyKH2Kkhz0A
UGniiUh4bAUuppbtSIvUTsRsJuPYOqHC3h8791JZ/3Sr5uB7QbCdz9K14c9zi6Z1
S0Xb3ZauZJQI7OdHeUPDRVq+8hcG77sopN9pEYrIH08oxvLX2US3GqrowjOxthRa
-----END CERTIFICATE-----
"""
INTERNAL_VALID_WILDCARD_CERT = parse_certificate(INTERNAL_VALID_WILDCARD_STR)
INVALID_CERT = parse_certificate(INVALID_CERT_STR)
EXTERNAL_VALID_STR = """
@ -169,36 +317,6 @@ Bs63gULVCqWygt5KEbv990m/XGuRMaXuHzHCHB4v5LRM30FiFmqCzyD8d+btzW9B
EXTERNAL_CERT = parse_certificate(EXTERNAL_VALID_STR)
PRIVATE_KEY_STR = """
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAnEjM0cQevlDjT6mDMtTo8N1ovAyKbfVEp0ketCPC4hLkStms
q9ETIyyerARIMv4SEhKqS4E7HIg6ccGkwv1ja5E/b2jHMH4ht1dEXnfM2yh0Mwvk
8nC0YPcGwt7+td5GiGQkAqBOwKLq7vVm1T5rkaGrH87a4JLFph/Yp30Gy+Ew3JnM
aKhmjJ+Go0E1QA+twip7rfglC2SDAURAVZUky4jju6mXU63fr47S1r3V1T3Fi0ga
3Vabt2J4aqk7XvgzM0B8GOwNrN37uAoOB+J6c3EftB9R/wec+uJMamavRVhiHGXM
+9MV3hzfVFCjw0k4LI7SMyk2iDnvXjC94xklOwIDAQABAoIBAGeykly5MeD70OgB
xPEMfoebkav88jklnekVxk6mz9+rw1i6+CyFLJqRN7NRoApdtOXTBrXUyMEUzxq9
7zIGaVptZNbqggh2GK8LM20vNnlQbVGVmdMX30fbgNv6lK1eEBTdxVsMvVRqhVIK
+LGTmlJmICKZ4XdTS9v/k4UGm2TZPCt2pvrNzIpT7TIm2QybCbZoOPY8SHx0U8c5
lmtdqmIsy2JPNSOsOCiJgzQIvkR/fMGWFgNE4fEHsHAfubgpK97TGzwLiFRmlTb+
QUDaz0YbwhF+5bQjHtaGUGATcg5bvV1UWBUvp+g4gRIfwzG+3PAGacYE/djouAdG
PHbxuCkCgYEAz/LsgMgsaV3arlounviSwc8wG9WcI5gbYw5qwX0P57ZoxS7EBAGu
yYtudurJrU9SfsSV44GL11UzBcAGOeS0btddrcMiNBhc7fY7P/1xaufQ3GjG06/v
kH4gOjzsGSTJliZ709g4J6hnMCxz0O0PS31Qg5cBD8UG8xO7/AV0is0CgYEAwGWy
A6YPinpZuenaxrivM5AcVDWmj7aeC29M63l/GY+O5LQH2PKVESH0vL5PvG3LkrCR
SUbaMKdKR0wnZsJ89z21eZ54ydUgj41bZJczl8drxcY0GSajj6XZXGTUjtoVrWsB
A0kJbjsrpd+8J316Y9iCgpopmbVd965pUHe4ACcCgYAamJlDB1cWytgzQHmB/4zV
mOgwRyvHKacnDir9QD+OhTf1MDwFvylZwamJMBJHRkPozr/U7zaxfcYe0CZ7tRKW
spjapoBzZUJNdRay4nllEO0Xo5b6cCAVvOvmRvBzbs8Rky53M8pK2DEKakUNzaQN
JaPskJ2kJLD02etLGm+DaQKBgQCTI/NNmQ2foUzHw1J+0jWjoJ4ZxOI6XLZoFlnk
aInMuZ7Vx92MjJF2hdqPEpkWiX28FO839EjgFsDW4CXuD+XUjEwi1BCagzWgs8Hm
n0Bk3q3MlnW3mnZSYMtoPvDUw3L6qrAenBfrRrNt6zsRlIQqoiXFzjLsi+luh+Oh
F74P1wKBgQCPQGKLUcfAvjIcZp4ECH0K8sBEmoEf8pceuALZ3H5vneYDzqMDIceo
t5Gpocpt77LJnNiszXSerj/KjX2MflY5xUXeekWowLVTBOK5+CZ8+XBIgBt1hIG3
XKxcRgm/Va4QMEAnec0qXfdTVJaJiAW0bdKwKRRrrbwcTdNRGibdng==
-----END RSA PRIVATE KEY-----
"""
INTERNAL_CERTIFICATE_A_STR = """
-----BEGIN CERTIFICATE-----
MIIDazCCAlOgAwIBAgIBATANBgkqhkiG9w0BAQsFADB5MQswCQYDVQQGEwJVUzET