diff options
author | Ivan Kanakarakis <ivan.kanak@gmail.com> | 2022-04-18 23:54:10 +0300 |
---|---|---|
committer | Ivan Kanakarakis <ivan.kanak@gmail.com> | 2022-04-18 23:54:10 +0300 |
commit | a92443578acc20f3c095bdd5739d2de296746bc5 (patch) | |
tree | 49bff2ff83966cddc5e11ca6a899cc82745aa4f6 | |
parent | f36b06aa2a8aeb41394139d0fa2cf20b59f41dd9 (diff) | |
parent | e68304f64988bfeccdc525302083f718ff302c72 (diff) | |
download | pysaml2-a92443578acc20f3c095bdd5739d2de296746bc5.tar.gz |
Merge branch 'feat-cert-load'
-rw-r--r-- | setup.cfg | 2 | ||||
-rw-r--r-- | src/saml2/cert.py | 33 | ||||
-rw-r--r-- | src/saml2/cryptography/asymmetric.py | 6 | ||||
-rw-r--r-- | src/saml2/cryptography/pki.py | 43 | ||||
-rw-r--r-- | src/saml2/cryptography/symmetric.py | 6 | ||||
-rw-r--r-- | src/saml2/metadata.py | 13 | ||||
-rw-r--r-- | src/saml2/sigver.py | 66 | ||||
-rw-r--r-- | tests/extra_lines.crt | 19 | ||||
-rw-r--r-- | tests/malformed.crt | 12 | ||||
-rw-r--r-- | tests/test_1.der | bin | 0 -> 549 bytes | |||
-rw-r--r-- | tests/test_39_metadata.py | 21 | ||||
-rw-r--r-- | tests/test_40_sigver.py | 21 | ||||
-rw-r--r-- | tests/test_82_pefim.py | 2 | ||||
-rw-r--r-- | tests/test_94_read_cert.py | 68 | ||||
-rw-r--r-- | tests/test_chain.pem | 39 | ||||
-rw-r--r-- | tests/test_chain_with_linebreaks.pem | 51 |
16 files changed, 311 insertions, 91 deletions
@@ -48,7 +48,7 @@ scripts = tools/parse_xsd2.py python_requires = >=3.6, <4 install_requires = - cryptography >= 1.4 + cryptography >= 3.1 defusedxml pyOpenSSL python-dateutil diff --git a/src/saml2/cert.py b/src/saml2/cert.py index 68bd55e3..aeb5b662 100644 --- a/src/saml2/cert.py +++ b/src/saml2/cert.py @@ -5,9 +5,10 @@ import datetime import dateutil.parser import pytz import six -from OpenSSL import crypto -from os.path import join from os import remove +from os.path import join + +from OpenSSL import crypto import saml2.cryptography.pki @@ -323,8 +324,7 @@ class OpenSSLWrapper(object): cert_algorithm = cert_algorithm.decode('ascii') cert_str = cert_str.encode('ascii') - cert_crypto = saml2.cryptography.pki.load_pem_x509_certificate( - cert_str) + cert_crypto = saml2.cryptography.pki.load_pem_x509_certificate(cert_str) try: crypto.verify(ca_cert, cert_crypto.signature, @@ -335,3 +335,28 @@ class OpenSSLWrapper(object): return False, "Certificate is incorrectly signed." except Exception as e: return False, "Certificate is not valid for an unknown reason. %s" % str(e) + + +def read_cert_from_file(cert_file, cert_type="pem"): + """Read a certificate from a file. + + If there are multiple certificates in the file, the first is returned. + + :param cert_file: The name of the file + :param cert_type: The certificate type + :return: A base64 encoded certificate as a string or the empty string + """ + if not cert_file: + return "" + + with open(cert_file, "rb") as fp: + data = fp.read() + + try: + cert = saml2.cryptography.pki.load_x509_certificate(data, cert_type) + pem_data = saml2.cryptography.pki.get_public_bytes_from_cert(cert) + except Exception as e: + raise CertificateError(e) + + pem_data_no_headers = "".join(pem_data.splitlines()[1:-1]) + return pem_data_no_headers diff --git a/src/saml2/cryptography/asymmetric.py b/src/saml2/cryptography/asymmetric.py index 8cff93af..1c8ee519 100644 --- a/src/saml2/cryptography/asymmetric.py +++ b/src/saml2/cryptography/asymmetric.py @@ -1,15 +1,13 @@ """This module provides methods for asymmetric cryptography.""" -import cryptography.hazmat.backends as _backends import cryptography.hazmat.primitives.asymmetric as _asymmetric import cryptography.hazmat.primitives.hashes as _hashes import cryptography.hazmat.primitives.serialization as _serialization -def load_pem_private_key(data, password): +def load_pem_private_key(data, password=None): """Load RSA PEM certificate.""" - key = _serialization.load_pem_private_key( - data, password, _backends.default_backend()) + key = _serialization.load_pem_private_key(data, password) return key diff --git a/src/saml2/cryptography/pki.py b/src/saml2/cryptography/pki.py index 8c59fdaf..0aa6d2b8 100644 --- a/src/saml2/cryptography/pki.py +++ b/src/saml2/cryptography/pki.py @@ -1,9 +1,48 @@ """This module provides methods for PKI operations.""" -import cryptography.hazmat.backends as _backends +from logging import getLogger as get_logger + import cryptography.x509 as _x509 +from cryptography.hazmat.primitives.serialization import Encoding as _cryptography_encoding + + +logger = get_logger(__name__) + +DEFAULT_CERT_TYPE = "pem" def load_pem_x509_certificate(data): """Load X.509 PEM certificate.""" - return _x509.load_pem_x509_certificate(data, _backends.default_backend()) + return _x509.load_pem_x509_certificate(data) + + +def load_der_x509_certificate(data): + """Load X.509 DER certificate.""" + return _x509.load_der_x509_certificate(data) + + +def load_x509_certificate(data, cert_type="pem"): + cert_reader = _x509_loaders.get(cert_type) + + if not cert_reader: + cert_reader = _x509_loaders.get("pem") + context = { + "message": "Unknown cert_type, falling back to default", + "cert_type": cert_type, + "default": DEFAULT_CERT_TYPE, + } + logger.warning(context) + + cert = cert_reader(data) + return cert + + +def get_public_bytes_from_cert(cert): + data = cert.public_bytes(_cryptography_encoding.PEM).decode() + return data + + +_x509_loaders = { + "pem": load_pem_x509_certificate, + "der": load_der_x509_certificate, +} diff --git a/src/saml2/cryptography/symmetric.py b/src/saml2/cryptography/symmetric.py index ff73641e..ce0e19ee 100644 --- a/src/saml2/cryptography/symmetric.py +++ b/src/saml2/cryptography/symmetric.py @@ -10,7 +10,6 @@ import logging from warnings import warn as _warn import cryptography.fernet as _fernet -import cryptography.hazmat.backends as _backends import cryptography.hazmat.primitives.ciphers as _ciphers from .errors import SymmetricCryptographyError @@ -158,10 +157,7 @@ class AESCipher(object): except KeyError: raise Exception('Unsupported chaining mode: {}'.format(cmode)) - cipher = _ciphers.Cipher( - _ciphers.algorithms.AES(self.key), - mode(iv), - backend=_backends.default_backend()) + cipher = _ciphers.Cipher(_ciphers.algorithms.AES(self.key), mode(iv)) return cipher, iv diff --git a/src/saml2/metadata.py b/src/saml2/metadata.py index e7ab6011..379f73fe 100644 --- a/src/saml2/metadata.py +++ b/src/saml2/metadata.py @@ -2,6 +2,7 @@ from saml2.algsupport import algorithm_support_in_metadata from saml2.md import AttributeProfile from saml2.sigver import security_context +from saml2.cert import read_cert_from_file from saml2.config import Config from saml2.validate import valid_instance from saml2.time_util import in_a_while @@ -688,14 +689,14 @@ def entity_descriptor(confd): enc_cert = None if confd.cert_file is not None: mycert = [] - mycert.append("".join(read_cert(confd.cert_file))) + mycert.append(read_cert_from_file(confd.cert_file)) if confd.additional_cert_files is not None: for _cert_file in confd.additional_cert_files: - mycert.append("".join(read_cert(_cert_file))) + mycert.append(read_cert_from_file(_cert_file)) if confd.encryption_keypairs is not None: enc_cert = [] for _encryption in confd.encryption_keypairs: - enc_cert.append("".join(read_cert(_encryption["cert_file"]))) + enc_cert.append(read_cert_from_file(_encryption["cert_file"])) entd = md.EntityDescriptor() entd.entity_id = confd.entityid @@ -844,9 +845,3 @@ def sign_entity_descriptor(edesc, ident, secc, sign_alg=None, digest_alg=None): xmldoc = secc.sign_statement("%s" % edesc, class_name(edesc)) edesc = md.entity_descriptor_from_string(xmldoc) return edesc, xmldoc - - -def read_cert(path): - with open(path) as fp: - lines = fp.readlines() - return lines[1:-1] diff --git a/src/saml2/sigver.py b/src/saml2/sigver.py index af93c42d..79e23d4f 100644 --- a/src/saml2/sigver.py +++ b/src/saml2/sigver.py @@ -13,6 +13,7 @@ import re import six import sys from uuid import uuid4 as gen_random_key + from time import mktime from tempfile import NamedTemporaryFile from subprocess import Popen @@ -43,6 +44,8 @@ from saml2 import class_name from saml2 import saml from saml2 import ExtensionElement from saml2.cert import OpenSSLWrapper +from saml2.cert import read_cert_from_file +from saml2.cert import CertificateError from saml2.extension import pefim from saml2.extension.pefim import SPCertEnc from saml2.saml import EncryptedAssertion @@ -108,10 +111,6 @@ class BadSignature(SigverError): pass -class CertificateError(SigverError): - pass - - def get_pem_wrapped_unwrapped(cert): begin_cert = "-----BEGIN CERTIFICATE-----\n" end_cert = "\n-----END CERTIFICATE-----\n" @@ -120,11 +119,6 @@ def get_pem_wrapped_unwrapped(cert): return wrapped_cert, unwrapped_cert -def read_file(*args, **kwargs): - with open(*args, **kwargs) as handler: - return handler.read() - - def rm_xmltag(statement): XMLTAG = "<?xml version='1.0'?>" PREFIX1 = "<?xml version='1.0' encoding='UTF-8'?>" @@ -489,8 +483,9 @@ def pem_format(key): def import_rsa_key_from_file(filename): - data = read_file(filename, 'rb') - key = saml2.cryptography.asymmetric.load_pem_private_key(data, None) + with open(filename, "rb") as fd: + data = fd.read() + key = saml2.cryptography.asymmetric.load_pem_private_key(data) return key @@ -625,55 +620,6 @@ def verify_redirect_signature(saml_msg, crypto, cert=None, sigkey=None): return bool(signer.verify(string, _sign, _key)) -def make_str(txt): - if isinstance(txt, six.string_types): - return txt - else: - return txt.decode() - - -def read_cert_from_file(cert_file, cert_type): - """ Reads a certificate from a file. The assumption is that there is - only one certificate in the file - - :param cert_file: The name of the file - :param cert_type: The certificate type - :return: A base64 encoded certificate as a string or the empty string - """ - - if not cert_file: - return '' - - if cert_type == 'pem': - _a = read_file(cert_file, 'rb').decode() - _b = _a.replace('\r\n', '\n') - lines = _b.split('\n') - - for pattern in ( - '-----BEGIN CERTIFICATE-----', - '-----BEGIN PUBLIC KEY-----'): - if pattern in lines: - lines = lines[lines.index(pattern) + 1:] - break - else: - raise CertificateError('Strange beginning of PEM file') - - for pattern in ( - '-----END CERTIFICATE-----', - '-----END PUBLIC KEY-----'): - if pattern in lines: - lines = lines[:lines.index(pattern)] - break - else: - raise CertificateError('Strange end of PEM file') - return make_str(''.join(lines).encode()) - - if cert_type in ['der', 'cer', 'crt']: - data = read_file(cert_file, 'rb') - _cert = base64.b64encode(data) - return make_str(_cert) - - class CryptoBackend(object): def version(self): raise NotImplementedError() diff --git a/tests/extra_lines.crt b/tests/extra_lines.crt new file mode 100644 index 00000000..05b68bef --- /dev/null +++ b/tests/extra_lines.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIICITCCAYoCAQEwDQYJKoZIhvcNAQELBQAwWDELMAkGA1UEBhMCenoxCzAJBgNV +BAgMAnp6MQ0wCwYDVQQHDAR6enp6MQ4wDAYDVQQKDAVaenp6ejEOMAwGA1UECwwF +Wnp6enoxDTALBgNVBAMMBHRlc3QwIBcNMTkwNDEyMTk1MDM0WhgPMzAxODA4MTMx +OTUwMzRaMFgxCzAJBgNVBAYTAnp6MQswCQYDVQQIDAJ6ejENMAsGA1UEBwwEenp6 +ejEOMAwGA1UECgwFWnp6enoxDjAMBgNVBAsMBVp6enp6MQ0wCwYDVQQDDAR0ZXN0 +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjW0kJM+4baWKtvO24ZsGXNvNK +KkwTMz7OW5Z6BRqhSOq2WA0c5NCpMk6rD8Z2OTFEolPojEjf8dVyd/Ds/hrjFKQv +8wQgbdXLN51YTIsgd6h+hBJO+vzhl0PT4aT7M0JKo5ALtS6qk4tsworW2BnwyvsG +SAinwfeWt4t/b1J3kwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAFtj7WArQQBugmh/ +KQjjlfTQ5A052QeXfgTyO9vv1S6MRIi7qgiaEv49cGXnJv/TWbySkMKObPMUApjg +6z8PqcxuShew5FCTkNvwhABFPiyu0fUj3e2FEPHfsBu76jz4ugtmhUqjqhzwFY9c +tnWRkkl6J0AjM3LnHOSgjNIclDZG +-----END CERTIFICATE----- + + + + + diff --git a/tests/malformed.crt b/tests/malformed.crt new file mode 100644 index 00000000..fb4098ba --- /dev/null +++ b/tests/malformed.crt @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIICITCCAYoCAQEwDQYJKoZIhvcNAQELBQAwWDELMAkGA1UEBhMCenoxCzAJBgNV +BAgMAnp6MQ0wCwYDVQQHDAR6enp6MQ4wDAYDVQQKDAVaenp6ejEOMAwGA1UECwwF +Wnp6enoxDTALBgNVBAMMBHRlc3QwIBcNMTkwNDEyMTk1MDM0WhgPMzAxODA4MTMx +OTUwMzRaMFgxCzAJBgNVBAYTAnp6MQswCQYDVQQIDAJ6ejENMAsGA1UEBwwEenp6 +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjW0kJM+4baWKtvO24ZsGXNvNK +KkwTMz7OW5Z6BRqhSOq2WA0c5NCpMk6rD8Z2OTFEolPojEjf8dVyd/Ds/hrjFKQv +8wQgbdXLN51YTIsgd6h+hBJO+vzhl0PT4aT7M0JKo5ALtS6qk4tsworW2BnwyvsG +SAinwfeWt4t/b1J3kwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAFtj7WArQQBugmh/ +KQjjlfTQ5A052QeXfgTyO9vv1S6MRIi7qgiaEv49cGXnJv/TWbySkMKObPMUApjg +6z8PqcxuShew5FCTkNvwhABFPiyu0fUj3e2FEPHfsBu76jz4ugtmhUqjqhzwFY9c +tnWRkkl6J0AjM3LnHOSgjNIclDZG diff --git a/tests/test_1.der b/tests/test_1.der Binary files differnew file mode 100644 index 00000000..77abcf8d --- /dev/null +++ b/tests/test_1.der diff --git a/tests/test_39_metadata.py b/tests/test_39_metadata.py index 06de507a..80f36a41 100644 --- a/tests/test_39_metadata.py +++ b/tests/test_39_metadata.py @@ -1,12 +1,16 @@ import copy from saml2.config import SPConfig -from saml2.metadata import create_metadata_string, entity_descriptor +from saml2.metadata import create_metadata_string +from saml2.metadata import entity_descriptor +from saml2.cert import read_cert_from_file as read_cert +from saml2.cert import CertificateError from saml2.saml import NAME_FORMAT_URI, NAME_FORMAT_BASIC from saml2 import sigver from pathutils import full_path -__author__ = 'roland' +from pytest import raises + sp_conf = { "entityid": "urn:mace:umu.se:saml:roland:sp", @@ -62,5 +66,18 @@ def test_signed_metadata_proper_str_bytes_handling(): sp_metadata = create_metadata_string('', config=cnf, sign=True) +def test_cert_trailing_newlines_ignored(): + assert "".join(read_cert(full_path("extra_lines.crt"))) \ + == "".join(read_cert(full_path("test_2.crt"))) + + +def test_invalid_cert_raises_error(): + with raises(CertificateError): + read_cert(full_path("malformed.crt")) + + if __name__ == '__main__': test_requested_attribute_name_format() + test_cert_trailing_newlines_ignored() + test_invalid_cert_raises_error() + test_signed_metadata_proper_str_bytes_handling() diff --git a/tests/test_40_sigver.py b/tests/test_40_sigver.py index 87a785a1..e5225855 100644 --- a/tests/test_40_sigver.py +++ b/tests/test_40_sigver.py @@ -9,10 +9,11 @@ from saml2 import class_name from saml2 import time_util from saml2 import saml, samlp from saml2 import config +from saml2.cert import read_cert_from_file +from saml2.cert import CertificateError from saml2.sigver import pre_encryption_part from saml2.sigver import make_temp from saml2.sigver import XmlsecError -from saml2.sigver import SigverError from saml2.mdstore import MetadataStore from saml2.saml import assertion_from_string from saml2.saml import EncryptedAssertion @@ -97,8 +98,7 @@ def test_cert_from_instance_1(): assert certs[0] == CERT1 -@pytest.mark.skipif(not decoder, - reason="pyasn1 is not installed") +@pytest.mark.skipif(not decoder, reason="pyasn1 is not installed") def test_cert_from_instance_ssp(): with open(SIMPLE_SAML_PHP_RESPONSE) as fp: xml_response = fp.read() @@ -1114,6 +1114,21 @@ def test_xmlsec_output_line_parsing(): sigver.parse_xmlsec_output(output4) +def test_cert_trailing_newlines_ignored(): + assert read_cert_from_file(full_path("extra_lines.crt")) \ + == read_cert_from_file(full_path("test_2.crt")) + + +def test_invalid_cert_raises_error(): + with raises(CertificateError): + read_cert_from_file(full_path("malformed.crt")) + + +def test_der_certificate_loading(): + assert read_cert_from_file(full_path("test_1.der"), "der") == \ + read_cert_from_file(full_path("test_1.crt")) + + if __name__ == "__main__": # t = TestSecurity() # t.setup_class() diff --git a/tests/test_82_pefim.py b/tests/test_82_pefim.py index a593d035..613a343c 100644 --- a/tests/test_82_pefim.py +++ b/tests/test_82_pefim.py @@ -18,7 +18,7 @@ conf.load_file("server_conf") client = Saml2Client(conf) # place a certificate in an authn request -cert = read_cert_from_file(full_path("test.pem"), "pem") +cert = read_cert_from_file(full_path("test.pem")) spcertenc = SPCertEnc( x509_data=ds.X509Data( diff --git a/tests/test_94_read_cert.py b/tests/test_94_read_cert.py new file mode 100644 index 00000000..331a7c93 --- /dev/null +++ b/tests/test_94_read_cert.py @@ -0,0 +1,68 @@ +from pathutils import full_path +from saml2.cert import read_cert_from_file + + +def test_read_single_cert(): + cert = read_cert_from_file(full_path("test.pem")) + + assert cert == ( + "MIICsDCCAhmgAwIBAgIJAJrzqSSwmDY9MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV" + "BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX" + "aWRnaXRzIFB0eSBMdGQwHhcNMDkxMDA2MTk0OTQxWhcNMDkxMTA1MTk0OTQxWjBF" + "MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50" + "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB" + "gQDJg2cms7MqjniT8Fi/XkNHZNPbNVQyMUMXE9tXOdqwYCA1cc8vQdzkihscQMXy" + "3iPw2cMggBu6gjMTOSOxECkuvX5ZCclKr8pXAJM5cY6gVOaVO2PdTZcvDBKGbiaN" + "efiEw5hnoZomqZGp8wHNLAUkwtH9vjqqvxyS/vclc6k2ewIDAQABo4GnMIGkMB0G" + "A1UdDgQWBBRePsKHKYJsiojE78ZWXccK9K4aJTB1BgNVHSMEbjBsgBRePsKHKYJs" + "iojE78ZWXccK9K4aJaFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUt" + "U3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAJrzqSSw" + "mDY9MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAJSrKOEzHO7TL5cy6" + "h3qh+3+JAk8HbGBW+cbX6KBCAw/mzU8flK25vnWwXS3dv2FF3Aod0/S7AWNfKib5" + "U/SA9nJaz/mWeF9S0farz9AQFc8/NSzAzaVq7YbM4F6f6N2FRl7GikdXRCed45j6" + "mrPzGzk3ECbupFnqyREH3+ZPSdk=" + ) + + +def test_read_cert_chain(): + cert = read_cert_from_file(full_path("test_chain.pem")) + + assert cert == ( + "MIICsDCCAhmgAwIBAgIJAJrzqSSwmDY9MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV" + "BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX" + "aWRnaXRzIFB0eSBMdGQwHhcNMDkxMDA2MTk0OTQxWhcNMDkxMTA1MTk0OTQxWjBF" + "MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50" + "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB" + "gQDJg2cms7MqjniT8Fi/XkNHZNPbNVQyMUMXE9tXOdqwYCA1cc8vQdzkihscQMXy" + "3iPw2cMggBu6gjMTOSOxECkuvX5ZCclKr8pXAJM5cY6gVOaVO2PdTZcvDBKGbiaN" + "efiEw5hnoZomqZGp8wHNLAUkwtH9vjqqvxyS/vclc6k2ewIDAQABo4GnMIGkMB0G" + "A1UdDgQWBBRePsKHKYJsiojE78ZWXccK9K4aJTB1BgNVHSMEbjBsgBRePsKHKYJs" + "iojE78ZWXccK9K4aJaFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUt" + "U3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAJrzqSSw" + "mDY9MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAJSrKOEzHO7TL5cy6" + "h3qh+3+JAk8HbGBW+cbX6KBCAw/mzU8flK25vnWwXS3dv2FF3Aod0/S7AWNfKib5" + "U/SA9nJaz/mWeF9S0farz9AQFc8/NSzAzaVq7YbM4F6f6N2FRl7GikdXRCed45j6" + "mrPzGzk3ECbupFnqyREH3+ZPSdk=" + ) + + +def test_read_cert_chain_with_linebreaks(): + cert = read_cert_from_file(full_path("test_chain_with_linebreaks.pem")) + + assert cert == ( + "MIICsDCCAhmgAwIBAgIJAJrzqSSwmDY9MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV" + "BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX" + "aWRnaXRzIFB0eSBMdGQwHhcNMDkxMDA2MTk0OTQxWhcNMDkxMTA1MTk0OTQxWjBF" + "MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50" + "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB" + "gQDJg2cms7MqjniT8Fi/XkNHZNPbNVQyMUMXE9tXOdqwYCA1cc8vQdzkihscQMXy" + "3iPw2cMggBu6gjMTOSOxECkuvX5ZCclKr8pXAJM5cY6gVOaVO2PdTZcvDBKGbiaN" + "efiEw5hnoZomqZGp8wHNLAUkwtH9vjqqvxyS/vclc6k2ewIDAQABo4GnMIGkMB0G" + "A1UdDgQWBBRePsKHKYJsiojE78ZWXccK9K4aJTB1BgNVHSMEbjBsgBRePsKHKYJs" + "iojE78ZWXccK9K4aJaFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUt" + "U3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAJrzqSSw" + "mDY9MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAJSrKOEzHO7TL5cy6" + "h3qh+3+JAk8HbGBW+cbX6KBCAw/mzU8flK25vnWwXS3dv2FF3Aod0/S7AWNfKib5" + "U/SA9nJaz/mWeF9S0farz9AQFc8/NSzAzaVq7YbM4F6f6N2FRl7GikdXRCed45j6" + "mrPzGzk3ECbupFnqyREH3+ZPSdk=" + ) diff --git a/tests/test_chain.pem b/tests/test_chain.pem new file mode 100644 index 00000000..6b206e47 --- /dev/null +++ b/tests/test_chain.pem @@ -0,0 +1,39 @@ +-----BEGIN CERTIFICATE----- +MIICsDCCAhmgAwIBAgIJAJrzqSSwmDY9MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMDkxMDA2MTk0OTQxWhcNMDkxMTA1MTk0OTQxWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQDJg2cms7MqjniT8Fi/XkNHZNPbNVQyMUMXE9tXOdqwYCA1cc8vQdzkihscQMXy +3iPw2cMggBu6gjMTOSOxECkuvX5ZCclKr8pXAJM5cY6gVOaVO2PdTZcvDBKGbiaN +efiEw5hnoZomqZGp8wHNLAUkwtH9vjqqvxyS/vclc6k2ewIDAQABo4GnMIGkMB0G +A1UdDgQWBBRePsKHKYJsiojE78ZWXccK9K4aJTB1BgNVHSMEbjBsgBRePsKHKYJs +iojE78ZWXccK9K4aJaFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUt +U3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAJrzqSSw +mDY9MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAJSrKOEzHO7TL5cy6 +h3qh+3+JAk8HbGBW+cbX6KBCAw/mzU8flK25vnWwXS3dv2FF3Aod0/S7AWNfKib5 +U/SA9nJaz/mWeF9S0farz9AQFc8/NSzAzaVq7YbM4F6f6N2FRl7GikdXRCed45j6 +mrPzGzk3ECbupFnqyREH3+ZPSdk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgINSWITCHaai+Root+CAzANBgkqhkiG9w0BAQUFADBrMQsw +CQYDVQQGEwJDSDFAMD4GA1UEChM3U3dpdGNoIC0gVGVsZWluZm9ybWF0aWtkaWVu +c3RlIGZ1ZXIgTGVocmUgdW5kIEZvcnNjaHVuZzEaMBgGA1UEAxMRU1dJVENIYWFp +IFJvb3QgQ0EwHhcNMDgwNTE1MDYzMDAwWhcNMjgwNTE1MDYyOTU5WjBrMQswCQYD +VQQGEwJDSDFAMD4GA1UEChM3U3dpdGNoIC0gVGVsZWluZm9ybWF0aWtkaWVuc3Rl +IGZ1ZXIgTGVocmUgdW5kIEZvcnNjaHVuZzEaMBgGA1UEAxMRU1dJVENIYWFpIFJv +b3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUSWbn/rhWew/s +LJRyciyRKDGyFXSgiDO/EohYuZLw6EAKLLlhZorNtEHQbbn0Oo13S33MclHMvGWT +KJM0u1hG+6gLy78EPmJbqAE1Uv23wVEH4SX0VJfl3JVqIebiAH/CjuLubgMUspDI +jOdQHNLS7pthTbm7Tgh7zMsiLPyMTZJep5CGbqv8NoK6bMaF0Z+Bt7e1JRlhHFCV +iJJaR/+hfpzLsJ8NWVivvrpRGaGJ1XR+9FGsTkjNdMCirNJJZ6XvUOe5w7pHSd9M +cppFP0eyLs02AMzMXI4iz6PK/w3EdzXGXpK+gSgvLxWYct4xHpv1e2NXhNgdJOSN +9ra/wJLVAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG +MB0GA1UdDgQWBBTpmuIGWOsP14EDXVyXubG1k307hDANBgkqhkiG9w0BAQUFAAOC +AQEAMV/eIW6pFB+mbk7rD7hUPTWDRaoca3kHqmFGFnHfuY8+c0/Mqjh8Y/jyX1yb +f58crTSWrbyGbUZ3oxDGQ34tuZSkmeR32NqryiX3sP5qlNSozVguQKt8o4vhS1Qe +WPsXALs3em2pdKuIGSOpbuDnopPcmU2g5Zi2R5P7qpKDKAKtNUEwV+LW7GBMEksO +Nj7BFXk4AFBFBijaYJGgHmoKSImVgeNIvsV+BSv5HJ4q6vcxfnwuvvGHM0AGphYO +6f5qtHMUgvAblI8M/2QsBgethaGrirtKJ3aCRLdaR2R1QfaGRpck/Ron5/MpMxiJ +wLT8YlW/zjx2yNABhPSAjfzeMw== +-----END CERTIFICATE----- diff --git a/tests/test_chain_with_linebreaks.pem b/tests/test_chain_with_linebreaks.pem new file mode 100644 index 00000000..68ec8a4d --- /dev/null +++ b/tests/test_chain_with_linebreaks.pem @@ -0,0 +1,51 @@ + + + + + + +-----BEGIN CERTIFICATE----- +MIICsDCCAhmgAwIBAgIJAJrzqSSwmDY9MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMDkxMDA2MTk0OTQxWhcNMDkxMTA1MTk0OTQxWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQDJg2cms7MqjniT8Fi/XkNHZNPbNVQyMUMXE9tXOdqwYCA1cc8vQdzkihscQMXy +3iPw2cMggBu6gjMTOSOxECkuvX5ZCclKr8pXAJM5cY6gVOaVO2PdTZcvDBKGbiaN +efiEw5hnoZomqZGp8wHNLAUkwtH9vjqqvxyS/vclc6k2ewIDAQABo4GnMIGkMB0G +A1UdDgQWBBRePsKHKYJsiojE78ZWXccK9K4aJTB1BgNVHSMEbjBsgBRePsKHKYJs +iojE78ZWXccK9K4aJaFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUt +U3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAJrzqSSw +mDY9MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAJSrKOEzHO7TL5cy6 +h3qh+3+JAk8HbGBW+cbX6KBCAw/mzU8flK25vnWwXS3dv2FF3Aod0/S7AWNfKib5 +U/SA9nJaz/mWeF9S0farz9AQFc8/NSzAzaVq7YbM4F6f6N2FRl7GikdXRCed45j6 +mrPzGzk3ECbupFnqyREH3+ZPSdk= +-----END CERTIFICATE----- + + + +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgINSWITCHaai+Root+CAzANBgkqhkiG9w0BAQUFADBrMQsw +CQYDVQQGEwJDSDFAMD4GA1UEChM3U3dpdGNoIC0gVGVsZWluZm9ybWF0aWtkaWVu +c3RlIGZ1ZXIgTGVocmUgdW5kIEZvcnNjaHVuZzEaMBgGA1UEAxMRU1dJVENIYWFp +IFJvb3QgQ0EwHhcNMDgwNTE1MDYzMDAwWhcNMjgwNTE1MDYyOTU5WjBrMQswCQYD +VQQGEwJDSDFAMD4GA1UEChM3U3dpdGNoIC0gVGVsZWluZm9ybWF0aWtkaWVuc3Rl +IGZ1ZXIgTGVocmUgdW5kIEZvcnNjaHVuZzEaMBgGA1UEAxMRU1dJVENIYWFpIFJv +b3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUSWbn/rhWew/s +LJRyciyRKDGyFXSgiDO/EohYuZLw6EAKLLlhZorNtEHQbbn0Oo13S33MclHMvGWT +KJM0u1hG+6gLy78EPmJbqAE1Uv23wVEH4SX0VJfl3JVqIebiAH/CjuLubgMUspDI +jOdQHNLS7pthTbm7Tgh7zMsiLPyMTZJep5CGbqv8NoK6bMaF0Z+Bt7e1JRlhHFCV +iJJaR/+hfpzLsJ8NWVivvrpRGaGJ1XR+9FGsTkjNdMCirNJJZ6XvUOe5w7pHSd9M +cppFP0eyLs02AMzMXI4iz6PK/w3EdzXGXpK+gSgvLxWYct4xHpv1e2NXhNgdJOSN +9ra/wJLVAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG +MB0GA1UdDgQWBBTpmuIGWOsP14EDXVyXubG1k307hDANBgkqhkiG9w0BAQUFAAOC +AQEAMV/eIW6pFB+mbk7rD7hUPTWDRaoca3kHqmFGFnHfuY8+c0/Mqjh8Y/jyX1yb +f58crTSWrbyGbUZ3oxDGQ34tuZSkmeR32NqryiX3sP5qlNSozVguQKt8o4vhS1Qe +WPsXALs3em2pdKuIGSOpbuDnopPcmU2g5Zi2R5P7qpKDKAKtNUEwV+LW7GBMEksO +Nj7BFXk4AFBFBijaYJGgHmoKSImVgeNIvsV+BSv5HJ4q6vcxfnwuvvGHM0AGphYO +6f5qtHMUgvAblI8M/2QsBgethaGrirtKJ3aCRLdaR2R1QfaGRpck/Ron5/MpMxiJ +wLT8YlW/zjx2yNABhPSAjfzeMw== +-----END CERTIFICATE----- + + + |