blob: ed2fed57e9deb1bd3e28e60b04ad06646d5a7c21 [file] [log] [blame]
David Brown1314bf32017-12-20 11:10:55 -07001# Copyright 2017 Linaro Limited
Roland Mikhel57041742023-02-03 14:43:13 +01002# Copyright 2023 Arm Limited
David Brown1314bf32017-12-20 11:10:55 -07003#
David Brown79c4fcf2021-01-26 15:04:05 -07004# SPDX-License-Identifier: Apache-2.0
5#
David Brown1314bf32017-12-20 11:10:55 -07006# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17
David Brown23f91ad2017-05-16 11:38:17 -060018"""
19Cryptographic key management for imgtool.
20"""
21
David Brown5e7c6dd2017-11-16 14:47:16 -070022from cryptography.hazmat.backends import default_backend
23from cryptography.hazmat.primitives import serialization
Fabio Utzig960b4c52020-04-02 13:07:12 -030024from cryptography.hazmat.primitives.asymmetric.rsa import (
25 RSAPrivateKey, RSAPublicKey)
26from cryptography.hazmat.primitives.asymmetric.ec import (
27 EllipticCurvePrivateKey, EllipticCurvePublicKey)
28from cryptography.hazmat.primitives.asymmetric.ed25519 import (
29 Ed25519PrivateKey, Ed25519PublicKey)
30from cryptography.hazmat.primitives.asymmetric.x25519 import (
31 X25519PrivateKey, X25519PublicKey)
David Brown23f91ad2017-05-16 11:38:17 -060032
Fabio Utzig19fd79a2019-05-08 18:20:39 -030033from .rsa import RSA, RSAPublic, RSAUsageError, RSA_KEY_SIZES
Roland Mikhel57041742023-02-03 14:43:13 +010034from .ecdsa import (ECDSA256P1, ECDSA256P1Public,
35 ECDSA384P1, ECDSA384P1Public, ECDSAUsageError)
Fabio Utzig8101d1f2019-05-09 15:03:22 -030036from .ed25519 import Ed25519, Ed25519Public, Ed25519UsageError
Fabio Utzig960b4c52020-04-02 13:07:12 -030037from .x25519 import X25519, X25519Public, X25519UsageError
38
David Brown23f91ad2017-05-16 11:38:17 -060039
David Brown5e7c6dd2017-11-16 14:47:16 -070040class PasswordRequired(Exception):
41 """Raised to indicate that the key is password protected, but a
42 password was not specified."""
43 pass
44
Fabio Utzig960b4c52020-04-02 13:07:12 -030045
David Brown5e7c6dd2017-11-16 14:47:16 -070046def load(path, passwd=None):
Roland Mikhel57041742023-02-03 14:43:13 +010047 """Try loading a key from the given path.
48 Returns None if the password wasn't specified."""
David Brown23f91ad2017-05-16 11:38:17 -060049 with open(path, 'rb') as f:
David Brown5e7c6dd2017-11-16 14:47:16 -070050 raw_pem = f.read()
David Brown23f91ad2017-05-16 11:38:17 -060051 try:
David Brown5e7c6dd2017-11-16 14:47:16 -070052 pk = serialization.load_pem_private_key(
53 raw_pem,
54 password=passwd,
55 backend=default_backend())
David Brown1d5bea12017-11-16 15:11:10 -070056 # Unfortunately, the crypto library raises unhelpful exceptions,
57 # so we have to look at the text.
58 except TypeError as e:
59 msg = str(e)
60 if "private key is encrypted" in msg:
61 return None
62 raise e
David Brown23f91ad2017-05-16 11:38:17 -060063 except ValueError:
David Brown5e7c6dd2017-11-16 14:47:16 -070064 # This seems to happen if the key is a public key, let's try
65 # loading it as a public key.
66 pk = serialization.load_pem_public_key(
67 raw_pem,
68 backend=default_backend())
69
70 if isinstance(pk, RSAPrivateKey):
Fabio Utzig19fd79a2019-05-08 18:20:39 -030071 if pk.key_size not in RSA_KEY_SIZES:
David Brown5e7c6dd2017-11-16 14:47:16 -070072 raise Exception("Unsupported RSA key size: " + pk.key_size)
Fabio Utzig19fd79a2019-05-08 18:20:39 -030073 return RSA(pk)
David Brown5e7c6dd2017-11-16 14:47:16 -070074 elif isinstance(pk, RSAPublicKey):
Fabio Utzig19fd79a2019-05-08 18:20:39 -030075 if pk.key_size not in RSA_KEY_SIZES:
David Brown5e7c6dd2017-11-16 14:47:16 -070076 raise Exception("Unsupported RSA key size: " + pk.key_size)
Fabio Utzig19fd79a2019-05-08 18:20:39 -030077 return RSAPublic(pk)
David Brownb6e0ae62017-11-21 15:13:04 -070078 elif isinstance(pk, EllipticCurvePrivateKey):
Roland Mikhel57041742023-02-03 14:43:13 +010079 if pk.curve.name not in ('secp256r1', 'secp384r1'):
David Brownb6e0ae62017-11-21 15:13:04 -070080 raise Exception("Unsupported EC curve: " + pk.curve.name)
Roland Mikhel57041742023-02-03 14:43:13 +010081 if pk.key_size not in (256, 384):
David Brownb6e0ae62017-11-21 15:13:04 -070082 raise Exception("Unsupported EC size: " + pk.key_size)
Roland Mikhel57041742023-02-03 14:43:13 +010083 if pk.curve.name == 'secp256r1':
84 return ECDSA256P1(pk)
85 elif pk.curve.name == 'secp384r1':
86 return ECDSA384P1(pk)
David Brownb6e0ae62017-11-21 15:13:04 -070087 elif isinstance(pk, EllipticCurvePublicKey):
Roland Mikhel57041742023-02-03 14:43:13 +010088 if pk.curve.name not in ('secp256r1', 'secp384r1'):
David Brownb6e0ae62017-11-21 15:13:04 -070089 raise Exception("Unsupported EC curve: " + pk.curve.name)
Roland Mikhel57041742023-02-03 14:43:13 +010090 if pk.key_size not in (256, 384):
David Brownb6e0ae62017-11-21 15:13:04 -070091 raise Exception("Unsupported EC size: " + pk.key_size)
Roland Mikhel57041742023-02-03 14:43:13 +010092 if pk.curve.name == 'secp256r1':
93 return ECDSA256P1Public(pk)
94 elif pk.curve.name == 'secp384r1':
95 return ECDSA384P1Public(pk)
Fabio Utzig8101d1f2019-05-09 15:03:22 -030096 elif isinstance(pk, Ed25519PrivateKey):
97 return Ed25519(pk)
98 elif isinstance(pk, Ed25519PublicKey):
99 return Ed25519Public(pk)
Fabio Utzig960b4c52020-04-02 13:07:12 -0300100 elif isinstance(pk, X25519PrivateKey):
101 return X25519(pk)
102 elif isinstance(pk, X25519PublicKey):
103 return X25519Public(pk)
David Brown5e7c6dd2017-11-16 14:47:16 -0700104 else:
105 raise Exception("Unknown key type: " + str(type(pk)))