diff --git a/src/auto_archiver/modules/timestamping_enricher/timestamping_enricher.py b/src/auto_archiver/modules/timestamping_enricher/timestamping_enricher.py index b29d338..9742587 100644 --- a/src/auto_archiver/modules/timestamping_enricher/timestamping_enricher.py +++ b/src/auto_archiver/modules/timestamping_enricher/timestamping_enricher.py @@ -81,7 +81,7 @@ class TimestampingEnricher(Enricher): raise ValueError(f"No valid root certificate found for {tsa_url=}. Are you sure it's a trusted TSA? Or define an alternative trusted root with `cert_authorities`.") # save the timestamping certificate - cert_chain = self.save_certificate(signed) + cert_chain = self.save_certificate(signed, root_cert) # continue with saving the timestamp token tst_fn = os.path.join(self.tmp_dir, f"timestamp_token_{slugify(tsa_url)}") @@ -102,9 +102,19 @@ class TimestampingEnricher(Enricher): else: logger.warning(f"No successful timestamps for {url=}") - def verify_signed(self, timestamp_response: TimeStampResponse, message: bytes) -> None: + def verify_signed(self, timestamp_response: TimeStampResponse, message: bytes) -> x509.Certificate: """ - Verify a Signed Timestamp using the TSA provided by the Trusted Root. + Verify a Signed Timestamp Response is trusted by a known Certificate Authority. + + Args: + timestamp_response (TimeStampResponse): The signed timestamp response. + message (bytes): The message that was timestamped. + + Returns: + x509.Certificate: A valid root certificate that was used to sign the timestamp response, or None + + Raises: + ValueError: If no valid root certificate was found in the trusted root store. """ trusted_root_path = self.cert_authorities or certifi.where() @@ -148,7 +158,7 @@ class TimestampingEnricher(Enricher): logger.debug(f"Unable to verify Timestamp with CA {certificate.subject}: {e}") continue - return None + raise ValueError(f"No valid root certificate found in {trusted_root_path}.") def sign_data(self, tsa_url: str, bytes_data: bytes) -> TimeStampResponse: # see https://github.com/sigstore/sigstore-python/blob/99948d5b80525a5a104e904ffea58169dc6e0629/sigstore/_internal/timestamp.py#L84-L121 @@ -173,19 +183,31 @@ class TimestampingEnricher(Enricher): def tst_certs(self, tsp_response: TimeStampResponse): signed_data: SignedData = tsp_response.signed_data - return [x509.load_der_x509_certificate(c) for c in signed_data.certificates] + certs = [x509.load_der_x509_certificate(c) for c in signed_data.certificates] + # reorder the certs to be in the correct order + ordered_certs = [] + while(len(ordered_certs) < len(certs)): + if len(ordered_certs) == 0: + for cert in certs: + if not [c for c in certs if c.subject == cert.issuer]: + ordered_certs.append(cert) + break + else: + for cert in certs: + if cert.issuer == ordered_certs[-1].subject: + ordered_certs.append(cert) + break + return ordered_certs - - def save_certificate(self, tsp_response: TimeStampResponse) -> list[Media]: + def save_certificate(self, tsp_response: TimeStampResponse, verified_root_cert: x509.Certificate) -> list[Media]: # returns the leaf certificate URL, fails if not set - certificates = self.tst_certs(tsp_response) + certificates = self.tst_certs(tsp_response) + [verified_root_cert] cert_chain = [] - for cert in certificates: - cert_fn = os.path.join(self.tmp_dir, f"{str(cert.serial_number)[:20]}.crt") - print(cert_fn) + for i, cert in enumerate(certificates): + cert_fn = os.path.join(self.tmp_dir, f"{i+1} – {str(cert.serial_number)[:20]}.crt") with open(cert_fn, "wb") as f: f.write(cert.public_bytes(encoding=serialization.Encoding.PEM)) cert_chain.append(Media(filename=cert_fn).set("subject", cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)[0].value)) diff --git a/tests/data/timestamp_token_digicert_com.crt b/tests/data/timestamp_token_digicert_com.crt deleted file mode 100644 index 592edf4..0000000 Binary files a/tests/data/timestamp_token_digicert_com.crt and /dev/null differ diff --git a/tests/data/timestamping/intermediate.crt b/tests/data/timestamping/intermediate.crt new file mode 100644 index 0000000..a9242f9 --- /dev/null +++ b/tests/data/timestamping/intermediate.crt @@ -0,0 +1,44 @@ +-----BEGIN CERTIFICATE----- +MIIHuDCCBaCgAwIBAgIQQAF/lJAVu6kSuFeWPUTs7jANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMjIwMzE2MjEwOTA1WhcNMzMw +NjEyMjEwOTA1WjBFMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSIw +IAYDVQQDExlUcnVzdElEIFRpbWVzdGFtcGluZyBDQSAzMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAqGL0RYFG7mL0RgSXLynLNWhEVrhsKhrVL4rSG+NA +p4v8TbAP2YXsqWB8yZgj9DQ55AECnmQ2Uo/BqQSsI/AOr9ctqZykItmca/nGjKez +l1kZS2YoNc4Zjj+7QO9iNunclA06fBhI+iQHAam7isQLK3CwXRDLzKkMs7TisMoG +QOSd0M8P6YY/QOGYv/+tCxmfvUz2GjWzQQemgiuLjvGhPwo+hrcNzays9j0G7QtA +LkJ0KfvJS+guvCvSuEfDzt3BaPIpD2q6GYK+MUiNis3uwwngauyL4r048wdvUSsf +92Kyr6T1pAfjjPyVDNazf/w/BjzA6ewNevFVLNfE0DhQkXMmsNVGBzY5Phhlp5fb +TwsrD19K0FPgbGO/l/Zp2dheeiCbe09bxbhdeahSBtTVPca4Vu3Ljz+PRZjFodq7 ++lziqqpqqCP/ikEnmK/QkxjCG7AkX384dxg7yb5jjtXOnP5Yv4SXuV4SNNVVUBJf +bLXyYAf3Q0Dal85ZxNQd0QNPQIsYWv9ttTMVc6sVErdfTBPw355St6bHz91LUoDD +0S/GjUif8LYhVlZGXlwjYmVZOb2Z7+DAamzjwVrSsrxGCJ66Coy1rKapJuHVsfGA +W44p2ioIEZT3s6nQJkCt7te4ab1iWzaydZGAYyBao0K7kfK3vSp4AXsE5t5y6dpH +Yo0CAwEAAaOCAp0wggKZMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQD +AgGGMIGJBggrBgEFBQcBAQR9MHswMAYIKwYBBQUHMAGGJGh0dHA6Ly9jb21tZXJj +aWFsLm9jc3AuaWRlbnRydXN0LmNvbTBHBggrBgEFBQcwAoY7aHR0cDovL3ZhbGlk +YXRpb24uaWRlbnRydXN0LmNvbS9yb290cy9jb21tZXJjaWFscm9vdGNhMS5wN2Mw +HwYDVR0jBBgwFoAU7UQZwNPwBovupHu+QucmVMiONnYwggFEBgNVHSAEggE7MIIB +NzAIBgZngQwBBAIwDQYLYIZIAYb5LwAGDQMwggEaBgtghkgBhvkvAAYNATCCAQkw +SgYIKwYBBQUHAgEWPmh0dHBzOi8vc2VjdXJlLmlkZW50cnVzdC5jb20vY2VydGlm +aWNhdGVzL3BvbGljeS90cy9pbmRleC5odG1sMIG6BggrBgEFBQcCAjCBrQyBqlRo +aXMgVHJ1c3RJRCBDZXJ0aWZpY2F0ZSBoYXMgYmVlbiBpc3N1ZWQgaW4gYWNjb3Jk +YW5jZSB3aXRoIElkZW5UcnVzdCdzIFRydXN0SUQgQ2VydGlmaWNhdGUgUG9saWN5 +IGZvdW5kIGF0IGh0dHBzOi8vc2VjdXJlLmlkZW50cnVzdC5jb20vY2VydGlmaWNh +dGVzL3BvbGljeS90cy9pbmRleC5odG1sMEoGA1UdHwRDMEEwP6A9oDuGOWh0dHA6 +Ly92YWxpZGF0aW9uLmlkZW50cnVzdC5jb20vY3JsL2NvbW1lcmNpYWxyb290Y2Ex +LmNybDAdBgNVHQ4EFgQUyjLwNnzHKtqRtXyHihG9uCJsvwkwEwYDVR0lBAwwCgYI +KwYBBQUHAwgwDQYJKoZIhvcNAQELBQADggIBACtnO4f6QB6v2yDFeld3Pa1H7Bmb +y2tSwzQ/5dB5WXmTZHlV433s7BDkpwGzK4fGBuTcx814uPUWWSwcL+f8bpfozBv6 +p855j/AlKul1EiPMKkMlLtwdiK6sWT2x8qaTm4fMGbcpgUbQnxOo4BnzVUmgs3ep +m9/qXf9GaWXRz4maSWl4z3apD3X/5oMrriGWIiW6ivCq8bmOBUdm0I9quhW9Snk2 +JAaqkVCjs06rqE3rRblyNdrSypGzo5eBT498aCfcvDPJX2/q2PMkLvkKoXtVJ1g4 +sEwDQxm2sg8QMEd2GKo+X7TqOeF8An7KOPDq9v0xtSsF4+ufFrl43vl6v4uMey68 +wOHv6VmaGpCtWk1e6lSq9jLQqRBBg8CMwpw6niVyvkrdh4Tvu+5HLrareZBp98PJ +2cQzrHk1SiPcyDxSlhbXRks/TgKXTicUm3pZsKZcTvCXHcqulN1eoQ3z9azMIuR7 +RtdECz2RJUI6Xg//6ZdMMgaDnktMALgAyo9GgGGVimx4E2/aM5r0cm+RCrk956BT +qahEdiGLWjgjq8dAJe4XfLtp6EmGvsw650uBbDA0Mg9nlSCFdGTMFBKlw65o2oJa +enMysAvE/VC39ZIEOBfk2IOj2GTYlOgHi0iIBIZf7SqdjhTAtoW7U9TTZj8SHRen +/EEe1WEcfTawcOhJ +-----END CERTIFICATE----- diff --git a/tests/data/timestamping/leaf.crt b/tests/data/timestamping/leaf.crt new file mode 100644 index 0000000..539ae6e --- /dev/null +++ b/tests/data/timestamping/leaf.crt @@ -0,0 +1,39 @@ +-----BEGIN CERTIFICATE----- +MIIG4zCCBMugAwIBAgIQQAGSoSzKR+4rZmhPudMJdjANBgkqhkiG9w0BAQsFADBF +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSIwIAYDVQQDExlUcnVz +dElEIFRpbWVzdGFtcGluZyBDQSAzMB4XDTI0MTAxODE5NDg0MFoXDTI2MDExNzE5 +NDgzOVowRzELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUlkZW5UcnVzdDEkMCIGA1UE +AxMbVHJ1c3RJRCBUaW1lc3RhbXAgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA27BXl6MHeJwySCub5fd8rD4bWC2yOQE4hWDkw6YjMHMl +mKQVPIqD2+ezxhIK5GmwwNxDopo1ovsTMrF/KFsTExw0l4ZguJ+xs5W6qLrRVm7Z +TnkB6wMKaxR8+fdxtq9lnqRDnHtrGiGEQGOqVvUpAhnzioYa/5qWmqhRhdf7bRpI +1D71LC4UtWm1YG0PmJVSsE2ZqjB4rP7baj6hAlQxe0bvNwL/Bqy6D0QHNk2Xf2Vk +w7BLN7knh/SngAlzfumBg0cQff0C5DQgeyCQoM5/XBAyYZUQc//t2XVZPYiGUvOj +QNjLCbqOpRQf9JBaU/gh9Mf6Mbs6xh5qn4gKHpxOUMy+QfYAU+RiLhV4X0/brdqc +UOqRHte9gcv8yU4mqyMzbmHn5y09SkuhPOIhYE5Fd72XHeR8RnC9CI9V5NjVW370 +iNZuO2R2hw3dwtlWFxJPM+jortoxO3BPoxmppp/EdEH60p5Sk12eeyx86zieLb1E +JS5gEvu+jYWwKKjCf3visWC4OJNzbknGr3WRVOI6UvjyKrck3hpCuOjLXST+pEiB +XJzbiHCR5UJn8mXJnPAvKabgCGk7/trqrqB3Rkd2l5rce7maoyn265r/3IRLZisf +QdBsfzQv6RAP/zBFQkzcE2Yl12M25k2B6kFZMLsTT60jBTt1W6utXM2T7DbOwO8C +AwEAAaOCAcswggHHMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBYGA1Ud +JQEB/wQMMAoGCCsGAQUFBwMIMIGFBggrBgEFBQcBAQR5MHcwMAYIKwYBBQUHMAGG +JGh0dHA6Ly9jb21tZXJjaWFsLm9jc3AuaWRlbnRydXN0LmNvbTBDBggrBgEFBQcw +AoY3aHR0cDovL3ZhbGlkYXRpb24uaWRlbnRydXN0LmNvbS9jZXJ0cy90aW1lc3Rh +bXBpbmczLnA3YzAfBgNVHSMEGDAWgBTKMvA2fMcq2pG1fIeKEb24Imy/CTB/BgNV +HSAEeDB2MAgGBmeBDAEEAjANBgtghkgBhvkvAAYNATBbBgtghkgBhvkvAAYNAzBM +MEoGCCsGAQUFBwIBFj5odHRwczovL3NlY3VyZS5pZGVudHJ1c3QuY29tL2NlcnRp +ZmljYXRlcy9wb2xpY3kvdHMvaW5kZXguaHRtbDBGBgNVHR8EPzA9MDugOaA3hjVo +dHRwOi8vdmFsaWRhdGlvbi5pZGVudHJ1c3QuY29tL2NybC90aW1lc3RhbXBpbmcz +LmNybDAdBgNVHQ4EFgQUIYBfL7FSq7kLBlpOTWDaRGHtFgEwDQYJKoZIhvcNAQEL +BQADggIBAFIczKS3kFMFeX2WIC1uUj4Nvt+W2/kPNhuKukF2pOC+VcxrbbsTugTx +oO+X8J5JVX5sNP74p7YrkSY+dVPFQ+8rfJJeshSvJEQnt9DgsXPTRcU982OPmJCQ +QZY2Ux7xYfoEuWytuigyhMMoh+g5IzipQ56UCDY/sHY40SdLpSXg69RMy6y/L2Zm +9f4YPFrXPy7q3hGTemQHo+jmshg/hU/zIEjjfWx7uG223r0M5Ez9ks4y/EmtdT5l +KkF9RGALpKEBWIQaL+yi8X8NHRM1Qfs91GvEZe5wPri/5R9YvhiHWjizqxvDlqVW +ka6Mu13zbovM2vMppHJWYlvBTZ4z8vZBdNzN7fiTAdcd3lAl0A3wmpBIqrvFChhY +DX0Su1/3kA3X2PAJrbaZ7RNQ+Zjuz31T8QK0d1PyzHOZ/jK76f7Nb5Ic8fbALKzs +S+Yg3O4fmLqC0kERtL96xA/y+Y9oAJYMOOvrpBvpe1TdGZ5s3nRpLhWT4NEddkGg +AWodbBA3W0x5iKRWXAo+sATHTNXB6RGTIuF1/PC3R4fjbTMvpHXyW+bP+k8m+uIu +XLDMJ+XW5TZ01g6UGfg62ti4ohS0PyEHbnuEQDQogcqtqF0d8oihfcbDXOm/YgId +vhdRXJC/UZ0Q6Q6jtuj5uV76fvNU4j4FYKnXZqutzlCxeKn1odHN +-----END CERTIFICATE----- diff --git a/tests/data/timestamping/rfc3161-client-issue-104.tsr b/tests/data/timestamping/rfc3161-client-issue-104.tsr new file mode 100644 index 0000000..eae5900 Binary files /dev/null and b/tests/data/timestamping/rfc3161-client-issue-104.tsr differ diff --git a/tests/data/timestamping/root.crt b/tests/data/timestamping/root.crt new file mode 100644 index 0000000..de6f07d --- /dev/null +++ b/tests/data/timestamping/root.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- diff --git a/tests/data/timestamping/timestamp_response.tsr b/tests/data/timestamping/timestamp_response.tsr new file mode 100644 index 0000000..1ec90ac Binary files /dev/null and b/tests/data/timestamping/timestamp_response.tsr differ diff --git a/tests/enrichers/test_timestamping_enricher.py b/tests/enrichers/test_timestamping_enricher.py index 369610b..b5c6b77 100644 --- a/tests/enrichers/test_timestamping_enricher.py +++ b/tests/enrichers/test_timestamping_enricher.py @@ -1,7 +1,6 @@ import pytest from auto_archiver.modules.timestamping_enricher.timestamping_enricher import TimestampingEnricher from rfc3161_client import ( - TimestampRequestBuilder, TimeStampResponse, decode_timestamp_response, ) @@ -9,12 +8,17 @@ from rfc3161_client import ( from cryptography import x509 @pytest.fixture -def digicert(): - with open("tests/data/timestamp_token_digicert_com.crt", "rb") as f: - return f.read() +def timestamp_response() -> TimeStampResponse: + with open("tests/data/timestamping/timestamp_response.tsr", "rb") as f: + return decode_timestamp_response(f.read()) + +@pytest.fixture +def wrong_order_timestamp_response() -> TimeStampResponse: + with open("tests/data/timestamping/rfc3161-client-issue-104.tsr", "rb") as f: + return decode_timestamp_response(f.read()) @pytest.mark.download -def test_sign_data(setup_module): +def test_download_tsr(setup_module): tsa_url = "http://timestamp.identrust.com" tsp: TimestampingEnricher = setup_module("timestamping_enricher") @@ -22,27 +26,36 @@ def test_sign_data(setup_module): result: TimeStampResponse = tsp.sign_data(tsa_url, data) assert isinstance(result, TimeStampResponse) - root_cert: x509.Certificate = tsp.verify_signed(result, data) - assert root_cert.subject.rfc4514_string() == "CN=IdenTrust Commercial Root CA 1,O=IdenTrust,C=US" + verified_root_cert = tsp.verify_signed(result, data) + assert verified_root_cert.subject.rfc4514_string() == "CN=IdenTrust Commercial Root CA 1,O=IdenTrust,C=US" # test downloading the cert - cert_chain = tsp.save_certificate(result) - assert len(cert_chain) == 2 - -def test_tsp_enricher_download_syndication(setup_module, digicert): - tsp: TimestampingEnricher = setup_module("timestamping_enricher") - - cert_chain = tsp.download_and_verify_certificate(digicert) + cert_chain = tsp.save_certificate(result, verified_root_cert) assert len(cert_chain) == 3 - assert cert_chain[0].filename == f"{tsp.tmp_dir}/74515005589773707779.crt" - assert cert_chain[1].filename == f"{tsp.tmp_dir}/95861100433808324400.crt" - assert cert_chain[2].filename == f"{tsp.tmp_dir}/15527051335772373346.crt" - -def test_tst_cert_valid(setup_module, digicert): +def test_verify_save(setup_module, timestamp_response): tsp: TimestampingEnricher = setup_module("timestamping_enricher") - - try: - tsp.verify_signed(digicert, b"4b7b4e39f12b8c725e6e603e6d4422500316df94211070682ef10260ff5759ef") - except Exception as e: - pytest.fail(f"Verification failed: {e}") \ No newline at end of file + + verified_root_cert = tsp.verify_signed(timestamp_response, b"4b7b4e39f12b8c725e6e603e6d4422500316df94211070682ef10260ff5759ef") + assert verified_root_cert.subject.rfc4514_string() == "CN=IdenTrust Commercial Root CA 1,O=IdenTrust,C=US" + + cert_chain = tsp.save_certificate(timestamp_response, verified_root_cert) + assert len(cert_chain) == 3 + + assert cert_chain[0].filename == f"{tsp.tmp_dir}/1 – 85078371663472981624.crt" + assert cert_chain[1].filename == f"{tsp.tmp_dir}/2 – 85078758028491331763.crt" + assert cert_chain[2].filename == f"{tsp.tmp_dir}/3 – 13298821034946342390.crt" + + +def test_order_crt_correctly(setup_module, wrong_order_timestamp_response): + # reference: https://github.com/trailofbits/rfc3161-client/issues/104#issuecomment-2711244010 + tsp: TimestampingEnricher = setup_module("timestamping_enricher") + + # get the certificates, make sure the reordering is working: + + ordered_certs = tsp.tst_certs(wrong_order_timestamp_response) + assert len(ordered_certs) == 2 + assert ordered_certs[0].subject.rfc4514_string() == "CN=TrustID Timestamping CA 3,O=IdenTrust,C=US" + assert ordered_certs[1].subject.rfc4514_string() == "CN=TrustID Timestamp Authority,O=IdenTrust,C=US" + +