blob: da5b083193b590016eb9132fe4003b2b45385339 [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
David Brown5e7c6dd2017-11-16 14:47:16 -070024from .rsa import RSA2048, RSA2048Public, RSAUsageError
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):
56 if pk.key_size != 2048:
57 raise Exception("Unsupported RSA key size: " + pk.key_size)
58 return RSA2048(pk)
59 elif isinstance(pk, RSAPublicKey):
60 if pk.key_size != 2048:
61 raise Exception("Unsupported RSA key size: " + pk.key_size)
62 return RSA2048Public(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)))