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+
43+ def _load_bytes (path : str ) -> bytes :
44+ return Path (path ).read_bytes ()
45+
46+
547working_client = Rsmime ('tests/data/certificate.crt' , 'tests/data/certificate.key' )
648expired_client = Rsmime ('tests/data/expired.crt' , 'tests/data/certificate.key' )
749
850
951class TestRsmime :
1052 def test_sign (self ):
1153 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- )
54+ assert signed_data == ATTACHED_SIGNATURE_REGEX
2255
2356 def test_sign_detached (self ):
2457 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 '
58+ assert signed_data == DETACHED_SIGNATURE_REGEX
59+
60+ def test_sign_with_in_memory_material ( self ):
61+ client = Rsmime (
62+ cert_data = _load_text ( 'tests/data/certificate.crt' ),
63+ key_data = _load_text ( 'tests/data/certificate.key' ),
64+ )
65+
66+ signed_data = client . sign ( b'abc' )
67+
68+ assert signed_data == ATTACHED_SIGNATURE_REGEX
69+
70+ def test_sign_with_in_memory_bytes_material ( self ):
71+ client = Rsmime (
72+ cert_data = _load_text ( 'tests/data/certificate.crt' ). encode (),
73+ key_data = _load_text ( 'tests/data/certificate.key' ). encode (),
4174 )
4275
76+ signed_data = client .sign (b'abc' )
77+
78+ assert signed_data == ATTACHED_SIGNATURE_REGEX
79+
80+ def test_sign_with_in_memory_bytearray_material (self ):
81+ client = Rsmime (
82+ cert_data = bytearray (_load_bytes ('tests/data/certificate.crt' )),
83+ key_data = bytearray (_load_bytes ('tests/data/certificate.key' )),
84+ )
85+
86+ signed_data = client .sign (b'abc' )
87+
88+ assert signed_data == ATTACHED_SIGNATURE_REGEX
89+
90+ def test_sign_with_path_objects (self ):
91+ client = Rsmime (
92+ Path ('tests/data/certificate.crt' ),
93+ Path ('tests/data/certificate.key' ),
94+ )
95+
96+ signed_data = client .sign (b'abc' )
97+
98+ assert signed_data == ATTACHED_SIGNATURE_REGEX
99+
43100 def test_sign_missing_cert (self ):
44101 with pytest .raises (
45102 exceptions .CertificateError , match = 'No such file or directory'
@@ -64,6 +121,52 @@ def test_sign_empty_data(self):
64121 with pytest .raises (exceptions .SignError , match = 'Cannot sign empty data' ):
65122 working_client .sign (b'' )
66123
124+ def test_conflicting_certificate_inputs (self ):
125+ with pytest .raises (
126+ exceptions .CertificateError ,
127+ match = 'Provide either cert_file or cert_data' ,
128+ ):
129+ Rsmime (
130+ 'tests/data/certificate.crt' ,
131+ 'tests/data/certificate.key' ,
132+ cert_data = _load_text ('tests/data/certificate.crt' ),
133+ )
134+
135+ def test_conflicting_key_inputs (self ):
136+ with pytest .raises (
137+ exceptions .CertificateError ,
138+ match = 'Provide either key_file or key_data' ,
139+ ):
140+ Rsmime (
141+ 'tests/data/certificate.crt' ,
142+ 'tests/data/certificate.key' ,
143+ key_data = _load_text ('tests/data/certificate.key' ),
144+ )
145+
146+ def test_missing_certificate_input (self ):
147+ with pytest .raises (
148+ exceptions .CertificateError ,
149+ match = 'cert_file or cert_data' ,
150+ ):
151+ Rsmime (key_data = _load_text ('tests/data/certificate.key' ))
152+
153+ def test_missing_key_input (self ):
154+ with pytest .raises (
155+ exceptions .CertificateError ,
156+ match = 'key_file or key_data' ,
157+ ):
158+ Rsmime (cert_data = _load_text ('tests/data/certificate.crt' ))
159+
160+ def test_in_memory_material_requires_text_or_bytes (self ):
161+ with pytest .raises (
162+ exceptions .CertificateError ,
163+ match = 'cert_data must be a str or bytes-like object' ,
164+ ):
165+ Rsmime (
166+ cert_data = object (),
167+ key_data = _load_text ('tests/data/certificate.key' ),
168+ )
169+
67170 def test_verify (self ):
68171 data = b'abc'
69172 signed_data = working_client .sign (data )
0 commit comments