boot: bootutil: add x25519 encrypted image support
- Define new TLV for carrying information for x25519 based encrypted
images.
- Add routines to parse embedded encryption key, generated shared
secret and image decryption key.
Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/boot/bootutil/include/bootutil/enc_key.h b/boot/bootutil/include/bootutil/enc_key.h
index d6dd976..866dcf7 100644
--- a/boot/bootutil/include/bootutil/enc_key.h
+++ b/boot/bootutil/include/bootutil/enc_key.h
@@ -42,11 +42,14 @@
#define TLV_ENC_RSA_SZ 256
#define TLV_ENC_KW_SZ 24
#define TLV_ENC_EC256_SZ (65 + 32 + 16)
+#define TLV_ENC_X25519_SZ (32 + 32 + 16)
#if defined(MCUBOOT_ENCRYPT_RSA)
#define BOOT_ENC_TLV_SIZE TLV_ENC_RSA_SZ
#elif defined(MCUBOOT_ENCRYPT_EC256)
#define BOOT_ENC_TLV_SIZE TLV_ENC_EC256_SZ
+#elif defined(MCUBOOT_ENCRYPT_X25519)
+#define BOOT_ENC_TLV_SIZE TLV_ENC_X25519_SZ
#else
#define BOOT_ENC_TLV_SIZE TLV_ENC_KW_SZ
#endif
diff --git a/boot/bootutil/include/bootutil/image.h b/boot/bootutil/include/bootutil/image.h
index a73dbf6..db64812 100644
--- a/boot/bootutil/include/bootutil/image.h
+++ b/boot/bootutil/include/bootutil/image.h
@@ -84,6 +84,7 @@
#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */
#define IMAGE_TLV_ENC_KW128 0x31 /* Key encrypted with AES-KW-128 */
#define IMAGE_TLV_ENC_EC256 0x32 /* Key encrypted with ECIES-EC256 */
+#define IMAGE_TLV_ENC_X25519 0x33 /* Key encrypted with ECIES-X25519 */
#define IMAGE_TLV_DEPENDENCY 0x40 /* Image depends on other image */
#define IMAGE_TLV_SEC_CNT 0x50 /* security counter */
#define IMAGE_TLV_BOOT_RECORD 0x60 /* measured boot record */
diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c
index 951c800..abc9fdd 100644
--- a/boot/bootutil/src/encrypted.c
+++ b/boot/bootutil/src/encrypted.c
@@ -44,10 +44,13 @@
#endif
#if defined(MCUBOOT_ENCRYPT_EC256)
-#include "tinycrypt/utils.h"
-#include "tinycrypt/constants.h"
#include "tinycrypt/ecc.h"
#include "tinycrypt/ecc_dh.h"
+#endif
+
+#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
+#include "tinycrypt/utils.h"
+#include "tinycrypt/constants.h"
#include "tinycrypt/ctr_mode.h"
#include "tinycrypt/hmac.h"
#include "mbedtls/oid.h"
@@ -203,6 +206,9 @@
static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_EC_ALG_UNRESTRICTED;
static const uint8_t ec_secp256r1_oid[] = MBEDTLS_OID_EC_GRP_SECP256R1;
+#define SHARED_KEY_LEN NUM_ECC_BYTES
+#define PRIV_KEY_LEN NUM_ECC_BYTES
+
/*
* Parses the output of `imgtool keygen`, which produces a PKCS#8 elliptic
* curve keypair. See RFC5208 and RFC5915.
@@ -275,7 +281,68 @@
return 0;
}
+#endif /* defined(MCUBOOT_ENCRYPT_EC256) */
+#if defined(MCUBOOT_ENCRYPT_X25519)
+#define X25519_OID "\x6e"
+static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG \
+ MBEDTLS_OID_ORG_GOV X25519_OID;
+
+extern int X25519(uint8_t out_shared_key[32], const uint8_t private_key[32],
+ const uint8_t peer_public_value[32]);
+
+#define SHARED_KEY_LEN 32
+#define PRIV_KEY_LEN 32
+
+static int
+parse_x25519_enckey(uint8_t **p, uint8_t *end, uint8_t *pk)
+{
+ size_t len;
+ int version;
+ mbedtls_asn1_buf alg;
+ mbedtls_asn1_buf param;
+
+ if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+ MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return -1;
+ }
+
+ if (*p + len != end) {
+ return -2;
+ }
+
+ version = 0;
+ if (mbedtls_asn1_get_int(p, end, &version) || version != 0) {
+ return -3;
+ }
+
+ if (mbedtls_asn1_get_alg(p, end, &alg, ¶m) != 0) {
+ return -4;
+ }
+
+ if (alg.len != sizeof(ec_pubkey_oid) - 1 ||
+ memcmp(alg.p, ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
+ return -5;
+ }
+
+ if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING) != 0) {
+ return -6;
+ }
+
+ if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING) != 0) {
+ return -7;
+ }
+
+ if (len != PRIV_KEY_LEN) {
+ return -8;
+ }
+
+ memcpy(pk, *p, PRIV_KEY_LEN);
+ return 0;
+}
+#endif /* defined(MCUBOOT_ENCRYPT_X25519) */
+
+#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
/*
* HKDF as described by RFC5869.
*
@@ -423,6 +490,13 @@
# define EC_CIPHERKEY_INDEX (65 + 32)
_Static_assert(EC_CIPHERKEY_INDEX + 16 == EXPECTED_ENC_LEN,
"Please fix ECIES-P256 component indexes");
+#elif defined(MCUBOOT_ENCRYPT_X25519)
+# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519
+# define EC_PUBK_INDEX (0)
+# define EC_TAG_INDEX (32)
+# define EC_CIPHERKEY_INDEX (32 + 32)
+_Static_assert(EC_CIPHERKEY_INDEX + 16 == EXPECTED_ENC_LEN,
+ "Please fix ECIES-X25519 component indexes");
#endif
/*
@@ -440,15 +514,15 @@
uint8_t *cpend;
size_t olen;
#endif
-#if defined(MCUBOOT_ENCRYPT_EC256)
+#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
struct tc_hmac_state_struct hmac;
struct tc_aes_key_sched_struct aes;
uint8_t tag[TC_SHA256_DIGEST_SIZE];
- uint8_t shared[NUM_ECC_BYTES];
+ uint8_t shared[SHARED_KEY_LEN];
uint8_t derived_key[TC_AES_KEY_SIZE + TC_SHA256_DIGEST_SIZE];
uint8_t *cp;
uint8_t *cpend;
- uint8_t pk[NUM_ECC_BYTES];
+ uint8_t pk[PRIV_KEY_LEN];
uint8_t counter[TC_AES_BLOCK_SIZE];
uint16_t len;
#endif
@@ -471,12 +545,16 @@
NULL, 0, &olen, buf, enckey, BOOT_ENC_KEY_SIZE);
mbedtls_rsa_free(&rsa);
-#elif defined(MCUBOOT_ENCRYPT_KW)
+#endif /* defined(MCUBOOT_ENCRYPT_RSA) */
+
+#if defined(MCUBOOT_ENCRYPT_KW)
assert(*bootutil_enc_key.len == 16);
rc = key_unwrap(buf, enckey);
-#elif defined(MCUBOOT_ENCRYPT_EC256)
+#endif /* defined(MCUBOOT_ENCRYPT_KW) */
+
+#if defined(MCUBOOT_ENCRYPT_EC256)
cp = (uint8_t *)bootutil_enc_key.key;
cpend = cp + *bootutil_enc_key.len;
@@ -508,12 +586,41 @@
return -1;
}
+#endif /* defined(MCUBOOT_ENCRYPT_EC256) */
+
+#if defined(MCUBOOT_ENCRYPT_X25519)
+
+ cp = (uint8_t *)bootutil_enc_key.key;
+ cpend = cp + *bootutil_enc_key.len;
+
+ /*
+ * Load the stored X25519 decryption private key
+ */
+
+ rc = parse_x25519_enckey(&cp, cpend, pk);
+ if (rc) {
+ return rc;
+ }
+
+ /*
+ * First "element" in the TLV is the curve point (public key)
+ */
+
+ rc = X25519(shared, pk, &buf[EC_PUBK_INDEX]);
+ if (!rc) {
+ return -1;
+ }
+
+#endif /* defined(MCUBOOT_ENCRYPT_X25519) */
+
+#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
+
/*
* Expand shared secret to create keys for AES-128-CTR + HMAC-SHA256
*/
len = TC_AES_KEY_SIZE + TC_SHA256_DIGEST_SIZE;
- rc = hkdf(shared, NUM_ECC_BYTES, (uint8_t *)"MCUBoot_ECIES_v1", 16,
+ rc = hkdf(shared, SHARED_KEY_LEN, (uint8_t *)"MCUBoot_ECIES_v1", 16,
derived_key, &len);
if (rc != 0 || len != (TC_AES_KEY_SIZE + TC_SHA256_DIGEST_SIZE)) {
return -1;
@@ -566,7 +673,7 @@
rc = 0;
-#endif
+#endif /* defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519) */
return rc;
}