/* * SPDX-License-Identifier: Apache-2.0 * * Copyright (c) 2016-2019 JUUL Labs * Copyright (c) 2017 Linaro LTD * Copyright (C) 2021 Arm Limited * * Original license: * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ #include #include "mcuboot_config/mcuboot_config.h" #ifdef MCUBOOT_SIGN_EC256 /*TODO: remove this after cypress port mbedtls to abstract crypto api */ #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) || \ defined(MCUBOOT_USE_MBED_TLS) #include "bootutil/sign_key.h" #include "mbedtls/oid.h" #include "mbedtls/asn1.h" #include "bootutil/crypto/ecdsa_p256.h" #include "bootutil/crypto/common.h" #include "bootutil_priv.h" /* * Declaring these like this adds NULL termination. */ static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_EC_ALG_UNRESTRICTED; static const uint8_t ec_secp256r1_oid[] = MBEDTLS_OID_EC_GRP_SECP256R1; /* * Parse the public key used for signing. */ #ifdef CY_MBEDTLS_HW_ACCELERATION static int bootutil_parse_eckey(mbedtls_ecdsa_context *ctx, uint8_t **p, uint8_t *end) { size_t len; mbedtls_asn1_buf alg; mbedtls_asn1_buf param; if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) { return -1; } end = *p + len; if (mbedtls_asn1_get_alg(p, end, &alg, ¶m)) { return -2; } if (alg.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 || memcmp(alg.MBEDTLS_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) { return -3; } if (param.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_secp256r1_oid) - 1|| memcmp(param.MBEDTLS_CONTEXT_MEMBER(p), ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) { return -4; } if (mbedtls_ecp_group_load(&ctx->grp, MBEDTLS_ECP_DP_SECP256R1)) { return -5; } if (mbedtls_asn1_get_bitstring_null(p, end, &len)) { return -6; } if (*p + len != end) { return -7; } if (mbedtls_ecp_point_read_binary(&ctx->grp, &ctx->Q, *p, end - *p)) { return -8; } if (mbedtls_ecp_check_pubkey(&ctx->grp, &ctx->Q)) { return -9; } return 0; } #endif /* CY_MBEDTLS_HW_ACCELERATION */ static int bootutil_import_key(uint8_t **cp, uint8_t *end) { size_t len; mbedtls_asn1_buf alg; mbedtls_asn1_buf param; if (mbedtls_asn1_get_tag(cp, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) { return -1; } end = *cp + len; /* ECParameters (RFC5480) */ if (mbedtls_asn1_get_alg(cp, end, &alg, ¶m)) { return -2; } /* id-ecPublicKey (RFC5480) */ if (alg.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 || memcmp(alg.MBEDTLS_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) { return -3; } /* namedCurve (RFC5480) */ if (param.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_secp256r1_oid) - 1 || memcmp(param.MBEDTLS_CONTEXT_MEMBER(p), ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) { return -4; } /* ECPoint (RFC5480) */ if (mbedtls_asn1_get_bitstring_null(cp, end, &len)) { return -6; } if (*cp + len != end) { return -7; } if (len != 2 * NUM_ECC_BYTES + 1) { return -8; } 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. */ static int bootutil_read_bigint(uint8_t i[NUM_ECC_BYTES], uint8_t **cp, uint8_t *end) { size_t len; if (mbedtls_asn1_get_tag(cp, end, &len, MBEDTLS_ASN1_INTEGER)) { return -3; } if (len >= NUM_ECC_BYTES) { memcpy(i, *cp + len - NUM_ECC_BYTES, NUM_ECC_BYTES); } else { memset(i, 0, NUM_ECC_BYTES - len); memcpy(i + NUM_ECC_BYTES - len, *cp, len); } *cp += len; return 0; } /* * Read in signature. Signature has r and s encoded as integers. */ static int bootutil_decode_sig(uint8_t signature[NUM_ECC_BYTES * 2], uint8_t *cp, uint8_t *end) { int rc; size_t len; rc = mbedtls_asn1_get_tag(&cp, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (rc) { return -1; } if (cp + len > end) { return -2; } rc = bootutil_read_bigint(signature, &cp, end); if (rc) { return -3; } rc = bootutil_read_bigint(signature + NUM_ECC_BYTES, &cp, end); if (rc) { return -4; } 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, uint8_t key_id) { int rc; bootutil_ecdsa_p256_context ctx; 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; #ifdef CY_MBEDTLS_HW_ACCELERATION mbedtls_ecdsa_init(&ctx); rc = bootutil_parse_eckey(&ctx, &pubkey, end); #else rc = bootutil_import_key(&pubkey, end); #endif if (rc) { 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. */ #ifdef CY_MBEDTLS_HW_ACCELERATION while (sig[slen - 1] == '\0') { slen--; } rc = mbedtls_ecdsa_read_signature(&ctx, hash, hlen, sig, slen); #else /* CY_MBEDTLS_HW_ACCELERATION */ if (hlen != NUM_ECC_BYTES) { return -1; } bootutil_ecdsa_p256_init(&ctx); #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 #endif /* CY_MBEDTLS_HW_ACCELERATION */ bootutil_ecdsa_p256_drop(&ctx); return rc; } #endif /* MCUBOOT_USE_TINYCRYPT || defined MCUBOOT_USE_CC310 */ #endif /* MCUBOOT_SIGN_EC256 */