blob: af6caffaa4f51ee5f70c38bebd93e3b617bda802 [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
Fabio Utzig960b4c52020-04-02 13:07:12 -030021from cryptography.hazmat.primitives.asymmetric.rsa import (
22 RSAPrivateKey, RSAPublicKey)
23from cryptography.hazmat.primitives.asymmetric.ec import (
24 EllipticCurvePrivateKey, EllipticCurvePublicKey)
25from cryptography.hazmat.primitives.asymmetric.ed25519 import (
26 Ed25519PrivateKey, Ed25519PublicKey)
27from cryptography.hazmat.primitives.asymmetric.x25519 import (
28 X25519PrivateKey, X25519PublicKey)
David Brown23f91ad2017-05-16 11:38:17 -060029
Fabio Utzig19fd79a2019-05-08 18:20:39 -030030from .rsa import RSA, RSAPublic, RSAUsageError, RSA_KEY_SIZES
David Brownb6e0ae62017-11-21 15:13:04 -070031from .ecdsa import ECDSA256P1, ECDSA256P1Public, ECDSAUsageError
Fabio Utzig8101d1f2019-05-09 15:03:22 -030032from .ed25519 import Ed25519, Ed25519Public, Ed25519UsageError
Fabio Utzig960b4c52020-04-02 13:07:12 -030033from .x25519 import X25519, X25519Public, X25519UsageError
34
David Brown23f91ad2017-05-16 11:38:17 -060035
David Brown5e7c6dd2017-11-16 14:47:16 -070036class PasswordRequired(Exception):
37 """Raised to indicate that the key is password protected, but a
38 password was not specified."""
39 pass
40
Fabio Utzig960b4c52020-04-02 13:07:12 -030041
David Brown5e7c6dd2017-11-16 14:47:16 -070042def load(path, passwd=None):
43 """Try loading a key from the given path. Returns None if the password wasn't specified."""
David Brown23f91ad2017-05-16 11:38:17 -060044 with open(path, 'rb') as f:
David Brown5e7c6dd2017-11-16 14:47:16 -070045 raw_pem = f.read()
David Brown23f91ad2017-05-16 11:38:17 -060046 try:
David Brown5e7c6dd2017-11-16 14:47:16 -070047 pk = serialization.load_pem_private_key(
48 raw_pem,
49 password=passwd,
50 backend=default_backend())
David Brown1d5bea12017-11-16 15:11:10 -070051 # Unfortunately, the crypto library raises unhelpful exceptions,
52 # so we have to look at the text.
53 except TypeError as e:
54 msg = str(e)
55 if "private key is encrypted" in msg:
56 return None
57 raise e
David Brown23f91ad2017-05-16 11:38:17 -060058 except ValueError:
David Brown5e7c6dd2017-11-16 14:47:16 -070059 # This seems to happen if the key is a public key, let's try
60 # loading it as a public key.
61 pk = serialization.load_pem_public_key(
62 raw_pem,
63 backend=default_backend())
64
65 if isinstance(pk, RSAPrivateKey):
Fabio Utzig19fd79a2019-05-08 18:20:39 -030066 if pk.key_size not in RSA_KEY_SIZES:
David Brown5e7c6dd2017-11-16 14:47:16 -070067 raise Exception("Unsupported RSA key size: " + pk.key_size)
Fabio Utzig19fd79a2019-05-08 18:20:39 -030068 return RSA(pk)
David Brown5e7c6dd2017-11-16 14:47:16 -070069 elif isinstance(pk, RSAPublicKey):
Fabio Utzig19fd79a2019-05-08 18:20:39 -030070 if pk.key_size not in RSA_KEY_SIZES:
David Brown5e7c6dd2017-11-16 14:47:16 -070071 raise Exception("Unsupported RSA key size: " + pk.key_size)
Fabio Utzig19fd79a2019-05-08 18:20:39 -030072 return RSAPublic(pk)
David Brownb6e0ae62017-11-21 15:13:04 -070073 elif isinstance(pk, EllipticCurvePrivateKey):
74 if pk.curve.name != 'secp256r1':
75 raise Exception("Unsupported EC curve: " + pk.curve.name)
76 if pk.key_size != 256:
77 raise Exception("Unsupported EC size: " + pk.key_size)
78 return ECDSA256P1(pk)
79 elif isinstance(pk, EllipticCurvePublicKey):
80 if pk.curve.name != 'secp256r1':
81 raise Exception("Unsupported EC curve: " + pk.curve.name)
82 if pk.key_size != 256:
83 raise Exception("Unsupported EC size: " + pk.key_size)
84 return ECDSA256P1Public(pk)
Fabio Utzig8101d1f2019-05-09 15:03:22 -030085 elif isinstance(pk, Ed25519PrivateKey):
86 return Ed25519(pk)
87 elif isinstance(pk, Ed25519PublicKey):
88 return Ed25519Public(pk)
Fabio Utzig960b4c52020-04-02 13:07:12 -030089 elif isinstance(pk, X25519PrivateKey):
90 return X25519(pk)
91 elif isinstance(pk, X25519PublicKey):
92 return X25519Public(pk)
David Brown5e7c6dd2017-11-16 14:47:16 -070093 else:
94 raise Exception("Unknown key type: " + str(type(pk)))