blob: 4b2106a0fd07c6e0a490af3032cfd4df167dbea4 [file] [log] [blame]
David Brown5e7c6dd2017-11-16 14:47:16 -07001"""
2Tests for RSA keys
3"""
4
David Brown79c4fcf2021-01-26 15:04:05 -07005# SPDX-License-Identifier: Apache-2.0
6
David Brown5e7c6dd2017-11-16 14:47:16 -07007import io
8import os
9import sys
10import tempfile
11import unittest
12
13from cryptography.exceptions import InvalidSignature
14from cryptography.hazmat.primitives.asymmetric.padding import PSS, MGF1
15from cryptography.hazmat.primitives.hashes import SHA256
16
17# Setup sys path so 'imgtool' is in it.
Fabio Utzig19fd79a2019-05-08 18:20:39 -030018sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__),
19 '../..')))
David Brown5e7c6dd2017-11-16 14:47:16 -070020
Fabio Utzig19fd79a2019-05-08 18:20:39 -030021from imgtool.keys import load, RSA, RSAUsageError
22from imgtool.keys.rsa import RSA_KEY_SIZES
23
David Brown5e7c6dd2017-11-16 14:47:16 -070024
25class KeyGeneration(unittest.TestCase):
26
27 def setUp(self):
28 self.test_dir = tempfile.TemporaryDirectory()
29
30 def tname(self, base):
31 return os.path.join(self.test_dir.name, base)
32
33 def tearDown(self):
34 self.test_dir.cleanup()
35
36 def test_keygen(self):
Fabio Utzig19fd79a2019-05-08 18:20:39 -030037 # Try generating a RSA key with non-supported size
38 with self.assertRaises(RSAUsageError):
39 RSA.generate(key_size=1024)
David Brown5e7c6dd2017-11-16 14:47:16 -070040
Fabio Utzig19fd79a2019-05-08 18:20:39 -030041 for key_size in RSA_KEY_SIZES:
42 name1 = self.tname("keygen.pem")
43 k = RSA.generate(key_size=key_size)
44 k.export_private(name1, b'secret')
David Brown5e7c6dd2017-11-16 14:47:16 -070045
Fabio Utzig19fd79a2019-05-08 18:20:39 -030046 # Try loading the key without a password.
47 self.assertIsNone(load(name1))
David Brown5e7c6dd2017-11-16 14:47:16 -070048
Fabio Utzig19fd79a2019-05-08 18:20:39 -030049 k2 = load(name1, b'secret')
David Brown5e7c6dd2017-11-16 14:47:16 -070050
Fabio Utzig19fd79a2019-05-08 18:20:39 -030051 pubname = self.tname('keygen-pub.pem')
52 k2.export_public(pubname)
53 pk2 = load(pubname)
54
55 # We should be able to export the public key from the loaded
56 # public key, but not the private key.
57 pk2.export_public(self.tname('keygen-pub2.pem'))
58 self.assertRaises(RSAUsageError, pk2.export_private,
59 self.tname('keygen-priv2.pem'))
David Brown5e7c6dd2017-11-16 14:47:16 -070060
61 def test_emit(self):
62 """Basic sanity check on the code emitters."""
Fabio Utzig19fd79a2019-05-08 18:20:39 -030063 for key_size in RSA_KEY_SIZES:
64 k = RSA.generate(key_size=key_size)
David Brown5e7c6dd2017-11-16 14:47:16 -070065
Fabio Utzig19fd79a2019-05-08 18:20:39 -030066 ccode = io.StringIO()
Fabio Utzig9560d772020-04-02 13:44:30 -030067 k.emit_c_public(ccode)
Fabio Utzig19fd79a2019-05-08 18:20:39 -030068 self.assertIn("rsa_pub_key", ccode.getvalue())
69 self.assertIn("rsa_pub_key_len", ccode.getvalue())
David Brown5e7c6dd2017-11-16 14:47:16 -070070
Fabio Utzig19fd79a2019-05-08 18:20:39 -030071 rustcode = io.StringIO()
Fabio Utzig9560d772020-04-02 13:44:30 -030072 k.emit_rust_public(rustcode)
Fabio Utzig19fd79a2019-05-08 18:20:39 -030073 self.assertIn("RSA_PUB_KEY", rustcode.getvalue())
David Brown5e7c6dd2017-11-16 14:47:16 -070074
75 def test_emit_pub(self):
76 """Basic sanity check on the code emitters, from public key."""
77 pubname = self.tname("public.pem")
Fabio Utzig19fd79a2019-05-08 18:20:39 -030078 for key_size in RSA_KEY_SIZES:
79 k = RSA.generate(key_size=key_size)
80 k.export_public(pubname)
David Brown5e7c6dd2017-11-16 14:47:16 -070081
Fabio Utzig19fd79a2019-05-08 18:20:39 -030082 k2 = load(pubname)
David Brown5e7c6dd2017-11-16 14:47:16 -070083
Fabio Utzig19fd79a2019-05-08 18:20:39 -030084 ccode = io.StringIO()
Fabio Utzig9560d772020-04-02 13:44:30 -030085 k2.emit_c_public(ccode)
Fabio Utzig19fd79a2019-05-08 18:20:39 -030086 self.assertIn("rsa_pub_key", ccode.getvalue())
87 self.assertIn("rsa_pub_key_len", ccode.getvalue())
David Brown5e7c6dd2017-11-16 14:47:16 -070088
Fabio Utzig19fd79a2019-05-08 18:20:39 -030089 rustcode = io.StringIO()
Fabio Utzig9560d772020-04-02 13:44:30 -030090 k2.emit_rust_public(rustcode)
Fabio Utzig19fd79a2019-05-08 18:20:39 -030091 self.assertIn("RSA_PUB_KEY", rustcode.getvalue())
David Brown5e7c6dd2017-11-16 14:47:16 -070092
93 def test_sig(self):
Fabio Utzig19fd79a2019-05-08 18:20:39 -030094 for key_size in RSA_KEY_SIZES:
95 k = RSA.generate(key_size=key_size)
96 buf = b'This is the message'
97 sig = k.sign(buf)
David Brown5e7c6dd2017-11-16 14:47:16 -070098
Fabio Utzig19fd79a2019-05-08 18:20:39 -030099 # The code doesn't have any verification, so verify this
100 # manually.
101 k.key.public_key().verify(
David Brown5e7c6dd2017-11-16 14:47:16 -0700102 signature=sig,
103 data=buf,
David Brown20462a72017-11-21 14:28:51 -0700104 padding=PSS(mgf=MGF1(SHA256()), salt_length=32),
David Brown5e7c6dd2017-11-16 14:47:16 -0700105 algorithm=SHA256())
106
Fabio Utzig19fd79a2019-05-08 18:20:39 -0300107 # Modify the message to make sure the signature fails.
108 self.assertRaises(InvalidSignature,
109 k.key.public_key().verify,
110 signature=sig,
111 data=b'This is thE message',
112 padding=PSS(mgf=MGF1(SHA256()), salt_length=32),
113 algorithm=SHA256())
114
David Brown5e7c6dd2017-11-16 14:47:16 -0700115
116if __name__ == '__main__':
117 unittest.main()