xref: /optee_os/lib/libmbedtls/mbedtls/library/ecdsa.c (revision 32b3180828fa15a49ccc86ecb4be9d274c140c89)
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