1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * Elliptic curve DSA 3817466cbSJens Wiklander * 47901324dSJerome Forissier * Copyright The Mbed TLS Contributors 57901324dSJerome Forissier * SPDX-License-Identifier: Apache-2.0 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8817466cbSJens Wiklander * not use this file except in compliance with the License. 9817466cbSJens Wiklander * You may obtain a copy of the License at 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12817466cbSJens Wiklander * 13817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16817466cbSJens Wiklander * See the License for the specific language governing permissions and 17817466cbSJens Wiklander * limitations under the License. 18817466cbSJens Wiklander */ 19817466cbSJens Wiklander 20817466cbSJens Wiklander /* 21817466cbSJens Wiklander * References: 22817466cbSJens Wiklander * 23817466cbSJens Wiklander * SEC1 http://www.secg.org/index.php?action=secg,docs_secg 24817466cbSJens Wiklander */ 25817466cbSJens Wiklander 267901324dSJerome Forissier #include "common.h" 27817466cbSJens Wiklander 28817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_C) 29817466cbSJens Wiklander 30817466cbSJens Wiklander #include "mbedtls/ecdsa.h" 31817466cbSJens Wiklander #include "mbedtls/asn1write.h" 32817466cbSJens Wiklander 33817466cbSJens Wiklander #include <string.h> 34817466cbSJens Wiklander 35817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC) 36817466cbSJens Wiklander #include "mbedtls/hmac_drbg.h" 37817466cbSJens Wiklander #endif 38817466cbSJens Wiklander 393d3b0591SJens Wiklander #include "mbedtls/platform.h" 403d3b0591SJens Wiklander 413d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 4211fa71b9SJerome Forissier #include "mbedtls/error.h" 433d3b0591SJens Wiklander 443d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 453d3b0591SJens Wiklander 463d3b0591SJens Wiklander /* 473d3b0591SJens Wiklander * Sub-context for ecdsa_verify() 483d3b0591SJens Wiklander */ 49*32b31808SJens Wiklander struct mbedtls_ecdsa_restart_ver { 503d3b0591SJens Wiklander mbedtls_mpi u1, u2; /* intermediate values */ 513d3b0591SJens Wiklander enum { /* what to do next? */ 523d3b0591SJens Wiklander ecdsa_ver_init = 0, /* getting started */ 533d3b0591SJens Wiklander ecdsa_ver_muladd, /* muladd step */ 543d3b0591SJens Wiklander } state; 553d3b0591SJens Wiklander }; 563d3b0591SJens Wiklander 573d3b0591SJens Wiklander /* 583d3b0591SJens Wiklander * Init verify restart sub-context 593d3b0591SJens Wiklander */ 603d3b0591SJens Wiklander static void ecdsa_restart_ver_init(mbedtls_ecdsa_restart_ver_ctx *ctx) 613d3b0591SJens Wiklander { 623d3b0591SJens Wiklander mbedtls_mpi_init(&ctx->u1); 633d3b0591SJens Wiklander mbedtls_mpi_init(&ctx->u2); 643d3b0591SJens Wiklander ctx->state = ecdsa_ver_init; 653d3b0591SJens Wiklander } 663d3b0591SJens Wiklander 673d3b0591SJens Wiklander /* 683d3b0591SJens Wiklander * Free the components of a verify restart sub-context 693d3b0591SJens Wiklander */ 703d3b0591SJens Wiklander static void ecdsa_restart_ver_free(mbedtls_ecdsa_restart_ver_ctx *ctx) 713d3b0591SJens Wiklander { 72*32b31808SJens Wiklander if (ctx == NULL) { 733d3b0591SJens Wiklander return; 74*32b31808SJens Wiklander } 753d3b0591SJens Wiklander 763d3b0591SJens Wiklander mbedtls_mpi_free(&ctx->u1); 773d3b0591SJens Wiklander mbedtls_mpi_free(&ctx->u2); 783d3b0591SJens Wiklander 793d3b0591SJens Wiklander ecdsa_restart_ver_init(ctx); 803d3b0591SJens Wiklander } 813d3b0591SJens Wiklander 823d3b0591SJens Wiklander /* 833d3b0591SJens Wiklander * Sub-context for ecdsa_sign() 843d3b0591SJens Wiklander */ 85*32b31808SJens Wiklander struct mbedtls_ecdsa_restart_sig { 863d3b0591SJens Wiklander int sign_tries; 873d3b0591SJens Wiklander int key_tries; 883d3b0591SJens Wiklander mbedtls_mpi k; /* per-signature random */ 893d3b0591SJens Wiklander mbedtls_mpi r; /* r value */ 903d3b0591SJens Wiklander enum { /* what to do next? */ 913d3b0591SJens Wiklander ecdsa_sig_init = 0, /* getting started */ 923d3b0591SJens Wiklander ecdsa_sig_mul, /* doing ecp_mul() */ 933d3b0591SJens Wiklander ecdsa_sig_modn, /* mod N computations */ 943d3b0591SJens Wiklander } state; 953d3b0591SJens Wiklander }; 963d3b0591SJens Wiklander 973d3b0591SJens Wiklander /* 983d3b0591SJens Wiklander * Init verify sign sub-context 993d3b0591SJens Wiklander */ 1003d3b0591SJens Wiklander static void ecdsa_restart_sig_init(mbedtls_ecdsa_restart_sig_ctx *ctx) 1013d3b0591SJens Wiklander { 1023d3b0591SJens Wiklander ctx->sign_tries = 0; 1033d3b0591SJens Wiklander ctx->key_tries = 0; 1043d3b0591SJens Wiklander mbedtls_mpi_init(&ctx->k); 1053d3b0591SJens Wiklander mbedtls_mpi_init(&ctx->r); 1063d3b0591SJens Wiklander ctx->state = ecdsa_sig_init; 1073d3b0591SJens Wiklander } 1083d3b0591SJens Wiklander 1093d3b0591SJens Wiklander /* 1103d3b0591SJens Wiklander * Free the components of a sign restart sub-context 1113d3b0591SJens Wiklander */ 1123d3b0591SJens Wiklander static void ecdsa_restart_sig_free(mbedtls_ecdsa_restart_sig_ctx *ctx) 1133d3b0591SJens Wiklander { 114*32b31808SJens Wiklander if (ctx == NULL) { 1153d3b0591SJens Wiklander return; 116*32b31808SJens Wiklander } 1173d3b0591SJens Wiklander 1183d3b0591SJens Wiklander mbedtls_mpi_free(&ctx->k); 1193d3b0591SJens Wiklander mbedtls_mpi_free(&ctx->r); 1203d3b0591SJens Wiklander } 1213d3b0591SJens Wiklander 1223d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC) 1233d3b0591SJens Wiklander /* 1243d3b0591SJens Wiklander * Sub-context for ecdsa_sign_det() 1253d3b0591SJens Wiklander */ 126*32b31808SJens Wiklander struct mbedtls_ecdsa_restart_det { 1273d3b0591SJens Wiklander mbedtls_hmac_drbg_context rng_ctx; /* DRBG state */ 1283d3b0591SJens Wiklander enum { /* what to do next? */ 1293d3b0591SJens Wiklander ecdsa_det_init = 0, /* getting started */ 1303d3b0591SJens Wiklander ecdsa_det_sign, /* make signature */ 1313d3b0591SJens Wiklander } state; 1323d3b0591SJens Wiklander }; 1333d3b0591SJens Wiklander 1343d3b0591SJens Wiklander /* 1353d3b0591SJens Wiklander * Init verify sign_det sub-context 1363d3b0591SJens Wiklander */ 1373d3b0591SJens Wiklander static void ecdsa_restart_det_init(mbedtls_ecdsa_restart_det_ctx *ctx) 1383d3b0591SJens Wiklander { 1393d3b0591SJens Wiklander mbedtls_hmac_drbg_init(&ctx->rng_ctx); 1403d3b0591SJens Wiklander ctx->state = ecdsa_det_init; 1413d3b0591SJens Wiklander } 1423d3b0591SJens Wiklander 1433d3b0591SJens Wiklander /* 1443d3b0591SJens Wiklander * Free the components of a sign_det restart sub-context 1453d3b0591SJens Wiklander */ 1463d3b0591SJens Wiklander static void ecdsa_restart_det_free(mbedtls_ecdsa_restart_det_ctx *ctx) 1473d3b0591SJens Wiklander { 148*32b31808SJens Wiklander if (ctx == NULL) { 1493d3b0591SJens Wiklander return; 150*32b31808SJens Wiklander } 1513d3b0591SJens Wiklander 1523d3b0591SJens Wiklander mbedtls_hmac_drbg_free(&ctx->rng_ctx); 1533d3b0591SJens Wiklander 1543d3b0591SJens Wiklander ecdsa_restart_det_init(ctx); 1553d3b0591SJens Wiklander } 1563d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ 1573d3b0591SJens Wiklander 1585b25c76aSJerome Forissier #define ECDSA_RS_ECP (rs_ctx == NULL ? NULL : &rs_ctx->ecp) 1593d3b0591SJens Wiklander 1603d3b0591SJens Wiklander /* Utility macro for checking and updating ops budget */ 1613d3b0591SJens Wiklander #define ECDSA_BUDGET(ops) \ 1625b25c76aSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_ecp_check_budget(grp, ECDSA_RS_ECP, ops)); 1633d3b0591SJens Wiklander 1643d3b0591SJens Wiklander /* Call this when entering a function that needs its own sub-context */ 1653d3b0591SJens Wiklander #define ECDSA_RS_ENTER(SUB) do { \ 1663d3b0591SJens Wiklander /* reset ops count for this call if top-level */ \ 1673d3b0591SJens Wiklander if (rs_ctx != NULL && rs_ctx->ecp.depth++ == 0) \ 1683d3b0591SJens Wiklander rs_ctx->ecp.ops_done = 0; \ 1693d3b0591SJens Wiklander \ 1703d3b0591SJens Wiklander /* set up our own sub-context if needed */ \ 1713d3b0591SJens Wiklander if (mbedtls_ecp_restart_is_enabled() && \ 1723d3b0591SJens Wiklander rs_ctx != NULL && rs_ctx->SUB == NULL) \ 1733d3b0591SJens Wiklander { \ 1743d3b0591SJens Wiklander rs_ctx->SUB = mbedtls_calloc(1, sizeof(*rs_ctx->SUB)); \ 1753d3b0591SJens Wiklander if (rs_ctx->SUB == NULL) \ 176*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_ALLOC_FAILED; \ 1773d3b0591SJens Wiklander \ 1783d3b0591SJens Wiklander ecdsa_restart_## SUB ##_init(rs_ctx->SUB); \ 1793d3b0591SJens Wiklander } \ 1803d3b0591SJens Wiklander } while (0) 1813d3b0591SJens Wiklander 1823d3b0591SJens Wiklander /* Call this when leaving a function that needs its own sub-context */ 1833d3b0591SJens Wiklander #define ECDSA_RS_LEAVE(SUB) do { \ 1843d3b0591SJens Wiklander /* clear our sub-context when not in progress (done or error) */ \ 1853d3b0591SJens Wiklander if (rs_ctx != NULL && rs_ctx->SUB != NULL && \ 1863d3b0591SJens Wiklander ret != MBEDTLS_ERR_ECP_IN_PROGRESS) \ 1873d3b0591SJens Wiklander { \ 1883d3b0591SJens Wiklander ecdsa_restart_## SUB ##_free(rs_ctx->SUB); \ 1893d3b0591SJens Wiklander mbedtls_free(rs_ctx->SUB); \ 1903d3b0591SJens Wiklander rs_ctx->SUB = NULL; \ 1913d3b0591SJens Wiklander } \ 1923d3b0591SJens Wiklander \ 1933d3b0591SJens Wiklander if (rs_ctx != NULL) \ 1943d3b0591SJens Wiklander rs_ctx->ecp.depth--; \ 1953d3b0591SJens Wiklander } while (0) 1963d3b0591SJens Wiklander 1973d3b0591SJens Wiklander #else /* MBEDTLS_ECP_RESTARTABLE */ 1983d3b0591SJens Wiklander 1993d3b0591SJens Wiklander #define ECDSA_RS_ECP NULL 2003d3b0591SJens Wiklander 2013d3b0591SJens Wiklander #define ECDSA_BUDGET(ops) /* no-op; for compatibility */ 2023d3b0591SJens Wiklander 2033d3b0591SJens Wiklander #define ECDSA_RS_ENTER(SUB) (void) rs_ctx 2043d3b0591SJens Wiklander #define ECDSA_RS_LEAVE(SUB) (void) rs_ctx 2053d3b0591SJens Wiklander 2063d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 2073d3b0591SJens Wiklander 2087901324dSJerome Forissier #if defined(MBEDTLS_ECDSA_DETERMINISTIC) || \ 2097901324dSJerome Forissier !defined(MBEDTLS_ECDSA_SIGN_ALT) || \ 2107901324dSJerome Forissier !defined(MBEDTLS_ECDSA_VERIFY_ALT) 211817466cbSJens Wiklander /* 212817466cbSJens Wiklander * Derive a suitable integer for group grp from a buffer of length len 213817466cbSJens Wiklander * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3 214817466cbSJens Wiklander */ 215817466cbSJens Wiklander static int derive_mpi(const mbedtls_ecp_group *grp, mbedtls_mpi *x, 216817466cbSJens Wiklander const unsigned char *buf, size_t blen) 217817466cbSJens Wiklander { 21811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 219817466cbSJens Wiklander size_t n_size = (grp->nbits + 7) / 8; 220817466cbSJens Wiklander size_t use_size = blen > n_size ? n_size : blen; 221817466cbSJens Wiklander 222817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(x, buf, use_size)); 223*32b31808SJens Wiklander if (use_size * 8 > grp->nbits) { 224817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(x, use_size * 8 - grp->nbits)); 225*32b31808SJens Wiklander } 226817466cbSJens Wiklander 227817466cbSJens Wiklander /* While at it, reduce modulo N */ 228*32b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(x, &grp->N) >= 0) { 229817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(x, x, &grp->N)); 230*32b31808SJens Wiklander } 231817466cbSJens Wiklander 232817466cbSJens Wiklander cleanup: 233*32b31808SJens Wiklander return ret; 234817466cbSJens Wiklander } 2357901324dSJerome Forissier #endif /* ECDSA_DETERMINISTIC || !ECDSA_SIGN_ALT || !ECDSA_VERIFY_ALT */ 236817466cbSJens Wiklander 2373d3b0591SJens Wiklander #if !defined(MBEDTLS_ECDSA_SIGN_ALT) 238817466cbSJens Wiklander /* 239817466cbSJens Wiklander * Compute ECDSA signature of a hashed message (SEC1 4.1.3) 240817466cbSJens Wiklander * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) 241817466cbSJens Wiklander */ 242*32b31808SJens Wiklander int mbedtls_ecdsa_sign_restartable(mbedtls_ecp_group *grp, 2433d3b0591SJens Wiklander mbedtls_mpi *r, mbedtls_mpi *s, 244817466cbSJens Wiklander const mbedtls_mpi *d, const unsigned char *buf, size_t blen, 2453d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, 2465b25c76aSJerome Forissier int (*f_rng_blind)(void *, unsigned char *, size_t), 2475b25c76aSJerome Forissier void *p_rng_blind, 2483d3b0591SJens Wiklander mbedtls_ecdsa_restart_ctx *rs_ctx) 249817466cbSJens Wiklander { 2503d3b0591SJens Wiklander int ret, key_tries, sign_tries; 2513d3b0591SJens Wiklander int *p_sign_tries = &sign_tries, *p_key_tries = &key_tries; 252817466cbSJens Wiklander mbedtls_ecp_point R; 253817466cbSJens Wiklander mbedtls_mpi k, e, t; 2543d3b0591SJens Wiklander mbedtls_mpi *pk = &k, *pr = r; 255817466cbSJens Wiklander 256817466cbSJens Wiklander /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ 257*32b31808SJens Wiklander if (!mbedtls_ecdsa_can_do(grp->id) || grp->N.p == NULL) { 258*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 259*32b31808SJens Wiklander } 260817466cbSJens Wiklander 2613d3b0591SJens Wiklander /* Make sure d is in range 1..n-1 */ 262*32b31808SJens Wiklander if (mbedtls_mpi_cmp_int(d, 1) < 0 || mbedtls_mpi_cmp_mpi(d, &grp->N) >= 0) { 263*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_INVALID_KEY; 264*32b31808SJens Wiklander } 2653d3b0591SJens Wiklander 266817466cbSJens Wiklander mbedtls_ecp_point_init(&R); 267817466cbSJens Wiklander mbedtls_mpi_init(&k); mbedtls_mpi_init(&e); mbedtls_mpi_init(&t); 268817466cbSJens Wiklander 2693d3b0591SJens Wiklander ECDSA_RS_ENTER(sig); 270817466cbSJens Wiklander 2713d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 272*32b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->sig != NULL) { 2733d3b0591SJens Wiklander /* redirect to our context */ 2743d3b0591SJens Wiklander p_sign_tries = &rs_ctx->sig->sign_tries; 2753d3b0591SJens Wiklander p_key_tries = &rs_ctx->sig->key_tries; 2763d3b0591SJens Wiklander pk = &rs_ctx->sig->k; 2773d3b0591SJens Wiklander pr = &rs_ctx->sig->r; 2783d3b0591SJens Wiklander 2793d3b0591SJens Wiklander /* jump to current step */ 280*32b31808SJens Wiklander if (rs_ctx->sig->state == ecdsa_sig_mul) { 2813d3b0591SJens Wiklander goto mul; 282*32b31808SJens Wiklander } 283*32b31808SJens Wiklander if (rs_ctx->sig->state == ecdsa_sig_modn) { 2843d3b0591SJens Wiklander goto modn; 2853d3b0591SJens Wiklander } 286*32b31808SJens Wiklander } 2873d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 2883d3b0591SJens Wiklander 2893d3b0591SJens Wiklander *p_sign_tries = 0; 290*32b31808SJens Wiklander do { 291*32b31808SJens Wiklander if ((*p_sign_tries)++ > 10) { 292817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; 293817466cbSJens Wiklander goto cleanup; 294817466cbSJens Wiklander } 2953d3b0591SJens Wiklander 2963d3b0591SJens Wiklander /* 2973d3b0591SJens Wiklander * Steps 1-3: generate a suitable ephemeral keypair 2983d3b0591SJens Wiklander * and set r = xR mod n 2993d3b0591SJens Wiklander */ 3003d3b0591SJens Wiklander *p_key_tries = 0; 301*32b31808SJens Wiklander do { 302*32b31808SJens Wiklander if ((*p_key_tries)++ > 10) { 3033d3b0591SJens Wiklander ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; 3043d3b0591SJens Wiklander goto cleanup; 305817466cbSJens Wiklander } 3063d3b0591SJens Wiklander 3073d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_gen_privkey(grp, pk, f_rng, p_rng)); 3083d3b0591SJens Wiklander 3093d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 310*32b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->sig != NULL) { 3113d3b0591SJens Wiklander rs_ctx->sig->state = ecdsa_sig_mul; 312*32b31808SJens Wiklander } 3133d3b0591SJens Wiklander 3143d3b0591SJens Wiklander mul: 3153d3b0591SJens Wiklander #endif 3163d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_mul_restartable(grp, &R, pk, &grp->G, 3175b25c76aSJerome Forissier f_rng_blind, 3185b25c76aSJerome Forissier p_rng_blind, 3195b25c76aSJerome Forissier ECDSA_RS_ECP)); 3203d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(pr, &R.X, &grp->N)); 321*32b31808SJens Wiklander } while (mbedtls_mpi_cmp_int(pr, 0) == 0); 3223d3b0591SJens Wiklander 3233d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 324*32b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->sig != NULL) { 3253d3b0591SJens Wiklander rs_ctx->sig->state = ecdsa_sig_modn; 326*32b31808SJens Wiklander } 3273d3b0591SJens Wiklander 3283d3b0591SJens Wiklander modn: 3293d3b0591SJens Wiklander #endif 3303d3b0591SJens Wiklander /* 3313d3b0591SJens Wiklander * Accounting for everything up to the end of the loop 3323d3b0591SJens Wiklander * (step 6, but checking now avoids saving e and t) 3333d3b0591SJens Wiklander */ 3343d3b0591SJens Wiklander ECDSA_BUDGET(MBEDTLS_ECP_OPS_INV + 4); 335817466cbSJens Wiklander 336817466cbSJens Wiklander /* 337817466cbSJens Wiklander * Step 5: derive MPI from hashed message 338817466cbSJens Wiklander */ 339817466cbSJens Wiklander MBEDTLS_MPI_CHK(derive_mpi(grp, &e, buf, blen)); 340817466cbSJens Wiklander 341817466cbSJens Wiklander /* 342817466cbSJens Wiklander * Generate a random value to blind inv_mod in next step, 343817466cbSJens Wiklander * avoiding a potential timing leak. 344817466cbSJens Wiklander */ 3455b25c76aSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_ecp_gen_privkey(grp, &t, f_rng_blind, 3465b25c76aSJerome Forissier p_rng_blind)); 347817466cbSJens Wiklander 348817466cbSJens Wiklander /* 349817466cbSJens Wiklander * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n 350817466cbSJens Wiklander */ 3513d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(s, pr, d)); 352817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&e, &e, s)); 353817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&e, &e, &t)); 3543d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(pk, pk, &t)); 3555b25c76aSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(pk, pk, &grp->N)); 3563d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(s, pk, &grp->N)); 357817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(s, s, &e)); 358817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(s, s, &grp->N)); 359*32b31808SJens Wiklander } while (mbedtls_mpi_cmp_int(s, 0) == 0); 360817466cbSJens Wiklander 3613d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 362*32b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->sig != NULL) { 3633d3b0591SJens Wiklander mbedtls_mpi_copy(r, pr); 364*32b31808SJens Wiklander } 3653d3b0591SJens Wiklander #endif 3663d3b0591SJens Wiklander 367817466cbSJens Wiklander cleanup: 368817466cbSJens Wiklander mbedtls_ecp_point_free(&R); 369817466cbSJens Wiklander mbedtls_mpi_free(&k); mbedtls_mpi_free(&e); mbedtls_mpi_free(&t); 370817466cbSJens Wiklander 3713d3b0591SJens Wiklander ECDSA_RS_LEAVE(sig); 3723d3b0591SJens Wiklander 373*32b31808SJens Wiklander return ret; 374817466cbSJens Wiklander } 375817466cbSJens Wiklander 37611fa71b9SJerome Forissier int mbedtls_ecdsa_can_do(mbedtls_ecp_group_id gid) 37711fa71b9SJerome Forissier { 378*32b31808SJens Wiklander switch (gid) { 37911fa71b9SJerome Forissier #ifdef MBEDTLS_ECP_DP_CURVE25519_ENABLED 38011fa71b9SJerome Forissier case MBEDTLS_ECP_DP_CURVE25519: return 0; 38111fa71b9SJerome Forissier #endif 38211fa71b9SJerome Forissier #ifdef MBEDTLS_ECP_DP_CURVE448_ENABLED 38311fa71b9SJerome Forissier case MBEDTLS_ECP_DP_CURVE448: return 0; 38411fa71b9SJerome Forissier #endif 38511fa71b9SJerome Forissier default: return 1; 38611fa71b9SJerome Forissier } 38711fa71b9SJerome Forissier } 38811fa71b9SJerome Forissier 3893d3b0591SJens Wiklander /* 3903d3b0591SJens Wiklander * Compute ECDSA signature of a hashed message 3913d3b0591SJens Wiklander */ 3923d3b0591SJens Wiklander int mbedtls_ecdsa_sign(mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, 3933d3b0591SJens Wiklander const mbedtls_mpi *d, const unsigned char *buf, size_t blen, 3943d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) 3953d3b0591SJens Wiklander { 3965b25c76aSJerome Forissier /* Use the same RNG for both blinding and ephemeral key generation */ 397*32b31808SJens Wiklander return mbedtls_ecdsa_sign_restartable(grp, r, s, d, buf, blen, 398*32b31808SJens Wiklander f_rng, p_rng, f_rng, p_rng, NULL); 3993d3b0591SJens Wiklander } 4003d3b0591SJens Wiklander #endif /* !MBEDTLS_ECDSA_SIGN_ALT */ 4013d3b0591SJens Wiklander 402817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC) 403817466cbSJens Wiklander /* 404817466cbSJens Wiklander * Deterministic signature wrapper 405*32b31808SJens Wiklander * 406*32b31808SJens Wiklander * note: The f_rng_blind parameter must not be NULL. 407*32b31808SJens Wiklander * 408817466cbSJens Wiklander */ 409*32b31808SJens Wiklander int mbedtls_ecdsa_sign_det_restartable(mbedtls_ecp_group *grp, 4103d3b0591SJens Wiklander mbedtls_mpi *r, mbedtls_mpi *s, 411817466cbSJens Wiklander const mbedtls_mpi *d, const unsigned char *buf, size_t blen, 4123d3b0591SJens Wiklander mbedtls_md_type_t md_alg, 4135b25c76aSJerome Forissier int (*f_rng_blind)(void *, unsigned char *, size_t), 4145b25c76aSJerome Forissier void *p_rng_blind, 4153d3b0591SJens Wiklander mbedtls_ecdsa_restart_ctx *rs_ctx) 416817466cbSJens Wiklander { 41711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 418817466cbSJens Wiklander mbedtls_hmac_drbg_context rng_ctx; 4193d3b0591SJens Wiklander mbedtls_hmac_drbg_context *p_rng = &rng_ctx; 420817466cbSJens Wiklander unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES]; 421817466cbSJens Wiklander size_t grp_len = (grp->nbits + 7) / 8; 422817466cbSJens Wiklander const mbedtls_md_info_t *md_info; 423817466cbSJens Wiklander mbedtls_mpi h; 424817466cbSJens Wiklander 425*32b31808SJens Wiklander if ((md_info = mbedtls_md_info_from_type(md_alg)) == NULL) { 426*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 427*32b31808SJens Wiklander } 428817466cbSJens Wiklander 429817466cbSJens Wiklander mbedtls_mpi_init(&h); 430817466cbSJens Wiklander mbedtls_hmac_drbg_init(&rng_ctx); 431817466cbSJens Wiklander 4323d3b0591SJens Wiklander ECDSA_RS_ENTER(det); 4333d3b0591SJens Wiklander 4343d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 435*32b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->det != NULL) { 4363d3b0591SJens Wiklander /* redirect to our context */ 4373d3b0591SJens Wiklander p_rng = &rs_ctx->det->rng_ctx; 4383d3b0591SJens Wiklander 4393d3b0591SJens Wiklander /* jump to current step */ 440*32b31808SJens Wiklander if (rs_ctx->det->state == ecdsa_det_sign) { 4413d3b0591SJens Wiklander goto sign; 4423d3b0591SJens Wiklander } 443*32b31808SJens Wiklander } 4443d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 4453d3b0591SJens Wiklander 446817466cbSJens Wiklander /* Use private key and message hash (reduced) to initialize HMAC_DRBG */ 447817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(d, data, grp_len)); 448817466cbSJens Wiklander MBEDTLS_MPI_CHK(derive_mpi(grp, &h, buf, blen)); 449817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&h, data + grp_len, grp_len)); 4503d3b0591SJens Wiklander mbedtls_hmac_drbg_seed_buf(p_rng, md_info, data, 2 * grp_len); 451817466cbSJens Wiklander 4523d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 453*32b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->det != NULL) { 4543d3b0591SJens Wiklander rs_ctx->det->state = ecdsa_det_sign; 455*32b31808SJens Wiklander } 4563d3b0591SJens Wiklander 4573d3b0591SJens Wiklander sign: 4583d3b0591SJens Wiklander #endif 4593d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_SIGN_ALT) 4607901324dSJerome Forissier (void) f_rng_blind; 4617901324dSJerome Forissier (void) p_rng_blind; 462817466cbSJens Wiklander ret = mbedtls_ecdsa_sign(grp, r, s, d, buf, blen, 4633d3b0591SJens Wiklander mbedtls_hmac_drbg_random, p_rng); 4643d3b0591SJens Wiklander #else 465*32b31808SJens Wiklander ret = mbedtls_ecdsa_sign_restartable(grp, r, s, d, buf, blen, 4665b25c76aSJerome Forissier mbedtls_hmac_drbg_random, p_rng, 4675b25c76aSJerome Forissier f_rng_blind, p_rng_blind, rs_ctx); 4683d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_SIGN_ALT */ 469817466cbSJens Wiklander 470817466cbSJens Wiklander cleanup: 471817466cbSJens Wiklander mbedtls_hmac_drbg_free(&rng_ctx); 472817466cbSJens Wiklander mbedtls_mpi_free(&h); 473817466cbSJens Wiklander 4743d3b0591SJens Wiklander ECDSA_RS_LEAVE(det); 4753d3b0591SJens Wiklander 476*32b31808SJens Wiklander return ret; 477817466cbSJens Wiklander } 4783d3b0591SJens Wiklander 4793d3b0591SJens Wiklander /* 480*32b31808SJens Wiklander * Deterministic signature wrapper 4813d3b0591SJens Wiklander */ 4825b25c76aSJerome Forissier int mbedtls_ecdsa_sign_det_ext(mbedtls_ecp_group *grp, mbedtls_mpi *r, 4835b25c76aSJerome Forissier mbedtls_mpi *s, const mbedtls_mpi *d, 4845b25c76aSJerome Forissier const unsigned char *buf, size_t blen, 4855b25c76aSJerome Forissier mbedtls_md_type_t md_alg, 4865b25c76aSJerome Forissier int (*f_rng_blind)(void *, unsigned char *, 4875b25c76aSJerome Forissier size_t), 4885b25c76aSJerome Forissier void *p_rng_blind) 4895b25c76aSJerome Forissier { 490*32b31808SJens Wiklander return mbedtls_ecdsa_sign_det_restartable(grp, r, s, d, buf, blen, md_alg, 491*32b31808SJens Wiklander f_rng_blind, p_rng_blind, NULL); 4923d3b0591SJens Wiklander } 493817466cbSJens Wiklander #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ 494817466cbSJens Wiklander 4953d3b0591SJens Wiklander #if !defined(MBEDTLS_ECDSA_VERIFY_ALT) 496817466cbSJens Wiklander /* 497817466cbSJens Wiklander * Verify ECDSA signature of hashed message (SEC1 4.1.4) 498817466cbSJens Wiklander * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message) 499817466cbSJens Wiklander */ 500*32b31808SJens Wiklander int mbedtls_ecdsa_verify_restartable(mbedtls_ecp_group *grp, 501817466cbSJens Wiklander const unsigned char *buf, size_t blen, 5023d3b0591SJens Wiklander const mbedtls_ecp_point *Q, 503*32b31808SJens Wiklander const mbedtls_mpi *r, 504*32b31808SJens Wiklander const mbedtls_mpi *s, 5053d3b0591SJens Wiklander mbedtls_ecdsa_restart_ctx *rs_ctx) 506817466cbSJens Wiklander { 50711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 508817466cbSJens Wiklander mbedtls_mpi e, s_inv, u1, u2; 509817466cbSJens Wiklander mbedtls_ecp_point R; 5103d3b0591SJens Wiklander mbedtls_mpi *pu1 = &u1, *pu2 = &u2; 511817466cbSJens Wiklander 512817466cbSJens Wiklander mbedtls_ecp_point_init(&R); 5133d3b0591SJens Wiklander mbedtls_mpi_init(&e); mbedtls_mpi_init(&s_inv); 5143d3b0591SJens Wiklander mbedtls_mpi_init(&u1); mbedtls_mpi_init(&u2); 515817466cbSJens Wiklander 516817466cbSJens Wiklander /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ 517*32b31808SJens Wiklander if (!mbedtls_ecdsa_can_do(grp->id) || grp->N.p == NULL) { 518*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 519*32b31808SJens Wiklander } 520817466cbSJens Wiklander 5213d3b0591SJens Wiklander ECDSA_RS_ENTER(ver); 5223d3b0591SJens Wiklander 5233d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 524*32b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->ver != NULL) { 5253d3b0591SJens Wiklander /* redirect to our context */ 5263d3b0591SJens Wiklander pu1 = &rs_ctx->ver->u1; 5273d3b0591SJens Wiklander pu2 = &rs_ctx->ver->u2; 5283d3b0591SJens Wiklander 5293d3b0591SJens Wiklander /* jump to current step */ 530*32b31808SJens Wiklander if (rs_ctx->ver->state == ecdsa_ver_muladd) { 5313d3b0591SJens Wiklander goto muladd; 5323d3b0591SJens Wiklander } 533*32b31808SJens Wiklander } 5343d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 5353d3b0591SJens Wiklander 536817466cbSJens Wiklander /* 537817466cbSJens Wiklander * Step 1: make sure r and s are in range 1..n-1 538817466cbSJens Wiklander */ 539817466cbSJens Wiklander if (mbedtls_mpi_cmp_int(r, 1) < 0 || mbedtls_mpi_cmp_mpi(r, &grp->N) >= 0 || 540*32b31808SJens Wiklander mbedtls_mpi_cmp_int(s, 1) < 0 || mbedtls_mpi_cmp_mpi(s, &grp->N) >= 0) { 541817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; 542817466cbSJens Wiklander goto cleanup; 543817466cbSJens Wiklander } 544817466cbSJens Wiklander 545817466cbSJens Wiklander /* 546817466cbSJens Wiklander * Step 3: derive MPI from hashed message 547817466cbSJens Wiklander */ 548817466cbSJens Wiklander MBEDTLS_MPI_CHK(derive_mpi(grp, &e, buf, blen)); 549817466cbSJens Wiklander 550817466cbSJens Wiklander /* 551817466cbSJens Wiklander * Step 4: u1 = e / s mod n, u2 = r / s mod n 552817466cbSJens Wiklander */ 5533d3b0591SJens Wiklander ECDSA_BUDGET(MBEDTLS_ECP_OPS_CHK + MBEDTLS_ECP_OPS_INV + 2); 5543d3b0591SJens Wiklander 555817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&s_inv, s, &grp->N)); 556817466cbSJens Wiklander 5573d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(pu1, &e, &s_inv)); 5583d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(pu1, pu1, &grp->N)); 559817466cbSJens Wiklander 5603d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(pu2, r, &s_inv)); 5613d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(pu2, pu2, &grp->N)); 562817466cbSJens Wiklander 5633d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 564*32b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->ver != NULL) { 5653d3b0591SJens Wiklander rs_ctx->ver->state = ecdsa_ver_muladd; 566*32b31808SJens Wiklander } 5673d3b0591SJens Wiklander 5683d3b0591SJens Wiklander muladd: 5693d3b0591SJens Wiklander #endif 570817466cbSJens Wiklander /* 571817466cbSJens Wiklander * Step 5: R = u1 G + u2 Q 572817466cbSJens Wiklander */ 5733d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_muladd_restartable(grp, 5743d3b0591SJens Wiklander &R, pu1, &grp->G, pu2, Q, ECDSA_RS_ECP)); 575817466cbSJens Wiklander 576*32b31808SJens Wiklander if (mbedtls_ecp_is_zero(&R)) { 577817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; 578817466cbSJens Wiklander goto cleanup; 579817466cbSJens Wiklander } 580817466cbSJens Wiklander 581817466cbSJens Wiklander /* 582817466cbSJens Wiklander * Step 6: convert xR to an integer (no-op) 583817466cbSJens Wiklander * Step 7: reduce xR mod n (gives v) 584817466cbSJens Wiklander */ 585817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&R.X, &R.X, &grp->N)); 586817466cbSJens Wiklander 587817466cbSJens Wiklander /* 588817466cbSJens Wiklander * Step 8: check if v (that is, R.X) is equal to r 589817466cbSJens Wiklander */ 590*32b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(&R.X, r) != 0) { 591817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; 592817466cbSJens Wiklander goto cleanup; 593817466cbSJens Wiklander } 594817466cbSJens Wiklander 595817466cbSJens Wiklander cleanup: 596817466cbSJens Wiklander mbedtls_ecp_point_free(&R); 5973d3b0591SJens Wiklander mbedtls_mpi_free(&e); mbedtls_mpi_free(&s_inv); 5983d3b0591SJens Wiklander mbedtls_mpi_free(&u1); mbedtls_mpi_free(&u2); 5993d3b0591SJens Wiklander 6003d3b0591SJens Wiklander ECDSA_RS_LEAVE(ver); 601817466cbSJens Wiklander 602*32b31808SJens Wiklander return ret; 603817466cbSJens Wiklander } 604817466cbSJens Wiklander 605817466cbSJens Wiklander /* 6063d3b0591SJens Wiklander * Verify ECDSA signature of hashed message 6073d3b0591SJens Wiklander */ 6083d3b0591SJens Wiklander int mbedtls_ecdsa_verify(mbedtls_ecp_group *grp, 6093d3b0591SJens Wiklander const unsigned char *buf, size_t blen, 6103d3b0591SJens Wiklander const mbedtls_ecp_point *Q, 6113d3b0591SJens Wiklander const mbedtls_mpi *r, 6123d3b0591SJens Wiklander const mbedtls_mpi *s) 6133d3b0591SJens Wiklander { 614*32b31808SJens Wiklander return mbedtls_ecdsa_verify_restartable(grp, buf, blen, Q, r, s, NULL); 6153d3b0591SJens Wiklander } 6163d3b0591SJens Wiklander #endif /* !MBEDTLS_ECDSA_VERIFY_ALT */ 6173d3b0591SJens Wiklander 6183d3b0591SJens Wiklander /* 619817466cbSJens Wiklander * Convert a signature (given by context) to ASN.1 620817466cbSJens Wiklander */ 621817466cbSJens Wiklander static int ecdsa_signature_to_asn1(const mbedtls_mpi *r, const mbedtls_mpi *s, 622*32b31808SJens Wiklander unsigned char *sig, size_t sig_size, 623*32b31808SJens Wiklander size_t *slen) 624817466cbSJens Wiklander { 62511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 6267901324dSJerome Forissier unsigned char buf[MBEDTLS_ECDSA_MAX_LEN] = { 0 }; 627817466cbSJens Wiklander unsigned char *p = buf + sizeof(buf); 628817466cbSJens Wiklander size_t len = 0; 629817466cbSJens Wiklander 630817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_mpi(&p, buf, s)); 631817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_mpi(&p, buf, r)); 632817466cbSJens Wiklander 633817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&p, buf, len)); 634817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&p, buf, 635*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | 636*32b31808SJens Wiklander MBEDTLS_ASN1_SEQUENCE)); 637*32b31808SJens Wiklander 638*32b31808SJens Wiklander if (len > sig_size) { 639*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 640*32b31808SJens Wiklander } 641817466cbSJens Wiklander 642817466cbSJens Wiklander memcpy(sig, p, len); 643817466cbSJens Wiklander *slen = len; 644817466cbSJens Wiklander 645*32b31808SJens Wiklander return 0; 646817466cbSJens Wiklander } 647817466cbSJens Wiklander 648817466cbSJens Wiklander /* 649817466cbSJens Wiklander * Compute and write signature 650817466cbSJens Wiklander */ 6513d3b0591SJens Wiklander int mbedtls_ecdsa_write_signature_restartable(mbedtls_ecdsa_context *ctx, 6523d3b0591SJens Wiklander mbedtls_md_type_t md_alg, 653817466cbSJens Wiklander const unsigned char *hash, size_t hlen, 654*32b31808SJens Wiklander unsigned char *sig, size_t sig_size, size_t *slen, 655817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 6563d3b0591SJens Wiklander void *p_rng, 6573d3b0591SJens Wiklander mbedtls_ecdsa_restart_ctx *rs_ctx) 658817466cbSJens Wiklander { 65911fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 660817466cbSJens Wiklander mbedtls_mpi r, s; 661*32b31808SJens Wiklander if (f_rng == NULL) { 662*32b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 663*32b31808SJens Wiklander } 664817466cbSJens Wiklander 665817466cbSJens Wiklander mbedtls_mpi_init(&r); 666817466cbSJens Wiklander mbedtls_mpi_init(&s); 667817466cbSJens Wiklander 668817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC) 669*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecdsa_sign_det_restartable(&ctx->grp, &r, &s, &ctx->d, 6705b25c76aSJerome Forissier hash, hlen, md_alg, f_rng, 6715b25c76aSJerome Forissier p_rng, rs_ctx)); 672817466cbSJens Wiklander #else 673817466cbSJens Wiklander (void) md_alg; 674817466cbSJens Wiklander 6753d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_SIGN_ALT) 6767901324dSJerome Forissier (void) rs_ctx; 6777901324dSJerome Forissier 678817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecdsa_sign(&ctx->grp, &r, &s, &ctx->d, 679817466cbSJens Wiklander hash, hlen, f_rng, p_rng)); 6803d3b0591SJens Wiklander #else 6815b25c76aSJerome Forissier /* Use the same RNG for both blinding and ephemeral key generation */ 682*32b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecdsa_sign_restartable(&ctx->grp, &r, &s, &ctx->d, 6835b25c76aSJerome Forissier hash, hlen, f_rng, p_rng, f_rng, 6845b25c76aSJerome Forissier p_rng, rs_ctx)); 6853d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_SIGN_ALT */ 6863d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ 687817466cbSJens Wiklander 688*32b31808SJens Wiklander MBEDTLS_MPI_CHK(ecdsa_signature_to_asn1(&r, &s, sig, sig_size, slen)); 689817466cbSJens Wiklander 690817466cbSJens Wiklander cleanup: 691817466cbSJens Wiklander mbedtls_mpi_free(&r); 692817466cbSJens Wiklander mbedtls_mpi_free(&s); 693817466cbSJens Wiklander 694*32b31808SJens Wiklander return ret; 695817466cbSJens Wiklander } 696817466cbSJens Wiklander 6973d3b0591SJens Wiklander /* 6983d3b0591SJens Wiklander * Compute and write signature 6993d3b0591SJens Wiklander */ 7003d3b0591SJens Wiklander int mbedtls_ecdsa_write_signature(mbedtls_ecdsa_context *ctx, 7013d3b0591SJens Wiklander mbedtls_md_type_t md_alg, 7023d3b0591SJens Wiklander const unsigned char *hash, size_t hlen, 703*32b31808SJens Wiklander unsigned char *sig, size_t sig_size, size_t *slen, 7043d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 7053d3b0591SJens Wiklander void *p_rng) 7063d3b0591SJens Wiklander { 707*32b31808SJens Wiklander return mbedtls_ecdsa_write_signature_restartable( 708*32b31808SJens Wiklander ctx, md_alg, hash, hlen, sig, sig_size, slen, 709*32b31808SJens Wiklander f_rng, p_rng, NULL); 7103d3b0591SJens Wiklander } 7113d3b0591SJens Wiklander 712817466cbSJens Wiklander /* 713817466cbSJens Wiklander * Read and check signature 714817466cbSJens Wiklander */ 715817466cbSJens Wiklander int mbedtls_ecdsa_read_signature(mbedtls_ecdsa_context *ctx, 716817466cbSJens Wiklander const unsigned char *hash, size_t hlen, 717817466cbSJens Wiklander const unsigned char *sig, size_t slen) 718817466cbSJens Wiklander { 719*32b31808SJens Wiklander return mbedtls_ecdsa_read_signature_restartable( 720*32b31808SJens Wiklander ctx, hash, hlen, sig, slen, NULL); 7213d3b0591SJens Wiklander } 7223d3b0591SJens Wiklander 7233d3b0591SJens Wiklander /* 7243d3b0591SJens Wiklander * Restartable read and check signature 7253d3b0591SJens Wiklander */ 7263d3b0591SJens Wiklander int mbedtls_ecdsa_read_signature_restartable(mbedtls_ecdsa_context *ctx, 7273d3b0591SJens Wiklander const unsigned char *hash, size_t hlen, 7283d3b0591SJens Wiklander const unsigned char *sig, size_t slen, 7293d3b0591SJens Wiklander mbedtls_ecdsa_restart_ctx *rs_ctx) 7303d3b0591SJens Wiklander { 73111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 732817466cbSJens Wiklander unsigned char *p = (unsigned char *) sig; 733817466cbSJens Wiklander const unsigned char *end = sig + slen; 734817466cbSJens Wiklander size_t len; 735817466cbSJens Wiklander mbedtls_mpi r, s; 736817466cbSJens Wiklander mbedtls_mpi_init(&r); 737817466cbSJens Wiklander mbedtls_mpi_init(&s); 738817466cbSJens Wiklander 739817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len, 740*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 741817466cbSJens Wiklander ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 742817466cbSJens Wiklander goto cleanup; 743817466cbSJens Wiklander } 744817466cbSJens Wiklander 745*32b31808SJens Wiklander if (p + len != end) { 7467901324dSJerome Forissier ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_ECP_BAD_INPUT_DATA, 7477901324dSJerome Forissier MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 748817466cbSJens Wiklander goto cleanup; 749817466cbSJens Wiklander } 750817466cbSJens Wiklander 751817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_mpi(&p, end, &r)) != 0 || 752*32b31808SJens Wiklander (ret = mbedtls_asn1_get_mpi(&p, end, &s)) != 0) { 753817466cbSJens Wiklander ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 754817466cbSJens Wiklander goto cleanup; 755817466cbSJens Wiklander } 7563d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_VERIFY_ALT) 7577901324dSJerome Forissier (void) rs_ctx; 7587901324dSJerome Forissier 759817466cbSJens Wiklander if ((ret = mbedtls_ecdsa_verify(&ctx->grp, hash, hlen, 760*32b31808SJens Wiklander &ctx->Q, &r, &s)) != 0) { 761817466cbSJens Wiklander goto cleanup; 762*32b31808SJens Wiklander } 7633d3b0591SJens Wiklander #else 764*32b31808SJens Wiklander if ((ret = mbedtls_ecdsa_verify_restartable(&ctx->grp, hash, hlen, 765*32b31808SJens Wiklander &ctx->Q, &r, &s, rs_ctx)) != 0) { 7663d3b0591SJens Wiklander goto cleanup; 767*32b31808SJens Wiklander } 7683d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_VERIFY_ALT */ 769817466cbSJens Wiklander 7703d3b0591SJens Wiklander /* At this point we know that the buffer starts with a valid signature. 7713d3b0591SJens Wiklander * Return 0 if the buffer just contains the signature, and a specific 7723d3b0591SJens Wiklander * error code if the valid signature is followed by more data. */ 773*32b31808SJens Wiklander if (p != end) { 774817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH; 775*32b31808SJens Wiklander } 776817466cbSJens Wiklander 777817466cbSJens Wiklander cleanup: 778817466cbSJens Wiklander mbedtls_mpi_free(&r); 779817466cbSJens Wiklander mbedtls_mpi_free(&s); 780817466cbSJens Wiklander 781*32b31808SJens Wiklander return ret; 782817466cbSJens Wiklander } 783817466cbSJens Wiklander 7843d3b0591SJens Wiklander #if !defined(MBEDTLS_ECDSA_GENKEY_ALT) 785817466cbSJens Wiklander /* 786817466cbSJens Wiklander * Generate key pair 787817466cbSJens Wiklander */ 788817466cbSJens Wiklander int mbedtls_ecdsa_genkey(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, 789817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) 790817466cbSJens Wiklander { 7915b25c76aSJerome Forissier int ret = 0; 7925b25c76aSJerome Forissier ret = mbedtls_ecp_group_load(&ctx->grp, gid); 793*32b31808SJens Wiklander if (ret != 0) { 794*32b31808SJens Wiklander return ret; 795*32b31808SJens Wiklander } 7965b25c76aSJerome Forissier 797*32b31808SJens Wiklander return mbedtls_ecp_gen_keypair(&ctx->grp, &ctx->d, 798*32b31808SJens Wiklander &ctx->Q, f_rng, p_rng); 799817466cbSJens Wiklander } 8003d3b0591SJens Wiklander #endif /* !MBEDTLS_ECDSA_GENKEY_ALT */ 801817466cbSJens Wiklander 802817466cbSJens Wiklander /* 803817466cbSJens Wiklander * Set context from an mbedtls_ecp_keypair 804817466cbSJens Wiklander */ 805817466cbSJens Wiklander int mbedtls_ecdsa_from_keypair(mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key) 806817466cbSJens Wiklander { 80711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 808817466cbSJens Wiklander if ((ret = mbedtls_ecp_group_copy(&ctx->grp, &key->grp)) != 0 || 809817466cbSJens Wiklander (ret = mbedtls_mpi_copy(&ctx->d, &key->d)) != 0 || 810*32b31808SJens Wiklander (ret = mbedtls_ecp_copy(&ctx->Q, &key->Q)) != 0) { 811817466cbSJens Wiklander mbedtls_ecdsa_free(ctx); 812817466cbSJens Wiklander } 813817466cbSJens Wiklander 814*32b31808SJens Wiklander return ret; 815817466cbSJens Wiklander } 816817466cbSJens Wiklander 817817466cbSJens Wiklander /* 818817466cbSJens Wiklander * Initialize context 819817466cbSJens Wiklander */ 820817466cbSJens Wiklander void mbedtls_ecdsa_init(mbedtls_ecdsa_context *ctx) 821817466cbSJens Wiklander { 822817466cbSJens Wiklander mbedtls_ecp_keypair_init(ctx); 823817466cbSJens Wiklander } 824817466cbSJens Wiklander 825817466cbSJens Wiklander /* 826817466cbSJens Wiklander * Free context 827817466cbSJens Wiklander */ 828817466cbSJens Wiklander void mbedtls_ecdsa_free(mbedtls_ecdsa_context *ctx) 829817466cbSJens Wiklander { 830*32b31808SJens Wiklander if (ctx == NULL) { 8313d3b0591SJens Wiklander return; 832*32b31808SJens Wiklander } 8333d3b0591SJens Wiklander 834817466cbSJens Wiklander mbedtls_ecp_keypair_free(ctx); 835817466cbSJens Wiklander } 836817466cbSJens Wiklander 8373d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 8383d3b0591SJens Wiklander /* 8393d3b0591SJens Wiklander * Initialize a restart context 8403d3b0591SJens Wiklander */ 8413d3b0591SJens Wiklander void mbedtls_ecdsa_restart_init(mbedtls_ecdsa_restart_ctx *ctx) 8423d3b0591SJens Wiklander { 8433d3b0591SJens Wiklander mbedtls_ecp_restart_init(&ctx->ecp); 8443d3b0591SJens Wiklander 8453d3b0591SJens Wiklander ctx->ver = NULL; 8463d3b0591SJens Wiklander ctx->sig = NULL; 8473d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC) 8483d3b0591SJens Wiklander ctx->det = NULL; 8493d3b0591SJens Wiklander #endif 8503d3b0591SJens Wiklander } 8513d3b0591SJens Wiklander 8523d3b0591SJens Wiklander /* 8533d3b0591SJens Wiklander * Free the components of a restart context 8543d3b0591SJens Wiklander */ 8553d3b0591SJens Wiklander void mbedtls_ecdsa_restart_free(mbedtls_ecdsa_restart_ctx *ctx) 8563d3b0591SJens Wiklander { 857*32b31808SJens Wiklander if (ctx == NULL) { 8583d3b0591SJens Wiklander return; 859*32b31808SJens Wiklander } 8603d3b0591SJens Wiklander 8613d3b0591SJens Wiklander mbedtls_ecp_restart_free(&ctx->ecp); 8623d3b0591SJens Wiklander 8633d3b0591SJens Wiklander ecdsa_restart_ver_free(ctx->ver); 8643d3b0591SJens Wiklander mbedtls_free(ctx->ver); 8653d3b0591SJens Wiklander ctx->ver = NULL; 8663d3b0591SJens Wiklander 8673d3b0591SJens Wiklander ecdsa_restart_sig_free(ctx->sig); 8683d3b0591SJens Wiklander mbedtls_free(ctx->sig); 8693d3b0591SJens Wiklander ctx->sig = NULL; 8703d3b0591SJens Wiklander 8713d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC) 8723d3b0591SJens Wiklander ecdsa_restart_det_free(ctx->det); 8733d3b0591SJens Wiklander mbedtls_free(ctx->det); 8743d3b0591SJens Wiklander ctx->det = NULL; 8753d3b0591SJens Wiklander #endif 8763d3b0591SJens Wiklander } 8773d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 8783d3b0591SJens Wiklander 879817466cbSJens Wiklander #endif /* MBEDTLS_ECDSA_C */ 880