1c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0 2817466cbSJens Wiklander /* 3817466cbSJens Wiklander * Elliptic curve DSA 4817466cbSJens Wiklander * 5817466cbSJens Wiklander * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 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 * This file is part of mbed TLS (https://tls.mbed.org) 20817466cbSJens Wiklander */ 21817466cbSJens Wiklander 22817466cbSJens Wiklander /* 23817466cbSJens Wiklander * References: 24817466cbSJens Wiklander * 25817466cbSJens Wiklander * SEC1 http://www.secg.org/index.php?action=secg,docs_secg 26817466cbSJens Wiklander */ 27817466cbSJens Wiklander 28817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 29817466cbSJens Wiklander #include "mbedtls/config.h" 30817466cbSJens Wiklander #else 31817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE 32817466cbSJens Wiklander #endif 33817466cbSJens Wiklander 34817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_C) 35817466cbSJens Wiklander 36817466cbSJens Wiklander #include "mbedtls/ecdsa.h" 37817466cbSJens Wiklander #include "mbedtls/asn1write.h" 38817466cbSJens Wiklander 39817466cbSJens Wiklander #include <string.h> 40817466cbSJens Wiklander 41817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC) 42817466cbSJens Wiklander #include "mbedtls/hmac_drbg.h" 43817466cbSJens Wiklander #endif 44817466cbSJens Wiklander 45*3d3b0591SJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 46*3d3b0591SJens Wiklander #include "mbedtls/platform.h" 47*3d3b0591SJens Wiklander #else 48*3d3b0591SJens Wiklander #include <stdlib.h> 49*3d3b0591SJens Wiklander #define mbedtls_calloc calloc 50*3d3b0591SJens Wiklander #define mbedtls_free free 51*3d3b0591SJens Wiklander #endif 52*3d3b0591SJens Wiklander 53*3d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 54*3d3b0591SJens Wiklander 55*3d3b0591SJens Wiklander /* Parameter validation macros based on platform_util.h */ 56*3d3b0591SJens Wiklander #define ECDSA_VALIDATE_RET( cond ) \ 57*3d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) 58*3d3b0591SJens Wiklander #define ECDSA_VALIDATE( cond ) \ 59*3d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE( cond ) 60*3d3b0591SJens Wiklander 61*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 62*3d3b0591SJens Wiklander 63*3d3b0591SJens Wiklander /* 64*3d3b0591SJens Wiklander * Sub-context for ecdsa_verify() 65*3d3b0591SJens Wiklander */ 66*3d3b0591SJens Wiklander struct mbedtls_ecdsa_restart_ver 67*3d3b0591SJens Wiklander { 68*3d3b0591SJens Wiklander mbedtls_mpi u1, u2; /* intermediate values */ 69*3d3b0591SJens Wiklander enum { /* what to do next? */ 70*3d3b0591SJens Wiklander ecdsa_ver_init = 0, /* getting started */ 71*3d3b0591SJens Wiklander ecdsa_ver_muladd, /* muladd step */ 72*3d3b0591SJens Wiklander } state; 73*3d3b0591SJens Wiklander }; 74*3d3b0591SJens Wiklander 75*3d3b0591SJens Wiklander /* 76*3d3b0591SJens Wiklander * Init verify restart sub-context 77*3d3b0591SJens Wiklander */ 78*3d3b0591SJens Wiklander static void ecdsa_restart_ver_init( mbedtls_ecdsa_restart_ver_ctx *ctx ) 79*3d3b0591SJens Wiklander { 80*3d3b0591SJens Wiklander mbedtls_mpi_init( &ctx->u1 ); 81*3d3b0591SJens Wiklander mbedtls_mpi_init( &ctx->u2 ); 82*3d3b0591SJens Wiklander ctx->state = ecdsa_ver_init; 83*3d3b0591SJens Wiklander } 84*3d3b0591SJens Wiklander 85*3d3b0591SJens Wiklander /* 86*3d3b0591SJens Wiklander * Free the components of a verify restart sub-context 87*3d3b0591SJens Wiklander */ 88*3d3b0591SJens Wiklander static void ecdsa_restart_ver_free( mbedtls_ecdsa_restart_ver_ctx *ctx ) 89*3d3b0591SJens Wiklander { 90*3d3b0591SJens Wiklander if( ctx == NULL ) 91*3d3b0591SJens Wiklander return; 92*3d3b0591SJens Wiklander 93*3d3b0591SJens Wiklander mbedtls_mpi_free( &ctx->u1 ); 94*3d3b0591SJens Wiklander mbedtls_mpi_free( &ctx->u2 ); 95*3d3b0591SJens Wiklander 96*3d3b0591SJens Wiklander ecdsa_restart_ver_init( ctx ); 97*3d3b0591SJens Wiklander } 98*3d3b0591SJens Wiklander 99*3d3b0591SJens Wiklander /* 100*3d3b0591SJens Wiklander * Sub-context for ecdsa_sign() 101*3d3b0591SJens Wiklander */ 102*3d3b0591SJens Wiklander struct mbedtls_ecdsa_restart_sig 103*3d3b0591SJens Wiklander { 104*3d3b0591SJens Wiklander int sign_tries; 105*3d3b0591SJens Wiklander int key_tries; 106*3d3b0591SJens Wiklander mbedtls_mpi k; /* per-signature random */ 107*3d3b0591SJens Wiklander mbedtls_mpi r; /* r value */ 108*3d3b0591SJens Wiklander enum { /* what to do next? */ 109*3d3b0591SJens Wiklander ecdsa_sig_init = 0, /* getting started */ 110*3d3b0591SJens Wiklander ecdsa_sig_mul, /* doing ecp_mul() */ 111*3d3b0591SJens Wiklander ecdsa_sig_modn, /* mod N computations */ 112*3d3b0591SJens Wiklander } state; 113*3d3b0591SJens Wiklander }; 114*3d3b0591SJens Wiklander 115*3d3b0591SJens Wiklander /* 116*3d3b0591SJens Wiklander * Init verify sign sub-context 117*3d3b0591SJens Wiklander */ 118*3d3b0591SJens Wiklander static void ecdsa_restart_sig_init( mbedtls_ecdsa_restart_sig_ctx *ctx ) 119*3d3b0591SJens Wiklander { 120*3d3b0591SJens Wiklander ctx->sign_tries = 0; 121*3d3b0591SJens Wiklander ctx->key_tries = 0; 122*3d3b0591SJens Wiklander mbedtls_mpi_init( &ctx->k ); 123*3d3b0591SJens Wiklander mbedtls_mpi_init( &ctx->r ); 124*3d3b0591SJens Wiklander ctx->state = ecdsa_sig_init; 125*3d3b0591SJens Wiklander } 126*3d3b0591SJens Wiklander 127*3d3b0591SJens Wiklander /* 128*3d3b0591SJens Wiklander * Free the components of a sign restart sub-context 129*3d3b0591SJens Wiklander */ 130*3d3b0591SJens Wiklander static void ecdsa_restart_sig_free( mbedtls_ecdsa_restart_sig_ctx *ctx ) 131*3d3b0591SJens Wiklander { 132*3d3b0591SJens Wiklander if( ctx == NULL ) 133*3d3b0591SJens Wiklander return; 134*3d3b0591SJens Wiklander 135*3d3b0591SJens Wiklander mbedtls_mpi_free( &ctx->k ); 136*3d3b0591SJens Wiklander mbedtls_mpi_free( &ctx->r ); 137*3d3b0591SJens Wiklander } 138*3d3b0591SJens Wiklander 139*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC) 140*3d3b0591SJens Wiklander /* 141*3d3b0591SJens Wiklander * Sub-context for ecdsa_sign_det() 142*3d3b0591SJens Wiklander */ 143*3d3b0591SJens Wiklander struct mbedtls_ecdsa_restart_det 144*3d3b0591SJens Wiklander { 145*3d3b0591SJens Wiklander mbedtls_hmac_drbg_context rng_ctx; /* DRBG state */ 146*3d3b0591SJens Wiklander enum { /* what to do next? */ 147*3d3b0591SJens Wiklander ecdsa_det_init = 0, /* getting started */ 148*3d3b0591SJens Wiklander ecdsa_det_sign, /* make signature */ 149*3d3b0591SJens Wiklander } state; 150*3d3b0591SJens Wiklander }; 151*3d3b0591SJens Wiklander 152*3d3b0591SJens Wiklander /* 153*3d3b0591SJens Wiklander * Init verify sign_det sub-context 154*3d3b0591SJens Wiklander */ 155*3d3b0591SJens Wiklander static void ecdsa_restart_det_init( mbedtls_ecdsa_restart_det_ctx *ctx ) 156*3d3b0591SJens Wiklander { 157*3d3b0591SJens Wiklander mbedtls_hmac_drbg_init( &ctx->rng_ctx ); 158*3d3b0591SJens Wiklander ctx->state = ecdsa_det_init; 159*3d3b0591SJens Wiklander } 160*3d3b0591SJens Wiklander 161*3d3b0591SJens Wiklander /* 162*3d3b0591SJens Wiklander * Free the components of a sign_det restart sub-context 163*3d3b0591SJens Wiklander */ 164*3d3b0591SJens Wiklander static void ecdsa_restart_det_free( mbedtls_ecdsa_restart_det_ctx *ctx ) 165*3d3b0591SJens Wiklander { 166*3d3b0591SJens Wiklander if( ctx == NULL ) 167*3d3b0591SJens Wiklander return; 168*3d3b0591SJens Wiklander 169*3d3b0591SJens Wiklander mbedtls_hmac_drbg_free( &ctx->rng_ctx ); 170*3d3b0591SJens Wiklander 171*3d3b0591SJens Wiklander ecdsa_restart_det_init( ctx ); 172*3d3b0591SJens Wiklander } 173*3d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ 174*3d3b0591SJens Wiklander 175*3d3b0591SJens Wiklander #define ECDSA_RS_ECP &rs_ctx->ecp 176*3d3b0591SJens Wiklander 177*3d3b0591SJens Wiklander /* Utility macro for checking and updating ops budget */ 178*3d3b0591SJens Wiklander #define ECDSA_BUDGET( ops ) \ 179*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_ecp_check_budget( grp, &rs_ctx->ecp, ops ) ); 180*3d3b0591SJens Wiklander 181*3d3b0591SJens Wiklander /* Call this when entering a function that needs its own sub-context */ 182*3d3b0591SJens Wiklander #define ECDSA_RS_ENTER( SUB ) do { \ 183*3d3b0591SJens Wiklander /* reset ops count for this call if top-level */ \ 184*3d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->ecp.depth++ == 0 ) \ 185*3d3b0591SJens Wiklander rs_ctx->ecp.ops_done = 0; \ 186*3d3b0591SJens Wiklander \ 187*3d3b0591SJens Wiklander /* set up our own sub-context if needed */ \ 188*3d3b0591SJens Wiklander if( mbedtls_ecp_restart_is_enabled() && \ 189*3d3b0591SJens Wiklander rs_ctx != NULL && rs_ctx->SUB == NULL ) \ 190*3d3b0591SJens Wiklander { \ 191*3d3b0591SJens Wiklander rs_ctx->SUB = mbedtls_calloc( 1, sizeof( *rs_ctx->SUB ) ); \ 192*3d3b0591SJens Wiklander if( rs_ctx->SUB == NULL ) \ 193*3d3b0591SJens Wiklander return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); \ 194*3d3b0591SJens Wiklander \ 195*3d3b0591SJens Wiklander ecdsa_restart_## SUB ##_init( rs_ctx->SUB ); \ 196*3d3b0591SJens Wiklander } \ 197*3d3b0591SJens Wiklander } while( 0 ) 198*3d3b0591SJens Wiklander 199*3d3b0591SJens Wiklander /* Call this when leaving a function that needs its own sub-context */ 200*3d3b0591SJens Wiklander #define ECDSA_RS_LEAVE( SUB ) do { \ 201*3d3b0591SJens Wiklander /* clear our sub-context when not in progress (done or error) */ \ 202*3d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->SUB != NULL && \ 203*3d3b0591SJens Wiklander ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) \ 204*3d3b0591SJens Wiklander { \ 205*3d3b0591SJens Wiklander ecdsa_restart_## SUB ##_free( rs_ctx->SUB ); \ 206*3d3b0591SJens Wiklander mbedtls_free( rs_ctx->SUB ); \ 207*3d3b0591SJens Wiklander rs_ctx->SUB = NULL; \ 208*3d3b0591SJens Wiklander } \ 209*3d3b0591SJens Wiklander \ 210*3d3b0591SJens Wiklander if( rs_ctx != NULL ) \ 211*3d3b0591SJens Wiklander rs_ctx->ecp.depth--; \ 212*3d3b0591SJens Wiklander } while( 0 ) 213*3d3b0591SJens Wiklander 214*3d3b0591SJens Wiklander #else /* MBEDTLS_ECP_RESTARTABLE */ 215*3d3b0591SJens Wiklander 216*3d3b0591SJens Wiklander #define ECDSA_RS_ECP NULL 217*3d3b0591SJens Wiklander 218*3d3b0591SJens Wiklander #define ECDSA_BUDGET( ops ) /* no-op; for compatibility */ 219*3d3b0591SJens Wiklander 220*3d3b0591SJens Wiklander #define ECDSA_RS_ENTER( SUB ) (void) rs_ctx 221*3d3b0591SJens Wiklander #define ECDSA_RS_LEAVE( SUB ) (void) rs_ctx 222*3d3b0591SJens Wiklander 223*3d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 224*3d3b0591SJens Wiklander 225817466cbSJens Wiklander /* 226817466cbSJens Wiklander * Derive a suitable integer for group grp from a buffer of length len 227817466cbSJens Wiklander * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3 228817466cbSJens Wiklander */ 229817466cbSJens Wiklander static int derive_mpi( const mbedtls_ecp_group *grp, mbedtls_mpi *x, 230817466cbSJens Wiklander const unsigned char *buf, size_t blen ) 231817466cbSJens Wiklander { 232817466cbSJens Wiklander int ret; 233817466cbSJens Wiklander size_t n_size = ( grp->nbits + 7 ) / 8; 234817466cbSJens Wiklander size_t use_size = blen > n_size ? n_size : blen; 235817466cbSJens Wiklander 236817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( x, buf, use_size ) ); 237817466cbSJens Wiklander if( use_size * 8 > grp->nbits ) 238817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( x, use_size * 8 - grp->nbits ) ); 239817466cbSJens Wiklander 240817466cbSJens Wiklander /* While at it, reduce modulo N */ 241817466cbSJens Wiklander if( mbedtls_mpi_cmp_mpi( x, &grp->N ) >= 0 ) 242817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( x, x, &grp->N ) ); 243817466cbSJens Wiklander 244817466cbSJens Wiklander cleanup: 245817466cbSJens Wiklander return( ret ); 246817466cbSJens Wiklander } 247817466cbSJens Wiklander 248*3d3b0591SJens Wiklander #if !defined(MBEDTLS_ECDSA_SIGN_ALT) 249817466cbSJens Wiklander /* 250817466cbSJens Wiklander * Compute ECDSA signature of a hashed message (SEC1 4.1.3) 251817466cbSJens Wiklander * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) 252817466cbSJens Wiklander */ 253*3d3b0591SJens Wiklander static int ecdsa_sign_restartable( mbedtls_ecp_group *grp, 254*3d3b0591SJens Wiklander mbedtls_mpi *r, mbedtls_mpi *s, 255817466cbSJens Wiklander const mbedtls_mpi *d, const unsigned char *buf, size_t blen, 256*3d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, 257*3d3b0591SJens Wiklander mbedtls_ecdsa_restart_ctx *rs_ctx ) 258817466cbSJens Wiklander { 259*3d3b0591SJens Wiklander int ret, key_tries, sign_tries; 260*3d3b0591SJens Wiklander int *p_sign_tries = &sign_tries, *p_key_tries = &key_tries; 261817466cbSJens Wiklander mbedtls_ecp_point R; 262817466cbSJens Wiklander mbedtls_mpi k, e, t; 263*3d3b0591SJens Wiklander mbedtls_mpi *pk = &k, *pr = r; 264817466cbSJens Wiklander 265817466cbSJens Wiklander /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ 266817466cbSJens Wiklander if( grp->N.p == NULL ) 267817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 268817466cbSJens Wiklander 269*3d3b0591SJens Wiklander /* Make sure d is in range 1..n-1 */ 270*3d3b0591SJens Wiklander if( mbedtls_mpi_cmp_int( d, 1 ) < 0 || mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ) 271*3d3b0591SJens Wiklander return( MBEDTLS_ERR_ECP_INVALID_KEY ); 272*3d3b0591SJens Wiklander 273817466cbSJens Wiklander mbedtls_ecp_point_init( &R ); 274817466cbSJens Wiklander mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t ); 275817466cbSJens Wiklander 276*3d3b0591SJens Wiklander ECDSA_RS_ENTER( sig ); 277817466cbSJens Wiklander 278*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 279*3d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->sig != NULL ) 280*3d3b0591SJens Wiklander { 281*3d3b0591SJens Wiklander /* redirect to our context */ 282*3d3b0591SJens Wiklander p_sign_tries = &rs_ctx->sig->sign_tries; 283*3d3b0591SJens Wiklander p_key_tries = &rs_ctx->sig->key_tries; 284*3d3b0591SJens Wiklander pk = &rs_ctx->sig->k; 285*3d3b0591SJens Wiklander pr = &rs_ctx->sig->r; 286*3d3b0591SJens Wiklander 287*3d3b0591SJens Wiklander /* jump to current step */ 288*3d3b0591SJens Wiklander if( rs_ctx->sig->state == ecdsa_sig_mul ) 289*3d3b0591SJens Wiklander goto mul; 290*3d3b0591SJens Wiklander if( rs_ctx->sig->state == ecdsa_sig_modn ) 291*3d3b0591SJens Wiklander goto modn; 292*3d3b0591SJens Wiklander } 293*3d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 294*3d3b0591SJens Wiklander 295*3d3b0591SJens Wiklander *p_sign_tries = 0; 296*3d3b0591SJens Wiklander do 297*3d3b0591SJens Wiklander { 298*3d3b0591SJens Wiklander if( *p_sign_tries++ > 10 ) 299817466cbSJens Wiklander { 300817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; 301817466cbSJens Wiklander goto cleanup; 302817466cbSJens Wiklander } 303*3d3b0591SJens Wiklander 304*3d3b0591SJens Wiklander /* 305*3d3b0591SJens Wiklander * Steps 1-3: generate a suitable ephemeral keypair 306*3d3b0591SJens Wiklander * and set r = xR mod n 307*3d3b0591SJens Wiklander */ 308*3d3b0591SJens Wiklander *p_key_tries = 0; 309*3d3b0591SJens Wiklander do 310*3d3b0591SJens Wiklander { 311*3d3b0591SJens Wiklander if( *p_key_tries++ > 10 ) 312*3d3b0591SJens Wiklander { 313*3d3b0591SJens Wiklander ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; 314*3d3b0591SJens Wiklander goto cleanup; 315817466cbSJens Wiklander } 316*3d3b0591SJens Wiklander 317*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, pk, f_rng, p_rng ) ); 318*3d3b0591SJens Wiklander 319*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 320*3d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->sig != NULL ) 321*3d3b0591SJens Wiklander rs_ctx->sig->state = ecdsa_sig_mul; 322*3d3b0591SJens Wiklander 323*3d3b0591SJens Wiklander mul: 324*3d3b0591SJens Wiklander #endif 325*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &R, pk, &grp->G, 326*3d3b0591SJens Wiklander f_rng, p_rng, ECDSA_RS_ECP ) ); 327*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pr, &R.X, &grp->N ) ); 328*3d3b0591SJens Wiklander } 329*3d3b0591SJens Wiklander while( mbedtls_mpi_cmp_int( pr, 0 ) == 0 ); 330*3d3b0591SJens Wiklander 331*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 332*3d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->sig != NULL ) 333*3d3b0591SJens Wiklander rs_ctx->sig->state = ecdsa_sig_modn; 334*3d3b0591SJens Wiklander 335*3d3b0591SJens Wiklander modn: 336*3d3b0591SJens Wiklander #endif 337*3d3b0591SJens Wiklander /* 338*3d3b0591SJens Wiklander * Accounting for everything up to the end of the loop 339*3d3b0591SJens Wiklander * (step 6, but checking now avoids saving e and t) 340*3d3b0591SJens Wiklander */ 341*3d3b0591SJens Wiklander ECDSA_BUDGET( MBEDTLS_ECP_OPS_INV + 4 ); 342817466cbSJens Wiklander 343817466cbSJens Wiklander /* 344817466cbSJens Wiklander * Step 5: derive MPI from hashed message 345817466cbSJens Wiklander */ 346817466cbSJens Wiklander MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); 347817466cbSJens Wiklander 348817466cbSJens Wiklander /* 349817466cbSJens Wiklander * Generate a random value to blind inv_mod in next step, 350817466cbSJens Wiklander * avoiding a potential timing leak. 351817466cbSJens Wiklander */ 352*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, &t, f_rng, p_rng ) ); 353817466cbSJens Wiklander 354817466cbSJens Wiklander /* 355817466cbSJens Wiklander * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n 356817466cbSJens Wiklander */ 357*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, pr, d ) ); 358817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &e, &e, s ) ); 359817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &e, &e, &t ) ); 360*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pk, pk, &t ) ); 361*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, pk, &grp->N ) ); 362817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) ); 363817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) ); 364817466cbSJens Wiklander } 365817466cbSJens Wiklander while( mbedtls_mpi_cmp_int( s, 0 ) == 0 ); 366817466cbSJens Wiklander 367*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 368*3d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->sig != NULL ) 369*3d3b0591SJens Wiklander mbedtls_mpi_copy( r, pr ); 370*3d3b0591SJens Wiklander #endif 371*3d3b0591SJens Wiklander 372817466cbSJens Wiklander cleanup: 373817466cbSJens Wiklander mbedtls_ecp_point_free( &R ); 374817466cbSJens Wiklander mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t ); 375817466cbSJens Wiklander 376*3d3b0591SJens Wiklander ECDSA_RS_LEAVE( sig ); 377*3d3b0591SJens Wiklander 378817466cbSJens Wiklander return( ret ); 379817466cbSJens Wiklander } 380817466cbSJens Wiklander 381*3d3b0591SJens Wiklander /* 382*3d3b0591SJens Wiklander * Compute ECDSA signature of a hashed message 383*3d3b0591SJens Wiklander */ 384*3d3b0591SJens Wiklander int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, 385*3d3b0591SJens Wiklander const mbedtls_mpi *d, const unsigned char *buf, size_t blen, 386*3d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) 387*3d3b0591SJens Wiklander { 388*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( grp != NULL ); 389*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( r != NULL ); 390*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( s != NULL ); 391*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( d != NULL ); 392*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( f_rng != NULL ); 393*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( buf != NULL || blen == 0 ); 394*3d3b0591SJens Wiklander 395*3d3b0591SJens Wiklander return( ecdsa_sign_restartable( grp, r, s, d, buf, blen, 396*3d3b0591SJens Wiklander f_rng, p_rng, NULL ) ); 397*3d3b0591SJens Wiklander } 398*3d3b0591SJens Wiklander #endif /* !MBEDTLS_ECDSA_SIGN_ALT */ 399*3d3b0591SJens Wiklander 400817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC) 401817466cbSJens Wiklander /* 402817466cbSJens Wiklander * Deterministic signature wrapper 403817466cbSJens Wiklander */ 404*3d3b0591SJens Wiklander static int ecdsa_sign_det_restartable( mbedtls_ecp_group *grp, 405*3d3b0591SJens Wiklander mbedtls_mpi *r, mbedtls_mpi *s, 406817466cbSJens Wiklander const mbedtls_mpi *d, const unsigned char *buf, size_t blen, 407*3d3b0591SJens Wiklander mbedtls_md_type_t md_alg, 408*3d3b0591SJens Wiklander mbedtls_ecdsa_restart_ctx *rs_ctx ) 409817466cbSJens Wiklander { 410817466cbSJens Wiklander int ret; 411817466cbSJens Wiklander mbedtls_hmac_drbg_context rng_ctx; 412*3d3b0591SJens Wiklander mbedtls_hmac_drbg_context *p_rng = &rng_ctx; 413817466cbSJens Wiklander unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES]; 414817466cbSJens Wiklander size_t grp_len = ( grp->nbits + 7 ) / 8; 415817466cbSJens Wiklander const mbedtls_md_info_t *md_info; 416817466cbSJens Wiklander mbedtls_mpi h; 417817466cbSJens Wiklander 418817466cbSJens Wiklander if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL ) 419817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 420817466cbSJens Wiklander 421817466cbSJens Wiklander mbedtls_mpi_init( &h ); 422817466cbSJens Wiklander mbedtls_hmac_drbg_init( &rng_ctx ); 423817466cbSJens Wiklander 424*3d3b0591SJens Wiklander ECDSA_RS_ENTER( det ); 425*3d3b0591SJens Wiklander 426*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 427*3d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->det != NULL ) 428*3d3b0591SJens Wiklander { 429*3d3b0591SJens Wiklander /* redirect to our context */ 430*3d3b0591SJens Wiklander p_rng = &rs_ctx->det->rng_ctx; 431*3d3b0591SJens Wiklander 432*3d3b0591SJens Wiklander /* jump to current step */ 433*3d3b0591SJens Wiklander if( rs_ctx->det->state == ecdsa_det_sign ) 434*3d3b0591SJens Wiklander goto sign; 435*3d3b0591SJens Wiklander } 436*3d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 437*3d3b0591SJens Wiklander 438817466cbSJens Wiklander /* Use private key and message hash (reduced) to initialize HMAC_DRBG */ 439817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, data, grp_len ) ); 440817466cbSJens Wiklander MBEDTLS_MPI_CHK( derive_mpi( grp, &h, buf, blen ) ); 441817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) ); 442*3d3b0591SJens Wiklander mbedtls_hmac_drbg_seed_buf( p_rng, md_info, data, 2 * grp_len ); 443817466cbSJens Wiklander 444*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 445*3d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->det != NULL ) 446*3d3b0591SJens Wiklander rs_ctx->det->state = ecdsa_det_sign; 447*3d3b0591SJens Wiklander 448*3d3b0591SJens Wiklander sign: 449*3d3b0591SJens Wiklander #endif 450*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_SIGN_ALT) 451817466cbSJens Wiklander ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen, 452*3d3b0591SJens Wiklander mbedtls_hmac_drbg_random, p_rng ); 453*3d3b0591SJens Wiklander #else 454*3d3b0591SJens Wiklander ret = ecdsa_sign_restartable( grp, r, s, d, buf, blen, 455*3d3b0591SJens Wiklander mbedtls_hmac_drbg_random, p_rng, rs_ctx ); 456*3d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_SIGN_ALT */ 457817466cbSJens Wiklander 458817466cbSJens Wiklander cleanup: 459817466cbSJens Wiklander mbedtls_hmac_drbg_free( &rng_ctx ); 460817466cbSJens Wiklander mbedtls_mpi_free( &h ); 461817466cbSJens Wiklander 462*3d3b0591SJens Wiklander ECDSA_RS_LEAVE( det ); 463*3d3b0591SJens Wiklander 464817466cbSJens Wiklander return( ret ); 465817466cbSJens Wiklander } 466*3d3b0591SJens Wiklander 467*3d3b0591SJens Wiklander /* 468*3d3b0591SJens Wiklander * Deterministic signature wrapper 469*3d3b0591SJens Wiklander */ 470*3d3b0591SJens Wiklander int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, 471*3d3b0591SJens Wiklander const mbedtls_mpi *d, const unsigned char *buf, size_t blen, 472*3d3b0591SJens Wiklander mbedtls_md_type_t md_alg ) 473*3d3b0591SJens Wiklander { 474*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( grp != NULL ); 475*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( r != NULL ); 476*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( s != NULL ); 477*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( d != NULL ); 478*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( buf != NULL || blen == 0 ); 479*3d3b0591SJens Wiklander 480*3d3b0591SJens Wiklander return( ecdsa_sign_det_restartable( grp, r, s, d, buf, blen, md_alg, NULL ) ); 481*3d3b0591SJens Wiklander } 482817466cbSJens Wiklander #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ 483817466cbSJens Wiklander 484*3d3b0591SJens Wiklander #if !defined(MBEDTLS_ECDSA_VERIFY_ALT) 485817466cbSJens Wiklander /* 486817466cbSJens Wiklander * Verify ECDSA signature of hashed message (SEC1 4.1.4) 487817466cbSJens Wiklander * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message) 488817466cbSJens Wiklander */ 489*3d3b0591SJens Wiklander static int ecdsa_verify_restartable( mbedtls_ecp_group *grp, 490817466cbSJens Wiklander const unsigned char *buf, size_t blen, 491*3d3b0591SJens Wiklander const mbedtls_ecp_point *Q, 492*3d3b0591SJens Wiklander const mbedtls_mpi *r, const mbedtls_mpi *s, 493*3d3b0591SJens Wiklander mbedtls_ecdsa_restart_ctx *rs_ctx ) 494817466cbSJens Wiklander { 495817466cbSJens Wiklander int ret; 496817466cbSJens Wiklander mbedtls_mpi e, s_inv, u1, u2; 497817466cbSJens Wiklander mbedtls_ecp_point R; 498*3d3b0591SJens Wiklander mbedtls_mpi *pu1 = &u1, *pu2 = &u2; 499817466cbSJens Wiklander 500817466cbSJens Wiklander mbedtls_ecp_point_init( &R ); 501*3d3b0591SJens Wiklander mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv ); 502*3d3b0591SJens Wiklander mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 ); 503817466cbSJens Wiklander 504817466cbSJens Wiklander /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ 505817466cbSJens Wiklander if( grp->N.p == NULL ) 506817466cbSJens Wiklander return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); 507817466cbSJens Wiklander 508*3d3b0591SJens Wiklander ECDSA_RS_ENTER( ver ); 509*3d3b0591SJens Wiklander 510*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 511*3d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->ver != NULL ) 512*3d3b0591SJens Wiklander { 513*3d3b0591SJens Wiklander /* redirect to our context */ 514*3d3b0591SJens Wiklander pu1 = &rs_ctx->ver->u1; 515*3d3b0591SJens Wiklander pu2 = &rs_ctx->ver->u2; 516*3d3b0591SJens Wiklander 517*3d3b0591SJens Wiklander /* jump to current step */ 518*3d3b0591SJens Wiklander if( rs_ctx->ver->state == ecdsa_ver_muladd ) 519*3d3b0591SJens Wiklander goto muladd; 520*3d3b0591SJens Wiklander } 521*3d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 522*3d3b0591SJens Wiklander 523817466cbSJens Wiklander /* 524817466cbSJens Wiklander * Step 1: make sure r and s are in range 1..n-1 525817466cbSJens Wiklander */ 526817466cbSJens Wiklander if( mbedtls_mpi_cmp_int( r, 1 ) < 0 || mbedtls_mpi_cmp_mpi( r, &grp->N ) >= 0 || 527817466cbSJens Wiklander mbedtls_mpi_cmp_int( s, 1 ) < 0 || mbedtls_mpi_cmp_mpi( s, &grp->N ) >= 0 ) 528817466cbSJens Wiklander { 529817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; 530817466cbSJens Wiklander goto cleanup; 531817466cbSJens Wiklander } 532817466cbSJens Wiklander 533817466cbSJens Wiklander /* 534817466cbSJens Wiklander * Step 3: derive MPI from hashed message 535817466cbSJens Wiklander */ 536817466cbSJens Wiklander MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); 537817466cbSJens Wiklander 538817466cbSJens Wiklander /* 539817466cbSJens Wiklander * Step 4: u1 = e / s mod n, u2 = r / s mod n 540817466cbSJens Wiklander */ 541*3d3b0591SJens Wiklander ECDSA_BUDGET( MBEDTLS_ECP_OPS_CHK + MBEDTLS_ECP_OPS_INV + 2 ); 542*3d3b0591SJens Wiklander 543817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) ); 544817466cbSJens Wiklander 545*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu1, &e, &s_inv ) ); 546*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu1, pu1, &grp->N ) ); 547817466cbSJens Wiklander 548*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu2, r, &s_inv ) ); 549*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu2, pu2, &grp->N ) ); 550817466cbSJens Wiklander 551*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 552*3d3b0591SJens Wiklander if( rs_ctx != NULL && rs_ctx->ver != NULL ) 553*3d3b0591SJens Wiklander rs_ctx->ver->state = ecdsa_ver_muladd; 554*3d3b0591SJens Wiklander 555*3d3b0591SJens Wiklander muladd: 556*3d3b0591SJens Wiklander #endif 557817466cbSJens Wiklander /* 558817466cbSJens Wiklander * Step 5: R = u1 G + u2 Q 559817466cbSJens Wiklander */ 560*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( mbedtls_ecp_muladd_restartable( grp, 561*3d3b0591SJens Wiklander &R, pu1, &grp->G, pu2, Q, ECDSA_RS_ECP ) ); 562817466cbSJens Wiklander 563817466cbSJens Wiklander if( mbedtls_ecp_is_zero( &R ) ) 564817466cbSJens Wiklander { 565817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; 566817466cbSJens Wiklander goto cleanup; 567817466cbSJens Wiklander } 568817466cbSJens Wiklander 569817466cbSJens Wiklander /* 570817466cbSJens Wiklander * Step 6: convert xR to an integer (no-op) 571817466cbSJens Wiklander * Step 7: reduce xR mod n (gives v) 572817466cbSJens Wiklander */ 573817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &R.X, &R.X, &grp->N ) ); 574817466cbSJens Wiklander 575817466cbSJens Wiklander /* 576817466cbSJens Wiklander * Step 8: check if v (that is, R.X) is equal to r 577817466cbSJens Wiklander */ 578817466cbSJens Wiklander if( mbedtls_mpi_cmp_mpi( &R.X, r ) != 0 ) 579817466cbSJens Wiklander { 580817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; 581817466cbSJens Wiklander goto cleanup; 582817466cbSJens Wiklander } 583817466cbSJens Wiklander 584817466cbSJens Wiklander cleanup: 585817466cbSJens Wiklander mbedtls_ecp_point_free( &R ); 586*3d3b0591SJens Wiklander mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv ); 587*3d3b0591SJens Wiklander mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 ); 588*3d3b0591SJens Wiklander 589*3d3b0591SJens Wiklander ECDSA_RS_LEAVE( ver ); 590817466cbSJens Wiklander 591817466cbSJens Wiklander return( ret ); 592817466cbSJens Wiklander } 593817466cbSJens Wiklander 594817466cbSJens Wiklander /* 595*3d3b0591SJens Wiklander * Verify ECDSA signature of hashed message 596*3d3b0591SJens Wiklander */ 597*3d3b0591SJens Wiklander int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, 598*3d3b0591SJens Wiklander const unsigned char *buf, size_t blen, 599*3d3b0591SJens Wiklander const mbedtls_ecp_point *Q, 600*3d3b0591SJens Wiklander const mbedtls_mpi *r, 601*3d3b0591SJens Wiklander const mbedtls_mpi *s) 602*3d3b0591SJens Wiklander { 603*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( grp != NULL ); 604*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( Q != NULL ); 605*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( r != NULL ); 606*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( s != NULL ); 607*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( buf != NULL || blen == 0 ); 608*3d3b0591SJens Wiklander 609*3d3b0591SJens Wiklander return( ecdsa_verify_restartable( grp, buf, blen, Q, r, s, NULL ) ); 610*3d3b0591SJens Wiklander } 611*3d3b0591SJens Wiklander #endif /* !MBEDTLS_ECDSA_VERIFY_ALT */ 612*3d3b0591SJens Wiklander 613*3d3b0591SJens Wiklander /* 614817466cbSJens Wiklander * Convert a signature (given by context) to ASN.1 615817466cbSJens Wiklander */ 616817466cbSJens Wiklander static int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, 617817466cbSJens Wiklander unsigned char *sig, size_t *slen ) 618817466cbSJens Wiklander { 619817466cbSJens Wiklander int ret; 620817466cbSJens Wiklander unsigned char buf[MBEDTLS_ECDSA_MAX_LEN]; 621817466cbSJens Wiklander unsigned char *p = buf + sizeof( buf ); 622817466cbSJens Wiklander size_t len = 0; 623817466cbSJens Wiklander 624817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, s ) ); 625817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, r ) ); 626817466cbSJens Wiklander 627817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &p, buf, len ) ); 628817466cbSJens Wiklander MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &p, buf, 629817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); 630817466cbSJens Wiklander 631817466cbSJens Wiklander memcpy( sig, p, len ); 632817466cbSJens Wiklander *slen = len; 633817466cbSJens Wiklander 634817466cbSJens Wiklander return( 0 ); 635817466cbSJens Wiklander } 636817466cbSJens Wiklander 637817466cbSJens Wiklander /* 638817466cbSJens Wiklander * Compute and write signature 639817466cbSJens Wiklander */ 640*3d3b0591SJens Wiklander int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx, 641*3d3b0591SJens Wiklander mbedtls_md_type_t md_alg, 642817466cbSJens Wiklander const unsigned char *hash, size_t hlen, 643817466cbSJens Wiklander unsigned char *sig, size_t *slen, 644817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 645*3d3b0591SJens Wiklander void *p_rng, 646*3d3b0591SJens Wiklander mbedtls_ecdsa_restart_ctx *rs_ctx ) 647817466cbSJens Wiklander { 648817466cbSJens Wiklander int ret; 649817466cbSJens Wiklander mbedtls_mpi r, s; 650*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( ctx != NULL ); 651*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( hash != NULL ); 652*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( sig != NULL ); 653*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( slen != NULL ); 654817466cbSJens Wiklander 655817466cbSJens Wiklander mbedtls_mpi_init( &r ); 656817466cbSJens Wiklander mbedtls_mpi_init( &s ); 657817466cbSJens Wiklander 658817466cbSJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC) 659817466cbSJens Wiklander (void) f_rng; 660817466cbSJens Wiklander (void) p_rng; 661817466cbSJens Wiklander 662*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( ecdsa_sign_det_restartable( &ctx->grp, &r, &s, &ctx->d, 663*3d3b0591SJens Wiklander hash, hlen, md_alg, rs_ctx ) ); 664817466cbSJens Wiklander #else 665817466cbSJens Wiklander (void) md_alg; 666817466cbSJens Wiklander 667*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_SIGN_ALT) 668817466cbSJens Wiklander MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d, 669817466cbSJens Wiklander hash, hlen, f_rng, p_rng ) ); 670*3d3b0591SJens Wiklander #else 671*3d3b0591SJens Wiklander MBEDTLS_MPI_CHK( ecdsa_sign_restartable( &ctx->grp, &r, &s, &ctx->d, 672*3d3b0591SJens Wiklander hash, hlen, f_rng, p_rng, rs_ctx ) ); 673*3d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_SIGN_ALT */ 674*3d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_DETERMINISTIC */ 675817466cbSJens Wiklander 676817466cbSJens Wiklander MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) ); 677817466cbSJens Wiklander 678817466cbSJens Wiklander cleanup: 679817466cbSJens Wiklander mbedtls_mpi_free( &r ); 680817466cbSJens Wiklander mbedtls_mpi_free( &s ); 681817466cbSJens Wiklander 682817466cbSJens Wiklander return( ret ); 683817466cbSJens Wiklander } 684817466cbSJens Wiklander 685*3d3b0591SJens Wiklander /* 686*3d3b0591SJens Wiklander * Compute and write signature 687*3d3b0591SJens Wiklander */ 688*3d3b0591SJens Wiklander int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, 689*3d3b0591SJens Wiklander mbedtls_md_type_t md_alg, 690*3d3b0591SJens Wiklander const unsigned char *hash, size_t hlen, 691*3d3b0591SJens Wiklander unsigned char *sig, size_t *slen, 692*3d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 693*3d3b0591SJens Wiklander void *p_rng ) 694*3d3b0591SJens Wiklander { 695*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( ctx != NULL ); 696*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( hash != NULL ); 697*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( sig != NULL ); 698*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( slen != NULL ); 699*3d3b0591SJens Wiklander return( mbedtls_ecdsa_write_signature_restartable( 700*3d3b0591SJens Wiklander ctx, md_alg, hash, hlen, sig, slen, f_rng, p_rng, NULL ) ); 701*3d3b0591SJens Wiklander } 702*3d3b0591SJens Wiklander 703817466cbSJens Wiklander #if !defined(MBEDTLS_DEPRECATED_REMOVED) && \ 704817466cbSJens Wiklander defined(MBEDTLS_ECDSA_DETERMINISTIC) 705817466cbSJens Wiklander int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, 706817466cbSJens Wiklander const unsigned char *hash, size_t hlen, 707817466cbSJens Wiklander unsigned char *sig, size_t *slen, 708817466cbSJens Wiklander mbedtls_md_type_t md_alg ) 709817466cbSJens Wiklander { 710*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( ctx != NULL ); 711*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( hash != NULL ); 712*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( sig != NULL ); 713*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( slen != NULL ); 714817466cbSJens Wiklander return( mbedtls_ecdsa_write_signature( ctx, md_alg, hash, hlen, sig, slen, 715817466cbSJens Wiklander NULL, NULL ) ); 716817466cbSJens Wiklander } 717817466cbSJens Wiklander #endif 718817466cbSJens Wiklander 719817466cbSJens Wiklander /* 720817466cbSJens Wiklander * Read and check signature 721817466cbSJens Wiklander */ 722817466cbSJens Wiklander int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, 723817466cbSJens Wiklander const unsigned char *hash, size_t hlen, 724817466cbSJens Wiklander const unsigned char *sig, size_t slen ) 725817466cbSJens Wiklander { 726*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( ctx != NULL ); 727*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( hash != NULL ); 728*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( sig != NULL ); 729*3d3b0591SJens Wiklander return( mbedtls_ecdsa_read_signature_restartable( 730*3d3b0591SJens Wiklander ctx, hash, hlen, sig, slen, NULL ) ); 731*3d3b0591SJens Wiklander } 732*3d3b0591SJens Wiklander 733*3d3b0591SJens Wiklander /* 734*3d3b0591SJens Wiklander * Restartable read and check signature 735*3d3b0591SJens Wiklander */ 736*3d3b0591SJens Wiklander int mbedtls_ecdsa_read_signature_restartable( mbedtls_ecdsa_context *ctx, 737*3d3b0591SJens Wiklander const unsigned char *hash, size_t hlen, 738*3d3b0591SJens Wiklander const unsigned char *sig, size_t slen, 739*3d3b0591SJens Wiklander mbedtls_ecdsa_restart_ctx *rs_ctx ) 740*3d3b0591SJens Wiklander { 741817466cbSJens Wiklander int ret; 742817466cbSJens Wiklander unsigned char *p = (unsigned char *) sig; 743817466cbSJens Wiklander const unsigned char *end = sig + slen; 744817466cbSJens Wiklander size_t len; 745817466cbSJens Wiklander mbedtls_mpi r, s; 746*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( ctx != NULL ); 747*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( hash != NULL ); 748*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( sig != NULL ); 749817466cbSJens Wiklander 750817466cbSJens Wiklander mbedtls_mpi_init( &r ); 751817466cbSJens Wiklander mbedtls_mpi_init( &s ); 752817466cbSJens Wiklander 753817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, 754817466cbSJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) 755817466cbSJens Wiklander { 756817466cbSJens Wiklander ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 757817466cbSJens Wiklander goto cleanup; 758817466cbSJens Wiklander } 759817466cbSJens Wiklander 760817466cbSJens Wiklander if( p + len != end ) 761817466cbSJens Wiklander { 762817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA + 763817466cbSJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; 764817466cbSJens Wiklander goto cleanup; 765817466cbSJens Wiklander } 766817466cbSJens Wiklander 767817466cbSJens Wiklander if( ( ret = mbedtls_asn1_get_mpi( &p, end, &r ) ) != 0 || 768817466cbSJens Wiklander ( ret = mbedtls_asn1_get_mpi( &p, end, &s ) ) != 0 ) 769817466cbSJens Wiklander { 770817466cbSJens Wiklander ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 771817466cbSJens Wiklander goto cleanup; 772817466cbSJens Wiklander } 773*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_VERIFY_ALT) 774817466cbSJens Wiklander if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen, 775817466cbSJens Wiklander &ctx->Q, &r, &s ) ) != 0 ) 776817466cbSJens Wiklander goto cleanup; 777*3d3b0591SJens Wiklander #else 778*3d3b0591SJens Wiklander if( ( ret = ecdsa_verify_restartable( &ctx->grp, hash, hlen, 779*3d3b0591SJens Wiklander &ctx->Q, &r, &s, rs_ctx ) ) != 0 ) 780*3d3b0591SJens Wiklander goto cleanup; 781*3d3b0591SJens Wiklander #endif /* MBEDTLS_ECDSA_VERIFY_ALT */ 782817466cbSJens Wiklander 783*3d3b0591SJens Wiklander /* At this point we know that the buffer starts with a valid signature. 784*3d3b0591SJens Wiklander * Return 0 if the buffer just contains the signature, and a specific 785*3d3b0591SJens Wiklander * error code if the valid signature is followed by more data. */ 786817466cbSJens Wiklander if( p != end ) 787817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH; 788817466cbSJens Wiklander 789817466cbSJens Wiklander cleanup: 790817466cbSJens Wiklander mbedtls_mpi_free( &r ); 791817466cbSJens Wiklander mbedtls_mpi_free( &s ); 792817466cbSJens Wiklander 793817466cbSJens Wiklander return( ret ); 794817466cbSJens Wiklander } 795817466cbSJens Wiklander 796*3d3b0591SJens Wiklander #if !defined(MBEDTLS_ECDSA_GENKEY_ALT) 797817466cbSJens Wiklander /* 798817466cbSJens Wiklander * Generate key pair 799817466cbSJens Wiklander */ 800817466cbSJens Wiklander int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, 801817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) 802817466cbSJens Wiklander { 803*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( ctx != NULL ); 804*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( f_rng != NULL ); 805*3d3b0591SJens Wiklander 806817466cbSJens Wiklander return( mbedtls_ecp_group_load( &ctx->grp, gid ) || 807817466cbSJens Wiklander mbedtls_ecp_gen_keypair( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ); 808817466cbSJens Wiklander } 809*3d3b0591SJens Wiklander #endif /* !MBEDTLS_ECDSA_GENKEY_ALT */ 810817466cbSJens Wiklander 811817466cbSJens Wiklander /* 812817466cbSJens Wiklander * Set context from an mbedtls_ecp_keypair 813817466cbSJens Wiklander */ 814817466cbSJens Wiklander int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ) 815817466cbSJens Wiklander { 816817466cbSJens Wiklander int ret; 817*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( ctx != NULL ); 818*3d3b0591SJens Wiklander ECDSA_VALIDATE_RET( key != NULL ); 819817466cbSJens Wiklander 820817466cbSJens Wiklander if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 || 821817466cbSJens Wiklander ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 || 822817466cbSJens Wiklander ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 ) 823817466cbSJens Wiklander { 824817466cbSJens Wiklander mbedtls_ecdsa_free( ctx ); 825817466cbSJens Wiklander } 826817466cbSJens Wiklander 827817466cbSJens Wiklander return( ret ); 828817466cbSJens Wiklander } 829817466cbSJens Wiklander 830817466cbSJens Wiklander /* 831817466cbSJens Wiklander * Initialize context 832817466cbSJens Wiklander */ 833817466cbSJens Wiklander void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ) 834817466cbSJens Wiklander { 835*3d3b0591SJens Wiklander ECDSA_VALIDATE( ctx != NULL ); 836*3d3b0591SJens Wiklander 837817466cbSJens Wiklander mbedtls_ecp_keypair_init( ctx ); 838817466cbSJens Wiklander } 839817466cbSJens Wiklander 840817466cbSJens Wiklander /* 841817466cbSJens Wiklander * Free context 842817466cbSJens Wiklander */ 843817466cbSJens Wiklander void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ) 844817466cbSJens Wiklander { 845*3d3b0591SJens Wiklander if( ctx == NULL ) 846*3d3b0591SJens Wiklander return; 847*3d3b0591SJens Wiklander 848817466cbSJens Wiklander mbedtls_ecp_keypair_free( ctx ); 849817466cbSJens Wiklander } 850817466cbSJens Wiklander 851*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 852*3d3b0591SJens Wiklander /* 853*3d3b0591SJens Wiklander * Initialize a restart context 854*3d3b0591SJens Wiklander */ 855*3d3b0591SJens Wiklander void mbedtls_ecdsa_restart_init( mbedtls_ecdsa_restart_ctx *ctx ) 856*3d3b0591SJens Wiklander { 857*3d3b0591SJens Wiklander ECDSA_VALIDATE( ctx != NULL ); 858*3d3b0591SJens Wiklander 859*3d3b0591SJens Wiklander mbedtls_ecp_restart_init( &ctx->ecp ); 860*3d3b0591SJens Wiklander 861*3d3b0591SJens Wiklander ctx->ver = NULL; 862*3d3b0591SJens Wiklander ctx->sig = NULL; 863*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC) 864*3d3b0591SJens Wiklander ctx->det = NULL; 865*3d3b0591SJens Wiklander #endif 866*3d3b0591SJens Wiklander } 867*3d3b0591SJens Wiklander 868*3d3b0591SJens Wiklander /* 869*3d3b0591SJens Wiklander * Free the components of a restart context 870*3d3b0591SJens Wiklander */ 871*3d3b0591SJens Wiklander void mbedtls_ecdsa_restart_free( mbedtls_ecdsa_restart_ctx *ctx ) 872*3d3b0591SJens Wiklander { 873*3d3b0591SJens Wiklander if( ctx == NULL ) 874*3d3b0591SJens Wiklander return; 875*3d3b0591SJens Wiklander 876*3d3b0591SJens Wiklander mbedtls_ecp_restart_free( &ctx->ecp ); 877*3d3b0591SJens Wiklander 878*3d3b0591SJens Wiklander ecdsa_restart_ver_free( ctx->ver ); 879*3d3b0591SJens Wiklander mbedtls_free( ctx->ver ); 880*3d3b0591SJens Wiklander ctx->ver = NULL; 881*3d3b0591SJens Wiklander 882*3d3b0591SJens Wiklander ecdsa_restart_sig_free( ctx->sig ); 883*3d3b0591SJens Wiklander mbedtls_free( ctx->sig ); 884*3d3b0591SJens Wiklander ctx->sig = NULL; 885*3d3b0591SJens Wiklander 886*3d3b0591SJens Wiklander #if defined(MBEDTLS_ECDSA_DETERMINISTIC) 887*3d3b0591SJens Wiklander ecdsa_restart_det_free( ctx->det ); 888*3d3b0591SJens Wiklander mbedtls_free( ctx->det ); 889*3d3b0591SJens Wiklander ctx->det = NULL; 890*3d3b0591SJens Wiklander #endif 891*3d3b0591SJens Wiklander } 892*3d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 893*3d3b0591SJens Wiklander 894817466cbSJens Wiklander #endif /* MBEDTLS_ECDSA_C */ 895