blob: dfd101dd660a803471bfaff6f19acbc402398d67 [file] [log] [blame]
David Brown1314bf32017-12-20 11:10:55 -07001# Copyright 2017 Linaro Limited
2#
David Brown79c4fcf2021-01-26 15:04:05 -07003# SPDX-License-Identifier: Apache-2.0
4#
David Brown1314bf32017-12-20 11:10:55 -07005# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
David Brown23f91ad2017-05-16 11:38:17 -060017"""
18Cryptographic key management for imgtool.
19"""
20
David Brown5e7c6dd2017-11-16 14:47:16 -070021from cryptography.hazmat.backends import default_backend
22from cryptography.hazmat.primitives import serialization
Fabio Utzig960b4c52020-04-02 13:07:12 -030023from cryptography.hazmat.primitives.asymmetric.rsa import (
24 RSAPrivateKey, RSAPublicKey)
25from cryptography.hazmat.primitives.asymmetric.ec import (
26 EllipticCurvePrivateKey, EllipticCurvePublicKey)
27from cryptography.hazmat.primitives.asymmetric.ed25519 import (
28 Ed25519PrivateKey, Ed25519PublicKey)
29from cryptography.hazmat.primitives.asymmetric.x25519 import (
30 X25519PrivateKey, X25519PublicKey)
David Brown23f91ad2017-05-16 11:38:17 -060031
Fabio Utzig19fd79a2019-05-08 18:20:39 -030032from .rsa import RSA, RSAPublic, RSAUsageError, RSA_KEY_SIZES
David Brownb6e0ae62017-11-21 15:13:04 -070033from .ecdsa import ECDSA256P1, ECDSA256P1Public, ECDSAUsageError
Fabio Utzig8101d1f2019-05-09 15:03:22 -030034from .ed25519 import Ed25519, Ed25519Public, Ed25519UsageError
Fabio Utzig960b4c52020-04-02 13:07:12 -030035from .x25519 import X25519, X25519Public, X25519UsageError
36
David Brown23f91ad2017-05-16 11:38:17 -060037
David Brown5e7c6dd2017-11-16 14:47:16 -070038class PasswordRequired(Exception):
39 """Raised to indicate that the key is password protected, but a
40 password was not specified."""
41 pass
42
Fabio Utzig960b4c52020-04-02 13:07:12 -030043
David Brown5e7c6dd2017-11-16 14:47:16 -070044def load(path, passwd=None):
45 """Try loading a key from the given path. Returns None if the password wasn't specified."""
David Brown23f91ad2017-05-16 11:38:17 -060046 with open(path, 'rb') as f:
David Brown5e7c6dd2017-11-16 14:47:16 -070047 raw_pem = f.read()
David Brown23f91ad2017-05-16 11:38:17 -060048 try:
David Brown5e7c6dd2017-11-16 14:47:16 -070049 pk = serialization.load_pem_private_key(
50 raw_pem,
51 password=passwd,
52 backend=default_backend())
David Brown1d5bea12017-11-16 15:11:10 -070053 # Unfortunately, the crypto library raises unhelpful exceptions,
54 # so we have to look at the text.
55 except TypeError as e:
56 msg = str(e)
57 if "private key is encrypted" in msg:
58 return None
59 raise e
David Brown23f91ad2017-05-16 11:38:17 -060060 except ValueError:
David Brown5e7c6dd2017-11-16 14:47:16 -070061 # This seems to happen if the key is a public key, let's try
62 # loading it as a public key.
63 pk = serialization.load_pem_public_key(
64 raw_pem,
65 backend=default_backend())
66
67 if isinstance(pk, RSAPrivateKey):
Fabio Utzig19fd79a2019-05-08 18:20:39 -030068 if pk.key_size not in RSA_KEY_SIZES:
David Brown5e7c6dd2017-11-16 14:47:16 -070069 raise Exception("Unsupported RSA key size: " + pk.key_size)
Fabio Utzig19fd79a2019-05-08 18:20:39 -030070 return RSA(pk)
David Brown5e7c6dd2017-11-16 14:47:16 -070071 elif isinstance(pk, RSAPublicKey):
Fabio Utzig19fd79a2019-05-08 18:20:39 -030072 if pk.key_size not in RSA_KEY_SIZES:
David Brown5e7c6dd2017-11-16 14:47:16 -070073 raise Exception("Unsupported RSA key size: " + pk.key_size)
Fabio Utzig19fd79a2019-05-08 18:20:39 -030074 return RSAPublic(pk)
David Brownb6e0ae62017-11-21 15:13:04 -070075 elif isinstance(pk, EllipticCurvePrivateKey):
76 if pk.curve.name != 'secp256r1':
77 raise Exception("Unsupported EC curve: " + pk.curve.name)
78 if pk.key_size != 256:
79 raise Exception("Unsupported EC size: " + pk.key_size)
80 return ECDSA256P1(pk)
81 elif isinstance(pk, EllipticCurvePublicKey):
82 if pk.curve.name != 'secp256r1':
83 raise Exception("Unsupported EC curve: " + pk.curve.name)
84 if pk.key_size != 256:
85 raise Exception("Unsupported EC size: " + pk.key_size)
86 return ECDSA256P1Public(pk)
Fabio Utzig8101d1f2019-05-09 15:03:22 -030087 elif isinstance(pk, Ed25519PrivateKey):
88 return Ed25519(pk)
89 elif isinstance(pk, Ed25519PublicKey):
90 return Ed25519Public(pk)
Fabio Utzig960b4c52020-04-02 13:07:12 -030091 elif isinstance(pk, X25519PrivateKey):
92 return X25519(pk)
93 elif isinstance(pk, X25519PublicKey):
94 return X25519Public(pk)
David Brown5e7c6dd2017-11-16 14:47:16 -070095 else:
96 raise Exception("Unknown key type: " + str(type(pk)))