boot: Support Mbed TLS ECDSA for signatures

Add Mbed TLS ECDSA signature verification as an option (in addition to
Tinycrypt and the CC310 hardware version).  Although the Mbed TLS ECDSA
verification code is both larger and slower, this will still save space
if there is another reason that the Mbed TLS code is already being
brought in for another reason (such as certificate management, for
example).

Mbed TLS's ECDSA verification works at a different level than the other
two libraries, so this takes a bit of reworking.  There are some
additional parameters passed to the various functions, and a new define
MCUBOOT_ECDSA_NEED_ASN1_SIG to indicate that the ecdsa verification
wants the original ASN1 signature, not a decoded key.

This adds the boot changes and simulator support to test this configuration.

Signed-off-by: David Brown <david.brown@linaro.org>
diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa_p256.h b/boot/bootutil/include/bootutil/crypto/ecdsa_p256.h
index b77cd34..fa26ffd 100644
--- a/boot/bootutil/include/bootutil/crypto/ecdsa_p256.h
+++ b/boot/bootutil/include/bootutil/crypto/ecdsa_p256.h
@@ -15,7 +15,7 @@
 #if (defined(MCUBOOT_USE_TINYCRYPT) + \
      defined(MCUBOOT_USE_CC310) + \
      defined(MCUBOOT_USE_MBED_TLS)) != 1
-    #error "One crypto backend must be defined: either CC310 or TINYCRYPT"
+    #error "One crypto backend must be defined: either CC310, TINYCRYPT, or MBED_TLS"
 #endif
 
 #if defined(MCUBOOT_USE_TINYCRYPT)
@@ -29,6 +29,11 @@
     #define BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE (4 * 8)
 #endif /* MCUBOOT_USE_CC310 */
 
+#if defined(MCUBOOT_USE_MBED_TLS)
+    #include <mbedtls/ecdsa.h>
+    #define BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE (4 * 8)
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -45,10 +50,22 @@
     (void)ctx;
 }
 
-static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx, const uint8_t *pk, const uint8_t *hash, const uint8_t *sig)
+static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx,
+                                             const uint8_t *pk, size_t pk_len,
+                                             const uint8_t *hash,
+                                             const uint8_t *sig, size_t sig_len)
 {
     int rc;
     (void)ctx;
+    (void)pk_len;
+    (void)sig_len;
+
+    /* Only support uncompressed keys. */
+    if (pk[0] != 0x04) {
+        return -1;
+    }
+    pk++;
+
     rc = uECC_verify(pk, hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, sig, uECC_secp256r1());
     if (rc != TC_CRYPTO_SUCCESS) {
         return -1;
@@ -69,13 +86,77 @@
     (void)ctx;
 }
 
-static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx, uint8_t *pk, uint8_t *hash, uint8_t *sig)
+static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx,
+                                             uint8_t *pk, size_t pk_len,
+                                             uint8_t *hash,
+                                             uint8_t *sig, size_t sig_len)
 {
     (void)ctx;
+    (void)pk_len;
+    (void)sig_len;
+
+    /* Only support uncompressed keys. */
+    if (pk[0] != 0x04) {
+        return -1;
+    }
+    pk++;
+
     return cc310_ecdsa_verify_secp256r1(hash, pk, sig, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE);
 }
 #endif /* MCUBOOT_USE_CC310 */
 
+#if defined(MCUBOOT_USE_MBED_TLS)
+
+/* Indicate to the caller that the verify function needs the raw ASN.1
+ * signature, not a decoded one. */
+#define MCUBOOT_ECDSA_NEED_ASN1_SIG
+
+typedef mbedtls_ecdsa_context bootutil_ecdsa_p256_context;
+static inline void bootutil_ecdsa_p256_init(bootutil_ecdsa_p256_context *ctx)
+{
+    mbedtls_ecdsa_init(ctx);
+}
+
+static inline void bootutil_ecdsa_p256_drop(bootutil_ecdsa_p256_context *ctx)
+{
+    mbedtls_ecdsa_free(ctx);
+}
+
+static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx,
+                                             uint8_t *pk, size_t pk_len,
+                                             uint8_t *hash,
+                                             uint8_t *sig, size_t sig_len)
+{
+    int rc;
+
+    (void)sig;
+    (void)hash;
+
+    rc = mbedtls_ecp_group_load(&ctx->grp, MBEDTLS_ECP_DP_SECP256R1);
+    if (rc) {
+        return -1;
+    }
+
+    rc = mbedtls_ecp_point_read_binary(&ctx->grp, &ctx->Q, pk, pk_len);
+    if (rc) {
+        return -1;
+    }
+
+    rc = mbedtls_ecp_check_pubkey(&ctx->grp, &ctx->Q);
+    if (rc) {
+        return -1;
+    }
+
+    rc = mbedtls_ecdsa_read_signature(ctx, hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE,
+                                      sig, sig_len);
+    if (rc) {
+        return -1;
+    }
+
+    return 0;
+}
+#endif /* MCUBOOT_USE_MBED_TLS */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boot/bootutil/src/image_ec256.c b/boot/bootutil/src/image_ec256.c
index f5b8135..ccb67f3 100644
--- a/boot/bootutil/src/image_ec256.c
+++ b/boot/bootutil/src/image_ec256.c
@@ -30,10 +30,11 @@
 
 #ifdef MCUBOOT_SIGN_EC256
 /*TODO: remove this after cypress port mbedtls to abstract crypto api */
-#ifdef MCUBOOT_USE_CC310
+#if defined(MCUBOOT_USE_CC310) || defined(MCUBOOT_USE_MBED_TLS)
 #define NUM_ECC_BYTES (256 / 8)
 #endif
-#if defined (MCUBOOT_USE_TINYCRYPT) || defined (MCUBOOT_USE_CC310)
+#if defined(MCUBOOT_USE_TINYCRYPT) || defined(MCUBOOT_USE_CC310) || \
+    defined(MCUBOOT_USE_MBED_TLS)
 #include "bootutil/sign_key.h"
 
 #include "mbedtls/oid.h"
@@ -88,16 +89,11 @@
     if (len != 2 * NUM_ECC_BYTES + 1) {
         return -8;
     }
-    /* Is uncompressed? */
-    if (*cp[0] != 0x04) {
-        return -9;
-    }
-
-    (*cp)++;
 
     return 0;
 }
 
+#ifndef MCUBOOT_ECDSA_NEED_ASN1_SIG
 /*
  * cp points to ASN1 string containing an integer.
  * Verify the tag, and that the length is 32 bytes.
@@ -149,6 +145,7 @@
     }
     return 0;
 }
+#endif /* not MCUBOOT_ECDSA_NEED_ASN1_SIG */
 
 int
 bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
@@ -159,7 +156,9 @@
     uint8_t *pubkey;
     uint8_t *end;
 
+#ifndef MCUBOOT_ECDSA_NEED_ASN1_SIG
     uint8_t signature[2 * NUM_ECC_BYTES];
+#endif
 
     pubkey = (uint8_t *)bootutil_keys[key_id].key;
     end = pubkey + *bootutil_keys[key_id].len;
@@ -169,10 +168,12 @@
         return -1;
     }
 
+#ifndef MCUBOOT_ECDSA_NEED_ASN1_SIG
     rc = bootutil_decode_sig(signature, sig, sig + slen);
     if (rc) {
         return -1;
     }
+#endif
 
     /*
      * This is simplified, as the hash length is also 32 bytes.
@@ -182,7 +183,12 @@
     }
 
     bootutil_ecdsa_p256_init(&ctx);
-    rc = bootutil_ecdsa_p256_verify(&ctx, pubkey, hash, signature);
+#ifdef MCUBOOT_ECDSA_NEED_ASN1_SIG
+    rc = bootutil_ecdsa_p256_verify(&ctx, pubkey, end - pubkey, hash, sig, slen);
+#else
+    rc = bootutil_ecdsa_p256_verify(&ctx, pubkey, end - pubkey, hash, signature,
+                                    2 * NUM_ECC_BYTES);
+#endif
     bootutil_ecdsa_p256_drop(&ctx);
     return rc;
 }
diff --git a/boot/zephyr/include/config-ecdsa.h b/boot/zephyr/include/config-ecdsa.h
new file mode 100644
index 0000000..6ae1ada
--- /dev/null
+++ b/boot/zephyr/include/config-ecdsa.h
@@ -0,0 +1,95 @@
+/*
+ *  Minimal configuration for using TLS in the bootloader
+ *
+ *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *  Copyright (C) 2016, Linaro Ltd
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  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.
+ *
+ *  This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+/*
+ * Minimal configuration for using TLS in the bootloader
+ *
+ * - RSA or ECDSA signature verification
+ */
+
+#ifndef MCUBOOT_MBEDTLS_CONFIG_ECDSA
+#define MCUBOOT_MBEDTLS_CONFIG_ECDSA
+
+#ifdef CONFIG_MCUBOOT_SERIAL
+/* Mcuboot uses mbedts-base64 for serial protocol encoding. */
+#define MBEDTLS_BASE64_C
+#endif
+
+/* System support */
+#define MBEDTLS_PLATFORM_C
+#define MBEDTLS_PLATFORM_MEMORY
+#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
+#define MBEDTLS_NO_PLATFORM_ENTROPY
+#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
+
+/* STD functions */
+#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
+
+#define MBEDTLS_PLATFORM_EXIT_ALT
+#define MBEDTLS_PLATFORM_PRINTF_ALT
+#define MBEDTLS_PLATFORM_SNPRINTF_ALT
+
+#if !defined(CONFIG_ARM)
+#define MBEDTLS_HAVE_ASM
+#endif
+
+#define MBEDTLS_ECDSA_C
+
+/* mbed TLS modules */
+#define MBEDTLS_ASN1_PARSE_C
+#define MBEDTLS_ASN1_WRITE_C
+#define MBEDTLS_ECP_C
+#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
+#define MBEDTLS_ECP_NIST_OPTIM
+#define MBEDTLS_BIGNUM_C
+#define MBEDTLS_MD_C
+#define MBEDTLS_OID_C
+#define MBEDTLS_SHA256_C
+#define MBEDTLS_AES_C
+
+/* Bring in support for x509. */
+#define MBEDTLS_X509_USE_C
+#define MBEDTLS_PK_C
+#define MBEDTLS_PK_PARSE_C
+#define MBEDTLS_X509_CRT_PARSE_C
+
+/* Save RAM by adjusting to our exact needs */
+#define MBEDTLS_ECP_MAX_BITS             256
+
+#define MBEDTLS_MPI_MAX_SIZE             32
+
+#define MBEDTLS_SSL_MAX_CONTENT_LEN 1024
+
+/* Save ROM and a few bytes of RAM by specifying our own ciphersuite list */
+#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
+
+/* If encryption is being used, also enable the features needed for
+ * that. */
+#if defined(MCUBOOT_ENC_IMAGES)
+#define MBEDTLS_CIPHER_MODE_CTR
+#define MBEDTLS_CIPHER_C
+#define MBEDTLS_NIST_KW_C
+#endif /* MCUBOOT_ENC_IMAGES */
+
+#include "mbedtls/check_config.h"
+
+#endif /* MCUBOOT_MBEDTLS_CONFIG_ECDSA */