1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
import os
import tempfile
from contextlib import contextmanager
from unittest import TestCase
from a38.crypto import P7M, InvalidSignatureError
# This is the CA certificate used to validate tests/data/test.txt.p7m
#
# The signature on the test file will expire (next expiration date: May 6 23:59:59 2024 GMT)
#
# To refresh it:
#
# 1. Sign tests/data/test.txt with a CAdES envelope
# 2. Extract the signature:
# openssl smime -verify -in tests/data/test.txt.p7m -inform der -noverify -signer /tmp/cert.pem -out /dev/null
# 3. Get signature information:
# openssl x509 -inform pem -in /tmp/cert.pem -text
# 4. Compute the issuer hash to find the CA certificate:
# openssl x509 -inform pem -in /tmp/cert.pem -issuer_hash
# 5. Download/refresh the CA certificate database:
# ./a38tool update_capath certs
# 6. Find the file named with the issuer hash in certs/
# 7. Update the CA_CERT_HASH variable below with the name of the file you just
# found in certs/
# 8. Replace the value of CA_CERT with its contents
#
CA_CERT = """
-----BEGIN CERTIFICATE-----
MIIE+jCCA+KgAwIBAgIQbK2AXjA4PMWG8x+rL26V9zANBgkqhkiG9w0BAQsFADBs
MQswCQYDVQQGEwJJVDEYMBYGA1UECgwPQXJ1YmFQRUMgUy5wLkEuMSEwHwYDVQQL
DBhDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eUMxIDAeBgNVBAMMF0FydWJhUEVDIFMu
cC5BLiBORyBDQSAzMB4XDTEwMTAyMjAwMDAwMFoXDTMwMTAyMjIzNTk1OVowbDEL
MAkGA1UEBhMCSVQxGDAWBgNVBAoMD0FydWJhUEVDIFMucC5BLjEhMB8GA1UECwwY
Q2VydGlmaWNhdGlvbiBBdXRob3JpdHlDMSAwHgYDVQQDDBdBcnViYVBFQyBTLnAu
QS4gTkcgQ0EgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtkY4EH
G+Nh4VYLL4R5tvmX6J+AYlL2BPDUCLN92+zi9QMbsh84zbRE+om9KE8P67mST2my
bhGTz6dzeK1BrQfSdKJ8AGxePzqUq+uGHGULoy4A6ey4EyqTfxY+pGzjB7OVcuiw
y7iV6k1YjshIsmNjTmYOAQepZMgBmxHPnR6IW9MsAOFBBQH/vJFQDeBts/rA6lbM
/VsURwzr6XOqCzwJK/csKvuE/rAaRKY+IPzah8mou//yEi4V401J1JYfPanbCJOW
nIty9HaioUe5Fu2jw4UP7T5Cbw4lND1sP7HVhsVRDuTj3gF9ulJ7EBmcR/2THDZC
ozD76uwuTmkm4VsCAwEAAaOCAZYwggGSMD8GCCsGAQUFBwEBBDMwMTAvBggrBgEF
BQcwAYYjaHR0cDovL29jc3AuYXJ1YmFwZWMudHJ1c3RpdGFsaWEuaXQwEgYDVR0T
AQH/BAgwBgEB/wIBADBGBgNVHSAEPzA9MDsGCisGAQQBgegtAQEwLTArBggrBgEF
BQcCARYfaHR0cHM6Ly9jYS5hcnViYXBlYy5pdC9jcHMuaHRtbDBqBgNVHR8EYzBh
MF+gXaBbhllodHRwOi8vb25zaXRlY3JsLmFydWJhcGVjLnRydXN0aXRhbGlhLml0
L0FydWJhUEVDU3BBQ2VydGlmaWNhdGlvbkF1dGhvcml0eUMvTGF0ZXN0Q1JMLmNy
bDArBgNVHRIEJDAipCAwHjEcMBoGA1UEAxMTR09WVlNQLUMxLTIwNDgtMS0xMDAO
BgNVHQ8BAf8EBAMCAQYwKwYDVR0RBCQwIqQgMB4xHDAaBgNVBAMTE0dPVlZTUC1D
MS0yMDQ4LTEtMTAwHQYDVR0OBBYEFPDARbG2NbTqXyn6gwNK3C/1s33oMA0GCSqG
SIb3DQEBCwUAA4IBAQBRGwGypquxMawPV6ZN5l/2eJdaaqgnYolin1PGXJUFRQy3
k5FK0Fwk/90U/j/ue83cYdsRpPVpo17LOk7hCNSFk/W2SRVGvqaM77/cVpgFwm25
Ab2x5sMxwJ9Uoouba00CDl2SiYgn9KN+Bd3LHrwtpO8IkzwSE7k0kKmDLdCZTyUO
ZPR8RKpwedjLJoiyXCtq9PKA3avI1R6N8yOxbK954+nSOsHfmGDP4wQi8PUJIWBm
dlpHNM669BLdLwj6lpCjNI6AuP4K5Jw1qkOmcccnVWxkk0r2qNu87AlVosHpKf6G
jkJbJNWfBsgjRHGg6Pq3enAf8/7DfkoCyKUzI8zZ
-----END CERTIFICATE-----
"""
CA_CERT_HASH = "b72ed47c.0"
class TestSignature(TestCase):
@contextmanager
def capath(self):
with tempfile.TemporaryDirectory() as td:
with open(os.path.join(td, CA_CERT_HASH), "wt") as fd:
fd.write(CA_CERT)
yield td
def test_load(self):
p7m = P7M("tests/data/test.txt.p7m")
data = p7m.get_payload()
self.assertEqual(
data,
"This is only a test payload.\n"
"\n"
"Questo รจ solo un payload di test.\n".encode("utf8"))
def test_verify(self):
p7m = P7M("tests/data/test.txt.p7m")
if p7m.is_expired():
self.skipTest("test signature has expired and needs to be regenerated")
with self.capath() as capath:
p7m.verify_signature(capath)
def test_verify_corrupted_random(self):
p7m = P7M("tests/data/test.txt.p7m")
if p7m.is_expired():
self.skipTest("test signature has expired and needs to be regenerated")
data_mid = len(p7m.data) // 2
p7m.data = p7m.data[:data_mid] + bytes([p7m.data[data_mid] + 1]) + p7m.data[data_mid + 1:]
with self.capath() as capath:
with self.assertRaises(InvalidSignatureError):
p7m.verify_signature(capath)
def test_verify_corrupted_payload(self):
p7m = P7M("tests/data/test.txt.p7m")
if p7m.is_expired():
self.skipTest("test signature has expired and needs to be regenerated")
signed_data = p7m.get_signed_data()
encap_content_info = signed_data["encap_content_info"]
encap_content_info["content"] = b"All your base are belong to us"
p7m.data = p7m.content_info.dump()
with self.capath() as capath:
with self.assertRaisesRegex(InvalidSignatureError, r"routines:CMS_verify:content verify error"):
p7m.verify_signature(capath)
def test_verify_noca(self):
p7m = P7M("tests/data/test.txt.p7m")
if p7m.is_expired():
self.skipTest("test signature has expired and needs to be regenerated")
with tempfile.TemporaryDirectory() as capath:
with self.assertRaisesRegex(
InvalidSignatureError, r"Verify error:\s*unable to get local issuer certificate"):
p7m.verify_signature(capath)
|