Commit de9bc3d0 authored by Dominik Ermel's avatar Dominik Ermel Committed by Andrzej Puzdrowski
Browse files

bootutil: PureEdDSA using ED25519



The commit adds support for PureEdDSA, which validates signature
of image rather than hash. This is most secure, available, ED25519
usage in MCUboot, but due to requirement of PureEdDSA to be able
to calculate signature at whole message at once, here image,
it only works on setups where entire image can be mapped to
device address space, so that PSA functions calculating the
signature can see the whole image at once.

The feature is enabled with MCUBOOT_SIGN_PURE MCUboot configuration
option.

Signed-off-by: default avatarDominik Ermel <dominik.ermel@nordicsemi.no>
parent b43b8c80
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -267,9 +267,18 @@ struct boot_loader_state {
#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
};

/* The function is intended for verification of image hash against
 * provided signature.
 */
fih_ret bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig,
                            size_t slen, uint8_t key_id);

/* The function is intended for direct verification of image
 * against provided signature.
 */
fih_ret bootutil_verify_img(uint8_t *img, uint32_t size,
                            uint8_t *sig, size_t slen, uint8_t key_id);

fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n);

int boot_find_status(int image_index, const struct flash_area **fap);
+53 −6
Original line number Diff line number Diff line
@@ -69,8 +69,15 @@ bootutil_import_key(uint8_t **cp, uint8_t *end)
    return 0;
}

fih_ret
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
/* Signature verification base function.
 * The function takes buffer of specified length and tries to verify
 * it against provided signature.
 * The function does key import and checks whether signature is
 * of expected length.
 */
static fih_ret
bootutil_verify(uint8_t *buf, uint32_t blen,
                uint8_t *sig, size_t slen,
                uint8_t key_id)
{
    int rc;
@@ -78,8 +85,7 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
    uint8_t *pubkey;
    uint8_t *end;

    if (hlen != IMAGE_HASH_SIZE ||
        slen != EDDSA_SIGNATURE_LENGTH) {
    if (slen != EDDSA_SIGNATURE_LENGTH) {
        FIH_SET(fih_rc, FIH_FAILURE);
        goto out;
    }
@@ -93,7 +99,7 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
        goto out;
    }

    rc = ED25519_verify(hash, IMAGE_HASH_SIZE, sig, pubkey);
    rc = ED25519_verify(buf, blen, sig, pubkey);

    if (rc == 0) {
        /* if verify returns 0, there was an error. */
@@ -107,4 +113,45 @@ out:
    FIH_RET(fih_rc);
}

/* Hash signature verification function.
 * Verifies hash against provided signature.
 * The function verifies that hash is of expected size and then
 * calls bootutil_verify to do the signature verification.
 */
fih_ret
bootutil_verify_sig(uint8_t *hash, uint32_t hlen,
                    uint8_t *sig, size_t slen,
                    uint8_t key_id)
{
    FIH_DECLARE(fih_rc, FIH_FAILURE);

    if (hlen != IMAGE_HASH_SIZE) {
        FIH_SET(fih_rc, FIH_FAILURE);
        goto out;
    }

    FIH_CALL(bootutil_verify, fih_rc, hash, IMAGE_HASH_SIZE, sig,
             slen, key_id);

out:
    FIH_RET(fih_rc);
}

/* Image verification function.
 * The function directly calls bootutil_verify to verify signature
 * of image.
 */
fih_ret
bootutil_verify_img(uint8_t *img, uint32_t size,
                    uint8_t *sig, size_t slen,
                    uint8_t key_id)
{
    FIH_DECLARE(fih_rc, FIH_FAILURE);

    FIH_CALL(bootutil_verify, fih_rc, img, size, sig,
             slen, key_id);

    FIH_RET(fih_rc);
}

#endif /* MCUBOOT_SIGN_ED25519 */
+90 −6
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@

#include "bootutil_priv.h"

#ifndef MCUBOOT_SIGN_PURE
/*
 * Compute SHA hash over the image.
 * (SHA384 if ECDSA-P384 is being used,
@@ -175,6 +176,7 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index,

    return 0;
}
#endif

/*
 * Currently, we only support being able to verify one type of
@@ -361,6 +363,44 @@ bootutil_get_img_security_cnt(struct image_header *hdr,
    return 0;
}

#if defined(MCUBOOT_SIGN_PURE)
/* Returns:
 *  0 -- found
 *  1 -- not found or found but not true
 * -1 -- failed for some reason
 *
 * Value of TLV does not matter, presence decides.
 */
static int bootutil_check_for_pure(const struct image_header *hdr,
                                   const struct flash_area *fap)
{
    struct image_tlv_iter it;
    uint32_t off;
    uint16_t len;
    int32_t rc;

    rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_SIG_PURE, false);
    if (rc) {
        return -1;
    }

    /* Search for the TLV */
    rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
    if (rc == 0 && len == 1) {
        uint8_t val;

        rc = LOAD_IMAGE_DATA(hdr, fap, off, &val, sizeof(val));
        if (rc == 0) {
            return (val == 1) ? 0 : 1;
        } else {
            return -1;
        }
    }

    return 1;
}
#endif

#ifndef ALLOW_ROGUE_TLVS
/*
 * The following list of TLVs are the only entries allowed in the unprotected
@@ -377,6 +417,9 @@ static const uint16_t allowed_unprot_tlvs[] = {
     IMAGE_TLV_ECDSA_SIG,
     IMAGE_TLV_RSA3072_PSS,
     IMAGE_TLV_ED25519,
#if defined(MCUBOOT_SIGN_PURE)
     IMAGE_TLV_SIG_PURE,
#endif
     IMAGE_TLV_ENC_RSA2048,
     IMAGE_TLV_ENC_KW,
     IMAGE_TLV_ENC_EC256,
@@ -399,7 +442,6 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
    uint32_t off;
    uint16_t len;
    uint16_t type;
    int image_hash_valid = 0;
#ifdef EXPECTED_SIG_TLV
    FIH_DECLARE(valid_signature, FIH_FAILURE);
#ifndef MCUBOOT_BUILTIN_KEY
@@ -416,7 +458,10 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
#endif /* EXPECTED_SIG_TLV */
    struct image_tlv_iter it;
    uint8_t buf[SIG_BUF_SIZE];
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
    int image_hash_valid = 0;
    uint8_t hash[IMAGE_HASH_SIZE];
#endif
    int rc = 0;
    FIH_DECLARE(fih_rc, FIH_FAILURE);
#ifdef MCUBOOT_HW_ROLLBACK_PROT
@@ -425,6 +470,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
    FIH_DECLARE(security_counter_valid, FIH_FAILURE);
#endif

#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
    rc = bootutil_img_hash(enc_state, image_index, hdr, fap, tmp_buf,
            tmp_buf_sz, hash, seed, seed_len);
    if (rc) {
@@ -434,6 +480,15 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
    if (out_hash) {
        memcpy(out_hash, hash, IMAGE_HASH_SIZE);
    }
#endif

#if defined(MCUBOOT_SIGN_PURE)
    /* If Pure type signature is expected then it has to be there */
    rc = bootutil_check_for_pure(hdr, fap);
    if (rc != 0) {
	goto out;
    }
#endif

    rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
    if (rc) {
@@ -477,8 +532,10 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
             }
        }
#endif

        if (type == EXPECTED_HASH_TLV) {
        switch(type) {
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
        case EXPECTED_HASH_TLV:
        {
            /* Verify the image hash. This must always be present. */
            if (len != sizeof(hash)) {
                rc = -1;
@@ -496,8 +553,12 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
            }

            image_hash_valid = 1;
            break;
        }
#endif /* defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) */
#ifdef EXPECTED_KEY_TLV
        } else if (type == EXPECTED_KEY_TLV) {
        case EXPECTED_KEY_TLV:
        {
            /*
             * Determine which key we should be checking.
             */
@@ -522,9 +583,12 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
             * The key may not be found, which is acceptable.  There
             * can be multiple signatures, each preceded by a key.
             */
            break;
        }
#endif /* EXPECTED_KEY_TLV */
#ifdef EXPECTED_SIG_TLV
        } else if (type == EXPECTED_SIG_TLV) {
        case EXPECTED_SIG_TLV:
        {
            /* Ignore this signature if it is out of bounds. */
            if (key_id < 0 || key_id >= bootutil_key_cnt) {
                key_id = -1;
@@ -538,12 +602,25 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
            if (rc) {
                goto out;
            }
#ifndef MCUBOOT_SIGN_PURE
            FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash),
                                                           buf, len, key_id);
#else
            /* Directly check signature on the image, by using the mapping of
             * a device to memory. The pointer is beginning of image in flash,
             * so offset of area, the range is header + image + protected tlvs.
             */
            FIH_CALL(bootutil_verify_img, valid_signature, (void *)flash_area_get_off(fap),
                     hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_protect_tlv_size,
                     buf, len, key_id);
#endif
            key_id = -1;
            break;
        }
#endif /* EXPECTED_SIG_TLV */
#ifdef MCUBOOT_HW_ROLLBACK_PROT
        } else if (type == IMAGE_TLV_SEC_CNT) {
        case IMAGE_TLV_SEC_CNT:
        {
            /*
             * Verify the image's security counter.
             * This must always be present.
@@ -578,14 +655,21 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index,

            /* The image's security counter has been successfully verified. */
            security_counter_valid = fih_rc;
            break;
        }
#endif /* MCUBOOT_HW_ROLLBACK_PROT */
        }
    }

#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
    rc = !image_hash_valid;
    if (rc) {
        goto out;
    }
#elif defined(MCUBOOT_SIGN_PURE)
    /* This returns true on EQ, rc is err on non-0 */
    rc = FIH_NOT_EQ(valid_signature, FIH_SUCCESS);
#endif
#ifdef EXPECTED_SIG_TLV
    FIH_SET(fih_rc, valid_signature);
#endif
+2 −0
Original line number Diff line number Diff line
@@ -111,6 +111,8 @@ struct image_tlv {
#define IMAGE_TLV_ECDSA_SIG         0x22   /* ECDSA of hash output */
#define IMAGE_TLV_RSA3072_PSS       0x23   /* RSA3072 of hash output */
#define IMAGE_TLV_ED25519           0x24   /* ED25519 of hash output */
#define IMAGE_TLV_SIG_PURE          0x25   /* If true then any signature found has been
                                              calculated over image directly. */
#define IMAGE_TLV_ENC_RSA2048       0x30   /* Key encrypted with RSA-OAEP-2048 */
#define IMAGE_TLV_ENC_KW            0x31   /* Key encrypted with AES-KW-128 or
                                              256 */