Skip to content

Commit 255290c

Browse files
committed
Improve PinkSign test coverage and validation
1 parent 789eeba commit 255290c

File tree

1 file changed

+135
-33
lines changed

1 file changed

+135
-33
lines changed

pypinksign/test_pinkSign.py

Lines changed: 135 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import base64
22
import datetime
33
import os
4+
import struct
45
import tempfile
56
import unittest
6-
from unittest import TestCase
7+
from unittest import TestCase, mock
8+
9+
from cryptography.exceptions import UnsupportedAlgorithm
710

811
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers, RSAPrivateNumbers
912
from pyasn1.codec.der import decoder as der_decoder
@@ -254,30 +257,36 @@
254257
'seed_block_key': bytes.fromhex('01 02 02 01 03 05 05 03 09 08 08 09 11 33 33 11'.replace(' ', '')),
255258
}
256259

260+
CERT_PUBKEY_DER = base64.b64decode(TEST_CERT['signCert'])
261+
CERT_PRIKEY_DER = base64.b64decode(TEST_CERT['signPri'])
262+
CERT_P12_DATA = base64.b64decode(TEST_CERT['pfx'])
263+
CERT_PASSWORD = TEST_CERT['signPw']
264+
257265

258266
class TestPinkSign(TestCase):
259267
def setUp(self) -> None:
260268
"""
261269
Load test certificate
262270
:return: None
263271
"""
264-
self.c = PinkSign(pubkey_data=base64.b64decode(TEST_CERT['signCert']),
265-
prikey_data=base64.b64decode(TEST_CERT['signPri']),
266-
prikey_password=TEST_CERT['signPw']
267-
)
268-
pass
272+
self.c = PinkSign(
273+
pubkey_data=CERT_PUBKEY_DER,
274+
prikey_data=CERT_PRIKEY_DER,
275+
prikey_password=CERT_PASSWORD,
276+
)
269277

270278
def test_load_pubkey(self):
271279
cert = PinkSign()
272-
cert.load_pubkey(pubkey_data=base64.b64decode(TEST_CERT['signCert']))
280+
cert.load_pubkey(pubkey_data=CERT_PUBKEY_DER)
273281
expected = RSAPublicNumbers(e=65537, n=TEST_CERT['n'])
274282
self.assertEqual(expected, cert.pubkey.public_numbers())
275283

276284
def test_load_prikey(self):
277-
cert = PinkSign(pubkey_data=base64.b64decode(TEST_CERT['signCert']),
278-
prikey_data=base64.b64decode(TEST_CERT['signPri']),
279-
prikey_password=TEST_CERT['signPw']
280-
)
285+
cert = PinkSign(
286+
pubkey_data=CERT_PUBKEY_DER,
287+
prikey_data=CERT_PRIKEY_DER,
288+
prikey_password=CERT_PASSWORD,
289+
)
281290
cert.load_prikey()
282291
expected_public_numbers = RSAPublicNumbers(e=65537, n=TEST_CERT['n'])
283292
expected = RSAPrivateNumbers(p=TEST_CERT['p'], q=TEST_CERT['q'], d=TEST_CERT['d'], dmp1=TEST_CERT['dmp1'],
@@ -286,8 +295,7 @@ def test_load_prikey(self):
286295
self.assertEqual(expected, cert.prikey.private_numbers())
287296

288297
def test_load_p12(self):
289-
cert = PinkSign(p12_data=base64.b64decode(TEST_CERT['pfx']),
290-
prikey_password=TEST_CERT['signPw'])
298+
cert = PinkSign(p12_data=CERT_P12_DATA, prikey_password=CERT_PASSWORD)
291299
expected_public_numbers = RSAPublicNumbers(e=65537, n=TEST_CERT['n'])
292300
self.assertEqual(cert.pubkey.public_numbers(), expected_public_numbers)
293301
expected = RSAPrivateNumbers(p=TEST_CERT['p'], q=TEST_CERT['q'], d=TEST_CERT['d'], dmp1=TEST_CERT['dmp1'],
@@ -296,13 +304,13 @@ def test_load_p12(self):
296304
self.assertEqual(expected, cert.prikey.private_numbers())
297305

298306
def test_load_12_file(self):
299-
f = tempfile.NamedTemporaryFile(delete=False)
300-
f.write(base64.b64decode(TEST_CERT['pfx']))
301-
f.close()
302-
cert = PinkSign(p12_path=f.name, prikey_password=TEST_CERT['signPw'])
307+
with tempfile.NamedTemporaryFile(delete=False) as f:
308+
f.write(CERT_P12_DATA)
309+
temp_path = f.name
310+
self.addCleanup(lambda: os.path.exists(temp_path) and os.unlink(temp_path))
311+
cert = PinkSign(p12_path=temp_path, prikey_password=CERT_PASSWORD)
303312
signed = cert.sign(msg=b'1')
304313
cert.verify(signature=signed, msg=b'1')
305-
os.unlink(f.name)
306314
expected_public_numbers = RSAPublicNumbers(e=65537, n=TEST_CERT['n'])
307315
self.assertEqual(cert.pubkey.public_numbers(), expected_public_numbers)
308316
expected = RSAPrivateNumbers(p=TEST_CERT['p'], q=TEST_CERT['q'], d=TEST_CERT['d'], dmp1=TEST_CERT['dmp1'],
@@ -441,40 +449,49 @@ def test_seed_cbc_128_decrypt_pure(self):
441449
def test_seed_generator(self):
442450
self.assertEqual(16, len(seed_generator(16)))
443451
self.assertIsInstance(seed_generator(16), bytes)
452+
self.assertTrue(all(b != 0 for b in seed_generator(64)))
453+
self.assertEqual(b'', seed_generator(0))
444454

445455
def test_separate_p12_into_npki(self):
446456
expected = tuple((base64.b64decode(TEST_CERT['signCert']), base64.b64decode(TEST_CERT['plainSignPri'])))
447-
self.assertEqual(expected, separate_p12_into_npki(base64.b64decode(TEST_CERT['pfx']), TEST_CERT['signPw']))
457+
self.assertEqual(expected, separate_p12_into_npki(CERT_P12_DATA, CERT_PASSWORD))
448458

449459
def test_inject_rand_in_plain_prikey(self):
450460
expected = TEST_CERT['plainSignPriFullB64']
451461
self.assertEqual(expected, inject_rand_in_plain_prikey(TEST_CERT['plainSignPri'], TEST_CERT['r']))
452462

453463
def test_encrypt_decrypted_prikey(self):
454464
expected = TEST_CERT['signPri']
455-
self.assertEqual(expected, encrypt_decrypted_prikey(TEST_CERT['plainSignPriFullB64'], TEST_CERT['signPw'],
465+
self.assertEqual(expected, encrypt_decrypted_prikey(TEST_CERT['plainSignPriFullB64'], CERT_PASSWORD,
456466
TEST_CERT['signPriSalt']))
457467

458468
def test_set_key(self):
459469
expected = TEST_DATA['seed_key']
460-
self.assertEqual(expected, set_key(bytes(16)), expected)
470+
self.assertEqual(expected, set_key(bytes(16)))
461471

462472
def test_process_block(self):
463-
expected = bytearray(TEST_DATA['seed_block_cipher'])
464-
self.assertEqual(expected, process_block(True, TEST_DATA['seed_block_key'], TEST_DATA['seed_block_plain']),
465-
expected)
466-
467-
expected = bytearray(TEST_DATA['seed_block_plain'])
468-
self.assertEqual(expected, process_block(False, TEST_DATA['seed_block_key'], TEST_DATA['seed_block_cipher']),
469-
expected)
473+
expected_cipher = bytearray(TEST_DATA['seed_block_cipher'])
474+
self.assertEqual(
475+
expected_cipher,
476+
process_block(True, TEST_DATA['seed_block_key'], TEST_DATA['seed_block_plain']),
477+
)
478+
479+
expected_plain = bytearray(TEST_DATA['seed_block_plain'])
480+
self.assertEqual(
481+
expected_plain,
482+
process_block(False, TEST_DATA['seed_block_key'], TEST_DATA['seed_block_cipher']),
483+
)
470484

471485
def test_process_block_openssl(self):
472486
expected = TEST_DATA['seed_block_cipher']
473-
self.assertEqual(expected,
474-
seed_cbc_128_encrypt_openssl(
475-
TEST_DATA['seed_block_key'],
476-
TEST_DATA['seed_block_plain'],
477-
bytes(16))[:16], expected)
487+
self.assertEqual(
488+
expected,
489+
seed_cbc_128_encrypt_openssl(
490+
TEST_DATA['seed_block_key'],
491+
TEST_DATA['seed_block_plain'],
492+
bytes(16),
493+
)[:16],
494+
)
478495

479496
def test_pure_vs_openssl(self):
480497
for i in range(100):
@@ -488,5 +505,90 @@ def test_pure_vs_openssl(self):
488505
self.assertEqual(dec, random_bytes)
489506

490507

508+
class TestPinkSignValidation(TestCase):
509+
def test_load_pubkey_requires_source(self):
510+
cert = PinkSign()
511+
with self.assertRaises(ValueError):
512+
cert.load_pubkey()
513+
514+
def test_load_prikey_requires_pubkey(self):
515+
cert = PinkSign()
516+
with self.assertRaises(ValueError):
517+
cert.load_prikey(prikey_path='dummy', prikey_password=CERT_PASSWORD)
518+
519+
def test_load_prikey_requires_password(self):
520+
cert = PinkSign(pubkey_data=CERT_PUBKEY_DER, prikey_data=CERT_PRIKEY_DER)
521+
with self.assertRaises(ValueError):
522+
cert.load_prikey()
523+
524+
def test_cert_type_oid_requires_pubkey(self):
525+
cert = PinkSign()
526+
with self.assertRaises(ValueError):
527+
cert.cert_type_oid()
528+
529+
def test_valid_date_requires_pubkey(self):
530+
cert = PinkSign()
531+
with self.assertRaises(ValueError):
532+
cert.valid_date()
533+
534+
def test_serialnum_requires_pubkey(self):
535+
cert = PinkSign()
536+
with self.assertRaises(ValueError):
537+
cert.serialnum()
538+
539+
def test_sign_requires_private_key(self):
540+
cert = PinkSign(pubkey_data=CERT_PUBKEY_DER)
541+
with self.assertRaises(ValueError):
542+
cert.sign(b'data')
543+
544+
def test_decrypt_requires_private_key(self):
545+
cert = PinkSign()
546+
with self.assertRaises(ValueError):
547+
cert.decrypt(b'data')
548+
549+
def test_verify_requires_public_key(self):
550+
cert = PinkSign()
551+
with self.assertRaises(ValueError):
552+
cert.verify(b'sig', b'msg')
553+
554+
def test_encrypt_requires_public_key(self):
555+
cert = PinkSign()
556+
with self.assertRaises(ValueError):
557+
cert.encrypt(b'msg')
558+
559+
560+
class TestSeedInternals(TestCase):
561+
def test_process_block_requires_key(self):
562+
with self.assertRaises(ValueError):
563+
process_block(True, None, TEST_DATA['seed_block_plain'])
564+
565+
def test_process_block_requires_block_size(self):
566+
with self.assertRaises(ValueError):
567+
process_block(True, TEST_DATA['seed_block_key'], b'\x00')
568+
569+
def test_set_key_requires_full_block(self):
570+
with self.assertRaises(struct.error):
571+
set_key(b'\x00' * 15)
572+
573+
574+
class TestSeedFallbacks(TestCase):
575+
def test_seed_encrypt_falls_back_to_pure(self):
576+
expected = seed_cbc_128_encrypt_pure(TEST_DATA['key'], TEST_DATA['plaintext'], TEST_DATA['iv'])
577+
with mock.patch('pypinksign.pypinksign.seed_cbc_128_encrypt_openssl', side_effect=UnsupportedAlgorithm("seed")):
578+
self.assertEqual(
579+
expected,
580+
seed_cbc_128_encrypt(TEST_DATA['key'], TEST_DATA['plaintext'], TEST_DATA['iv']),
581+
)
582+
583+
def test_seed_decrypt_falls_back_to_pure(self):
584+
ciphertext = seed_cbc_128_encrypt_pure(TEST_DATA['key'], TEST_DATA['plaintext'], TEST_DATA['iv'])
585+
expected = seed_cbc_128_decrypt_pure(TEST_DATA['key'], ciphertext, TEST_DATA['iv'])
586+
with mock.patch('pypinksign.pypinksign.seed_cbc_128_decrypt_openssl', side_effect=UnsupportedAlgorithm("seed")):
587+
self.assertEqual(
588+
expected,
589+
seed_cbc_128_decrypt(TEST_DATA['key'], ciphertext, TEST_DATA['iv']),
590+
)
591+
592+
491593
if __name__ == '__main__':
492594
unittest.main()

0 commit comments

Comments
 (0)