mcuboot/scripts/imgtool/keys/__init__.py

95 lines
3.6 KiB
Python

# Copyright 2017 Linaro Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Cryptographic key management for imgtool.
"""
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.rsa import (
RSAPrivateKey, RSAPublicKey)
from cryptography.hazmat.primitives.asymmetric.ec import (
EllipticCurvePrivateKey, EllipticCurvePublicKey)
from cryptography.hazmat.primitives.asymmetric.ed25519 import (
Ed25519PrivateKey, Ed25519PublicKey)
from cryptography.hazmat.primitives.asymmetric.x25519 import (
X25519PrivateKey, X25519PublicKey)
from .rsa import RSA, RSAPublic, RSAUsageError, RSA_KEY_SIZES
from .ecdsa import ECDSA256P1, ECDSA256P1Public, ECDSAUsageError
from .ed25519 import Ed25519, Ed25519Public, Ed25519UsageError
from .x25519 import X25519, X25519Public, X25519UsageError
class PasswordRequired(Exception):
"""Raised to indicate that the key is password protected, but a
password was not specified."""
pass
def load(path, passwd=None):
"""Try loading a key from the given path. Returns None if the password wasn't specified."""
with open(path, 'rb') as f:
raw_pem = f.read()
try:
pk = serialization.load_pem_private_key(
raw_pem,
password=passwd,
backend=default_backend())
# Unfortunately, the crypto library raises unhelpful exceptions,
# so we have to look at the text.
except TypeError as e:
msg = str(e)
if "private key is encrypted" in msg:
return None
raise e
except ValueError:
# This seems to happen if the key is a public key, let's try
# loading it as a public key.
pk = serialization.load_pem_public_key(
raw_pem,
backend=default_backend())
if isinstance(pk, RSAPrivateKey):
if pk.key_size not in RSA_KEY_SIZES:
raise Exception("Unsupported RSA key size: " + pk.key_size)
return RSA(pk)
elif isinstance(pk, RSAPublicKey):
if pk.key_size not in RSA_KEY_SIZES:
raise Exception("Unsupported RSA key size: " + pk.key_size)
return RSAPublic(pk)
elif isinstance(pk, EllipticCurvePrivateKey):
if pk.curve.name != 'secp256r1':
raise Exception("Unsupported EC curve: " + pk.curve.name)
if pk.key_size != 256:
raise Exception("Unsupported EC size: " + pk.key_size)
return ECDSA256P1(pk)
elif isinstance(pk, EllipticCurvePublicKey):
if pk.curve.name != 'secp256r1':
raise Exception("Unsupported EC curve: " + pk.curve.name)
if pk.key_size != 256:
raise Exception("Unsupported EC size: " + pk.key_size)
return ECDSA256P1Public(pk)
elif isinstance(pk, Ed25519PrivateKey):
return Ed25519(pk)
elif isinstance(pk, Ed25519PublicKey):
return Ed25519Public(pk)
elif isinstance(pk, X25519PrivateKey):
return X25519(pk)
elif isinstance(pk, X25519PublicKey):
return X25519Public(pk)
else:
raise Exception("Unknown key type: " + str(type(pk)))