1+ from pathlib import Path
2+
13import pytest
24from callee import strings
5+
36from rsmime import Rsmime , exceptions
47
8+
9+ ATTACHED_SIGNATURE_REGEX = strings .Regex (
10+ b'MIME-Version: 1.0\n '
11+ b'Content-Disposition: attachment; filename="smime.p7m"\n '
12+ b'Content-Type: application/x-pkcs7-mime; smime-type=signed-data; name="smime.p7m"\n '
13+ b'Content-Transfer-Encoding: base64\n '
14+ b'\n '
15+ b'MIIJwQYJKoZIhvcNAQcCoIIJsjCCCa4CAQExDzANBglghkgBZQMEAgEFADASBgkq\n '
16+ b'[A-Za-z0-9/+=\n ]+\n '
17+ b'\n '
18+ )
19+
20+ DETACHED_SIGNATURE_REGEX = strings .Regex (
21+ b'MIME-Version: 1.0\n '
22+ b'Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----[A-Z0-9]+"\n \n '
23+ b'This is an S/MIME signed message\n \n '
24+ b'------[A-Z0-9]+\n '
25+ b'abc\n '
26+ b'------[A-Z0-9]+\n '
27+ b'Content-Type: application/x-pkcs7-signature; name="smime.p7s"\n '
28+ b'Content-Transfer-Encoding: base64\n '
29+ b'Content-Disposition: attachment; filename="smime.p7s"\n '
30+ b'\n '
31+ b'MIIJugYJKoZIhvcNAQcCoIIJqzCCCacCAQExDzANBglghkgBZQMEAgEFADALBgkq\n '
32+ b'[A-Za-z0-9/+=\n ]+\n '
33+ b'\n '
34+ b'------[A-Z0-9]+--\n '
35+ b'\n '
36+ )
37+
38+
39+ def _load_text (path : str ) -> str :
40+ return Path (path ).read_text ()
41+
42+
543working_client = Rsmime ('tests/data/certificate.crt' , 'tests/data/certificate.key' )
644expired_client = Rsmime ('tests/data/expired.crt' , 'tests/data/certificate.key' )
745
846
947class TestRsmime :
1048 def test_sign (self ):
1149 signed_data = working_client .sign (b'abc' )
12- assert signed_data == strings .Regex (
13- b'MIME-Version: 1.0\n '
14- b'Content-Disposition: attachment; filename="smime.p7m"\n '
15- b'Content-Type: application/x-pkcs7-mime; smime-type=signed-data; name="smime.p7m"\n '
16- b'Content-Transfer-Encoding: base64\n '
17- b'\n '
18- b'MIIJwQYJKoZIhvcNAQcCoIIJsjCCCa4CAQExDzANBglghkgBZQMEAgEFADASBgkq\n '
19- b'[A-Za-z0-9/+=\n ]+\n '
20- b'\n '
21- )
50+ assert signed_data == ATTACHED_SIGNATURE_REGEX
2251
2352 def test_sign_detached (self ):
2453 signed_data = working_client .sign (b'abc' , detached = True )
25- assert signed_data == strings .Regex (
26- b'MIME-Version: 1.0\n '
27- b'Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----[A-Z0-9]+"\n \n '
28- b'This is an S/MIME signed message\n \n '
29- b'------[A-Z0-9]+\n '
30- b'abc\n '
31- b'------[A-Z0-9]+\n '
32- b'Content-Type: application/x-pkcs7-signature; name="smime.p7s"\n '
33- b'Content-Transfer-Encoding: base64\n '
34- b'Content-Disposition: attachment; filename="smime.p7s"\n '
35- b'\n '
36- b'MIIJugYJKoZIhvcNAQcCoIIJqzCCCacCAQExDzANBglghkgBZQMEAgEFADALBgkq\n '
37- b'[A-Za-z0-9/+=\n ]+\n '
38- b'\n '
39- b'------[A-Z0-9]+--\n '
40- b'\n '
54+ assert signed_data == DETACHED_SIGNATURE_REGEX
55+
56+ def test_sign_with_in_memory_material (self ):
57+ client = Rsmime (
58+ cert_data = _load_text ('tests/data/certificate.crt' ),
59+ key_data = _load_text ('tests/data/certificate.key' ),
60+ )
61+
62+ signed_data = client .sign (b'abc' )
63+
64+ assert signed_data == ATTACHED_SIGNATURE_REGEX
65+
66+ def test_sign_with_in_memory_bytes_material (self ):
67+ client = Rsmime (
68+ cert_data = _load_text ('tests/data/certificate.crt' ).encode (),
69+ key_data = _load_text ('tests/data/certificate.key' ).encode (),
70+ )
71+
72+ signed_data = client .sign (b'abc' )
73+
74+ assert signed_data == ATTACHED_SIGNATURE_REGEX
75+
76+ def test_sign_with_path_objects (self ):
77+ client = Rsmime (
78+ Path ('tests/data/certificate.crt' ),
79+ Path ('tests/data/certificate.key' ),
4180 )
4281
82+ signed_data = client .sign (b'abc' )
83+
84+ assert signed_data == ATTACHED_SIGNATURE_REGEX
85+
4386 def test_sign_missing_cert (self ):
4487 with pytest .raises (
4588 exceptions .CertificateError , match = 'No such file or directory'
@@ -64,6 +107,52 @@ def test_sign_empty_data(self):
64107 with pytest .raises (exceptions .SignError , match = 'Cannot sign empty data' ):
65108 working_client .sign (b'' )
66109
110+ def test_conflicting_certificate_inputs (self ):
111+ with pytest .raises (
112+ exceptions .CertificateError ,
113+ match = 'Provide either cert_file or cert_data' ,
114+ ):
115+ Rsmime (
116+ 'tests/data/certificate.crt' ,
117+ 'tests/data/certificate.key' ,
118+ cert_data = _load_text ('tests/data/certificate.crt' ),
119+ )
120+
121+ def test_conflicting_key_inputs (self ):
122+ with pytest .raises (
123+ exceptions .CertificateError ,
124+ match = 'Provide either key_file or key_data' ,
125+ ):
126+ Rsmime (
127+ 'tests/data/certificate.crt' ,
128+ 'tests/data/certificate.key' ,
129+ key_data = _load_text ('tests/data/certificate.key' ),
130+ )
131+
132+ def test_missing_certificate_input (self ):
133+ with pytest .raises (
134+ exceptions .CertificateError ,
135+ match = 'cert_file or cert_data' ,
136+ ):
137+ Rsmime (key_data = _load_text ('tests/data/certificate.key' ))
138+
139+ def test_missing_key_input (self ):
140+ with pytest .raises (
141+ exceptions .CertificateError ,
142+ match = 'key_file or key_data' ,
143+ ):
144+ Rsmime (cert_data = _load_text ('tests/data/certificate.crt' ))
145+
146+ def test_in_memory_material_requires_text_or_bytes (self ):
147+ with pytest .raises (
148+ exceptions .CertificateError ,
149+ match = 'cert_data must be a str or bytes-like object' ,
150+ ):
151+ Rsmime (
152+ cert_data = object (),
153+ key_data = _load_text ('tests/data/certificate.key' ),
154+ )
155+
67156 def test_verify (self ):
68157 data = b'abc'
69158 signed_data = working_client .sign (data )
0 commit comments