blob: b01635d5c78ac0343eee5587b8fdf9f700a9faba [file] [log] [blame]
David Brown5e7c6dd2017-11-16 14:47:16 -07001"""
2Tests for RSA keys
3"""
4
5import io
6import os
7import sys
8import tempfile
9import unittest
10
11from cryptography.exceptions import InvalidSignature
12from cryptography.hazmat.primitives.asymmetric.padding import PSS, MGF1
13from cryptography.hazmat.primitives.hashes import SHA256
14
15# Setup sys path so 'imgtool' is in it.
Fabio Utzig19fd79a2019-05-08 18:20:39 -030016sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__),
17 '../..')))
David Brown5e7c6dd2017-11-16 14:47:16 -070018
Fabio Utzig19fd79a2019-05-08 18:20:39 -030019from imgtool.keys import load, RSA, RSAUsageError
20from imgtool.keys.rsa import RSA_KEY_SIZES
21
David Brown5e7c6dd2017-11-16 14:47:16 -070022
23class KeyGeneration(unittest.TestCase):
24
25 def setUp(self):
26 self.test_dir = tempfile.TemporaryDirectory()
27
28 def tname(self, base):
29 return os.path.join(self.test_dir.name, base)
30
31 def tearDown(self):
32 self.test_dir.cleanup()
33
34 def test_keygen(self):
Fabio Utzig19fd79a2019-05-08 18:20:39 -030035 # Try generating a RSA key with non-supported size
36 with self.assertRaises(RSAUsageError):
37 RSA.generate(key_size=1024)
David Brown5e7c6dd2017-11-16 14:47:16 -070038
Fabio Utzig19fd79a2019-05-08 18:20:39 -030039 for key_size in RSA_KEY_SIZES:
40 name1 = self.tname("keygen.pem")
41 k = RSA.generate(key_size=key_size)
42 k.export_private(name1, b'secret')
David Brown5e7c6dd2017-11-16 14:47:16 -070043
Fabio Utzig19fd79a2019-05-08 18:20:39 -030044 # Try loading the key without a password.
45 self.assertIsNone(load(name1))
David Brown5e7c6dd2017-11-16 14:47:16 -070046
Fabio Utzig19fd79a2019-05-08 18:20:39 -030047 k2 = load(name1, b'secret')
David Brown5e7c6dd2017-11-16 14:47:16 -070048
Fabio Utzig19fd79a2019-05-08 18:20:39 -030049 pubname = self.tname('keygen-pub.pem')
50 k2.export_public(pubname)
51 pk2 = load(pubname)
52
53 # We should be able to export the public key from the loaded
54 # public key, but not the private key.
55 pk2.export_public(self.tname('keygen-pub2.pem'))
56 self.assertRaises(RSAUsageError, pk2.export_private,
57 self.tname('keygen-priv2.pem'))
David Brown5e7c6dd2017-11-16 14:47:16 -070058
59 def test_emit(self):
60 """Basic sanity check on the code emitters."""
Fabio Utzig19fd79a2019-05-08 18:20:39 -030061 for key_size in RSA_KEY_SIZES:
62 k = RSA.generate(key_size=key_size)
David Brown5e7c6dd2017-11-16 14:47:16 -070063
Fabio Utzig19fd79a2019-05-08 18:20:39 -030064 ccode = io.StringIO()
65 k.emit_c(ccode)
66 self.assertIn("rsa_pub_key", ccode.getvalue())
67 self.assertIn("rsa_pub_key_len", ccode.getvalue())
David Brown5e7c6dd2017-11-16 14:47:16 -070068
Fabio Utzig19fd79a2019-05-08 18:20:39 -030069 rustcode = io.StringIO()
70 k.emit_rust(rustcode)
71 self.assertIn("RSA_PUB_KEY", rustcode.getvalue())
David Brown5e7c6dd2017-11-16 14:47:16 -070072
73 def test_emit_pub(self):
74 """Basic sanity check on the code emitters, from public key."""
75 pubname = self.tname("public.pem")
Fabio Utzig19fd79a2019-05-08 18:20:39 -030076 for key_size in RSA_KEY_SIZES:
77 k = RSA.generate(key_size=key_size)
78 k.export_public(pubname)
David Brown5e7c6dd2017-11-16 14:47:16 -070079
Fabio Utzig19fd79a2019-05-08 18:20:39 -030080 k2 = load(pubname)
David Brown5e7c6dd2017-11-16 14:47:16 -070081
Fabio Utzig19fd79a2019-05-08 18:20:39 -030082 ccode = io.StringIO()
83 k2.emit_c(ccode)
84 self.assertIn("rsa_pub_key", ccode.getvalue())
85 self.assertIn("rsa_pub_key_len", ccode.getvalue())
David Brown5e7c6dd2017-11-16 14:47:16 -070086
Fabio Utzig19fd79a2019-05-08 18:20:39 -030087 rustcode = io.StringIO()
88 k2.emit_rust(rustcode)
89 self.assertIn("RSA_PUB_KEY", rustcode.getvalue())
David Brown5e7c6dd2017-11-16 14:47:16 -070090
91 def test_sig(self):
Fabio Utzig19fd79a2019-05-08 18:20:39 -030092 for key_size in RSA_KEY_SIZES:
93 k = RSA.generate(key_size=key_size)
94 buf = b'This is the message'
95 sig = k.sign(buf)
David Brown5e7c6dd2017-11-16 14:47:16 -070096
Fabio Utzig19fd79a2019-05-08 18:20:39 -030097 # The code doesn't have any verification, so verify this
98 # manually.
99 k.key.public_key().verify(
David Brown5e7c6dd2017-11-16 14:47:16 -0700100 signature=sig,
101 data=buf,
David Brown20462a72017-11-21 14:28:51 -0700102 padding=PSS(mgf=MGF1(SHA256()), salt_length=32),
David Brown5e7c6dd2017-11-16 14:47:16 -0700103 algorithm=SHA256())
104
Fabio Utzig19fd79a2019-05-08 18:20:39 -0300105 # Modify the message to make sure the signature fails.
106 self.assertRaises(InvalidSignature,
107 k.key.public_key().verify,
108 signature=sig,
109 data=b'This is thE message',
110 padding=PSS(mgf=MGF1(SHA256()), salt_length=32),
111 algorithm=SHA256())
112
David Brown5e7c6dd2017-11-16 14:47:16 -0700113
114if __name__ == '__main__':
115 unittest.main()