blob: b92f871aa36b8bb5b95af2e1948874c63243b6cc [file] [log] [blame]
David Brown1314bf32017-12-20 11:10:55 -07001# Copyright 2017 Linaro Limited
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
David Brown23f91ad2017-05-16 11:38:17 -060015"""
16Cryptographic key management for imgtool.
17"""
18
David Brown5e7c6dd2017-11-16 14:47:16 -070019from cryptography.hazmat.backends import default_backend
20from cryptography.hazmat.primitives import serialization
21from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey
David Brownb6e0ae62017-11-21 15:13:04 -070022from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey, EllipticCurvePublicKey
David Brown23f91ad2017-05-16 11:38:17 -060023
Fabio Utzig19fd79a2019-05-08 18:20:39 -030024from .rsa import RSA, RSAPublic, RSAUsageError, RSA_KEY_SIZES
David Brownb6e0ae62017-11-21 15:13:04 -070025from .ecdsa import ECDSA256P1, ECDSA256P1Public, ECDSAUsageError
David Brown23f91ad2017-05-16 11:38:17 -060026
David Brown5e7c6dd2017-11-16 14:47:16 -070027class PasswordRequired(Exception):
28 """Raised to indicate that the key is password protected, but a
29 password was not specified."""
30 pass
31
32def load(path, passwd=None):
33 """Try loading a key from the given path. Returns None if the password wasn't specified."""
David Brown23f91ad2017-05-16 11:38:17 -060034 with open(path, 'rb') as f:
David Brown5e7c6dd2017-11-16 14:47:16 -070035 raw_pem = f.read()
David Brown23f91ad2017-05-16 11:38:17 -060036 try:
David Brown5e7c6dd2017-11-16 14:47:16 -070037 pk = serialization.load_pem_private_key(
38 raw_pem,
39 password=passwd,
40 backend=default_backend())
David Brown1d5bea12017-11-16 15:11:10 -070041 # Unfortunately, the crypto library raises unhelpful exceptions,
42 # so we have to look at the text.
43 except TypeError as e:
44 msg = str(e)
45 if "private key is encrypted" in msg:
46 return None
47 raise e
David Brown23f91ad2017-05-16 11:38:17 -060048 except ValueError:
David Brown5e7c6dd2017-11-16 14:47:16 -070049 # This seems to happen if the key is a public key, let's try
50 # loading it as a public key.
51 pk = serialization.load_pem_public_key(
52 raw_pem,
53 backend=default_backend())
54
55 if isinstance(pk, RSAPrivateKey):
Fabio Utzig19fd79a2019-05-08 18:20:39 -030056 if pk.key_size not in RSA_KEY_SIZES:
David Brown5e7c6dd2017-11-16 14:47:16 -070057 raise Exception("Unsupported RSA key size: " + pk.key_size)
Fabio Utzig19fd79a2019-05-08 18:20:39 -030058 return RSA(pk)
David Brown5e7c6dd2017-11-16 14:47:16 -070059 elif isinstance(pk, RSAPublicKey):
Fabio Utzig19fd79a2019-05-08 18:20:39 -030060 if pk.key_size not in RSA_KEY_SIZES:
David Brown5e7c6dd2017-11-16 14:47:16 -070061 raise Exception("Unsupported RSA key size: " + pk.key_size)
Fabio Utzig19fd79a2019-05-08 18:20:39 -030062 return RSAPublic(pk)
David Brownb6e0ae62017-11-21 15:13:04 -070063 elif isinstance(pk, EllipticCurvePrivateKey):
64 if pk.curve.name != 'secp256r1':
65 raise Exception("Unsupported EC curve: " + pk.curve.name)
66 if pk.key_size != 256:
67 raise Exception("Unsupported EC size: " + pk.key_size)
68 return ECDSA256P1(pk)
69 elif isinstance(pk, EllipticCurvePublicKey):
70 if pk.curve.name != 'secp256r1':
71 raise Exception("Unsupported EC curve: " + pk.curve.name)
72 if pk.key_size != 256:
73 raise Exception("Unsupported EC size: " + pk.key_size)
74 return ECDSA256P1Public(pk)
David Brown5e7c6dd2017-11-16 14:47:16 -070075 else:
76 raise Exception("Unknown key type: " + str(type(pk)))