mirror of
https://git.suyu.dev/suyu/mbedtls.git
synced 2025-12-23 15:55:10 +01:00
Merge remote-tracking branch 'restricted/pr/390' into development
This commit is contained in:
commit
169712e15a
40 changed files with 4242 additions and 605 deletions
125
library/ecdh.c
125
library/ecdh.c
|
|
@ -40,13 +40,41 @@
|
|||
|
||||
#if !defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT)
|
||||
/*
|
||||
* Generate public key: simple wrapper around mbedtls_ecp_gen_keypair
|
||||
* Generate public key (restartable version)
|
||||
*
|
||||
* Note: this internal function relies on its caller preserving the value of
|
||||
* the output parameter 'd' across continuation calls. This would not be
|
||||
* acceptable for a public function but is OK here as we control call sites.
|
||||
*/
|
||||
static int ecdh_gen_public_restartable( mbedtls_ecp_group *grp,
|
||||
mbedtls_mpi *d, mbedtls_ecp_point *Q,
|
||||
int (*f_rng)(void *, unsigned char *, size_t),
|
||||
void *p_rng,
|
||||
mbedtls_ecp_restart_ctx *rs_ctx )
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* If multiplication is in progress, we already generated a privkey */
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( rs_ctx == NULL || rs_ctx->rsm == NULL )
|
||||
#endif
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) );
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, Q, d, &grp->G,
|
||||
f_rng, p_rng, rs_ctx ) );
|
||||
|
||||
cleanup:
|
||||
return( ret );
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate public key
|
||||
*/
|
||||
int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q,
|
||||
int (*f_rng)(void *, unsigned char *, size_t),
|
||||
void *p_rng )
|
||||
{
|
||||
return mbedtls_ecp_gen_keypair( grp, d, Q, f_rng, p_rng );
|
||||
return( ecdh_gen_public_restartable( grp, d, Q, f_rng, p_rng, NULL ) );
|
||||
}
|
||||
#endif /* MBEDTLS_ECDH_GEN_PUBLIC_ALT */
|
||||
|
||||
|
|
@ -54,22 +82,20 @@ int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp
|
|||
/*
|
||||
* Compute shared secret (SEC1 3.3.1)
|
||||
*/
|
||||
int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z,
|
||||
static int ecdh_compute_shared_restartable( mbedtls_ecp_group *grp,
|
||||
mbedtls_mpi *z,
|
||||
const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
|
||||
int (*f_rng)(void *, unsigned char *, size_t),
|
||||
void *p_rng )
|
||||
void *p_rng,
|
||||
mbedtls_ecp_restart_ctx *rs_ctx )
|
||||
{
|
||||
int ret;
|
||||
mbedtls_ecp_point P;
|
||||
|
||||
mbedtls_ecp_point_init( &P );
|
||||
|
||||
/*
|
||||
* Make sure Q is a valid pubkey before using it
|
||||
*/
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) );
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, &P, d, Q, f_rng, p_rng ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &P, d, Q,
|
||||
f_rng, p_rng, rs_ctx ) );
|
||||
|
||||
if( mbedtls_ecp_is_zero( &P ) )
|
||||
{
|
||||
|
|
@ -86,12 +112,37 @@ cleanup:
|
|||
}
|
||||
#endif /* MBEDTLS_ECDH_COMPUTE_SHARED_ALT */
|
||||
|
||||
/*
|
||||
* Compute shared secret (SEC1 3.3.1)
|
||||
*/
|
||||
int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z,
|
||||
const mbedtls_ecp_point *Q, const mbedtls_mpi *d,
|
||||
int (*f_rng)(void *, unsigned char *, size_t),
|
||||
void *p_rng )
|
||||
{
|
||||
return( ecdh_compute_shared_restartable( grp, z, Q, d,
|
||||
f_rng, p_rng, NULL ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize context
|
||||
*/
|
||||
void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx )
|
||||
{
|
||||
memset( ctx, 0, sizeof( mbedtls_ecdh_context ) );
|
||||
mbedtls_ecp_group_init( &ctx->grp );
|
||||
mbedtls_mpi_init( &ctx->d );
|
||||
mbedtls_ecp_point_init( &ctx->Q );
|
||||
mbedtls_ecp_point_init( &ctx->Qp );
|
||||
mbedtls_mpi_init( &ctx->z );
|
||||
ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED;
|
||||
mbedtls_ecp_point_init( &ctx->Vi );
|
||||
mbedtls_ecp_point_init( &ctx->Vf );
|
||||
mbedtls_mpi_init( &ctx->_d );
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
ctx->restart_enabled = 0;
|
||||
mbedtls_ecp_restart_init( &ctx->rs );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -103,15 +154,29 @@ void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx )
|
|||
return;
|
||||
|
||||
mbedtls_ecp_group_free( &ctx->grp );
|
||||
mbedtls_mpi_free( &ctx->d );
|
||||
mbedtls_ecp_point_free( &ctx->Q );
|
||||
mbedtls_ecp_point_free( &ctx->Qp );
|
||||
mbedtls_mpi_free( &ctx->z );
|
||||
mbedtls_ecp_point_free( &ctx->Vi );
|
||||
mbedtls_ecp_point_free( &ctx->Vf );
|
||||
mbedtls_mpi_free( &ctx->d );
|
||||
mbedtls_mpi_free( &ctx->z );
|
||||
mbedtls_mpi_free( &ctx->_d );
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
mbedtls_ecp_restart_free( &ctx->rs );
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
/*
|
||||
* Enable restartable operations for context
|
||||
*/
|
||||
void mbedtls_ecdh_enable_restart( mbedtls_ecdh_context *ctx )
|
||||
{
|
||||
ctx->restart_enabled = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Setup and write the ServerKeyExhange parameters (RFC 4492)
|
||||
* struct {
|
||||
|
|
@ -126,12 +191,18 @@ int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen,
|
|||
{
|
||||
int ret;
|
||||
size_t grp_len, pt_len;
|
||||
mbedtls_ecp_restart_ctx *rs_ctx = NULL;
|
||||
|
||||
if( ctx == NULL || ctx->grp.pbits == 0 )
|
||||
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
|
||||
|
||||
if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) )
|
||||
!= 0 )
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( ctx->restart_enabled )
|
||||
rs_ctx = &ctx->rs;
|
||||
#endif
|
||||
|
||||
if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q,
|
||||
f_rng, p_rng, rs_ctx ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf, blen ) )
|
||||
|
|
@ -142,7 +213,7 @@ int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen,
|
|||
blen -= grp_len;
|
||||
|
||||
if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format,
|
||||
&pt_len, buf, blen ) ) != 0 )
|
||||
&pt_len, buf, blen ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
*olen = grp_len + pt_len;
|
||||
|
|
@ -206,12 +277,18 @@ int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen,
|
|||
void *p_rng )
|
||||
{
|
||||
int ret;
|
||||
mbedtls_ecp_restart_ctx *rs_ctx = NULL;
|
||||
|
||||
if( ctx == NULL || ctx->grp.pbits == 0 )
|
||||
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
|
||||
|
||||
if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) )
|
||||
!= 0 )
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( ctx->restart_enabled )
|
||||
rs_ctx = &ctx->rs;
|
||||
#endif
|
||||
|
||||
if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q,
|
||||
f_rng, p_rng, rs_ctx ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format,
|
||||
|
|
@ -248,12 +325,18 @@ int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen,
|
|||
void *p_rng )
|
||||
{
|
||||
int ret;
|
||||
mbedtls_ecp_restart_ctx *rs_ctx = NULL;
|
||||
|
||||
if( ctx == NULL )
|
||||
if( ctx == NULL || ctx->grp.pbits == 0 )
|
||||
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
|
||||
|
||||
if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp, &ctx->d,
|
||||
f_rng, p_rng ) ) != 0 )
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( ctx->restart_enabled )
|
||||
rs_ctx = &ctx->rs;
|
||||
#endif
|
||||
|
||||
if( ( ret = ecdh_compute_shared_restartable( &ctx->grp,
|
||||
&ctx->z, &ctx->Qp, &ctx->d, f_rng, p_rng, rs_ctx ) ) != 0 )
|
||||
{
|
||||
return( ret );
|
||||
}
|
||||
|
|
|
|||
481
library/ecdsa.c
481
library/ecdsa.c
|
|
@ -42,6 +42,178 @@
|
|||
#include "mbedtls/hmac_drbg.h"
|
||||
#endif
|
||||
|
||||
#if defined(MBEDTLS_PLATFORM_C)
|
||||
#include "mbedtls/platform.h"
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#define mbedtls_calloc calloc
|
||||
#define mbedtls_free free
|
||||
#endif
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
|
||||
/*
|
||||
* Sub-context for ecdsa_verify()
|
||||
*/
|
||||
struct mbedtls_ecdsa_restart_ver
|
||||
{
|
||||
mbedtls_mpi u1, u2; /* intermediate values */
|
||||
enum { /* what to do next? */
|
||||
ecdsa_ver_init = 0, /* getting started */
|
||||
ecdsa_ver_muladd, /* muladd step */
|
||||
} state;
|
||||
};
|
||||
|
||||
/*
|
||||
* Init verify restart sub-context
|
||||
*/
|
||||
static void ecdsa_restart_ver_init( mbedtls_ecdsa_restart_ver_ctx *ctx )
|
||||
{
|
||||
mbedtls_mpi_init( &ctx->u1 );
|
||||
mbedtls_mpi_init( &ctx->u2 );
|
||||
ctx->state = ecdsa_ver_init;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the components of a verify restart sub-context
|
||||
*/
|
||||
static void ecdsa_restart_ver_free( mbedtls_ecdsa_restart_ver_ctx *ctx )
|
||||
{
|
||||
if( ctx == NULL )
|
||||
return;
|
||||
|
||||
mbedtls_mpi_free( &ctx->u1 );
|
||||
mbedtls_mpi_free( &ctx->u2 );
|
||||
|
||||
ecdsa_restart_ver_init( ctx );
|
||||
}
|
||||
|
||||
/*
|
||||
* Sub-context for ecdsa_sign()
|
||||
*/
|
||||
struct mbedtls_ecdsa_restart_sig
|
||||
{
|
||||
int sign_tries;
|
||||
int key_tries;
|
||||
mbedtls_mpi k; /* per-signature random */
|
||||
mbedtls_mpi r; /* r value */
|
||||
enum { /* what to do next? */
|
||||
ecdsa_sig_init = 0, /* getting started */
|
||||
ecdsa_sig_mul, /* doing ecp_mul() */
|
||||
ecdsa_sig_modn, /* mod N computations */
|
||||
} state;
|
||||
};
|
||||
|
||||
/*
|
||||
* Init verify sign sub-context
|
||||
*/
|
||||
static void ecdsa_restart_sig_init( mbedtls_ecdsa_restart_sig_ctx *ctx )
|
||||
{
|
||||
ctx->sign_tries = 0;
|
||||
ctx->key_tries = 0;
|
||||
mbedtls_mpi_init( &ctx->k );
|
||||
mbedtls_mpi_init( &ctx->r );
|
||||
ctx->state = ecdsa_sig_init;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the components of a sign restart sub-context
|
||||
*/
|
||||
static void ecdsa_restart_sig_free( mbedtls_ecdsa_restart_sig_ctx *ctx )
|
||||
{
|
||||
if( ctx == NULL )
|
||||
return;
|
||||
|
||||
mbedtls_mpi_free( &ctx->k );
|
||||
mbedtls_mpi_free( &ctx->r );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
|
||||
/*
|
||||
* Sub-context for ecdsa_sign_det()
|
||||
*/
|
||||
struct mbedtls_ecdsa_restart_det
|
||||
{
|
||||
mbedtls_hmac_drbg_context rng_ctx; /* DRBG state */
|
||||
enum { /* what to do next? */
|
||||
ecdsa_det_init = 0, /* getting started */
|
||||
ecdsa_det_sign, /* make signature */
|
||||
} state;
|
||||
};
|
||||
|
||||
/*
|
||||
* Init verify sign_det sub-context
|
||||
*/
|
||||
static void ecdsa_restart_det_init( mbedtls_ecdsa_restart_det_ctx *ctx )
|
||||
{
|
||||
mbedtls_hmac_drbg_init( &ctx->rng_ctx );
|
||||
ctx->state = ecdsa_det_init;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the components of a sign_det restart sub-context
|
||||
*/
|
||||
static void ecdsa_restart_det_free( mbedtls_ecdsa_restart_det_ctx *ctx )
|
||||
{
|
||||
if( ctx == NULL )
|
||||
return;
|
||||
|
||||
mbedtls_hmac_drbg_free( &ctx->rng_ctx );
|
||||
|
||||
ecdsa_restart_det_init( ctx );
|
||||
}
|
||||
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
|
||||
|
||||
#define ECDSA_RS_ECP &rs_ctx->ecp
|
||||
|
||||
/* Utility macro for checking and updating ops budget */
|
||||
#define ECDSA_BUDGET( ops ) \
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecp_check_budget( grp, &rs_ctx->ecp, ops ) );
|
||||
|
||||
/* Call this when entering a function that needs its own sub-context */
|
||||
#define ECDSA_RS_ENTER( SUB ) do { \
|
||||
/* reset ops count for this call if top-level */ \
|
||||
if( rs_ctx != NULL && rs_ctx->ecp.depth++ == 0 ) \
|
||||
rs_ctx->ecp.ops_done = 0; \
|
||||
\
|
||||
/* set up our own sub-context if needed */ \
|
||||
if( mbedtls_ecp_restart_is_enabled() && \
|
||||
rs_ctx != NULL && rs_ctx->SUB == NULL ) \
|
||||
{ \
|
||||
rs_ctx->SUB = mbedtls_calloc( 1, sizeof( *rs_ctx->SUB ) ); \
|
||||
if( rs_ctx->SUB == NULL ) \
|
||||
return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); \
|
||||
\
|
||||
ecdsa_restart_## SUB ##_init( rs_ctx->SUB ); \
|
||||
} \
|
||||
} while( 0 )
|
||||
|
||||
/* Call this when leaving a function that needs its own sub-context */
|
||||
#define ECDSA_RS_LEAVE( SUB ) do { \
|
||||
/* clear our sub-context when not in progress (done or error) */ \
|
||||
if( rs_ctx != NULL && rs_ctx->SUB != NULL && \
|
||||
ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) \
|
||||
{ \
|
||||
ecdsa_restart_## SUB ##_free( rs_ctx->SUB ); \
|
||||
mbedtls_free( rs_ctx->SUB ); \
|
||||
rs_ctx->SUB = NULL; \
|
||||
} \
|
||||
\
|
||||
if( rs_ctx != NULL ) \
|
||||
rs_ctx->ecp.depth--; \
|
||||
} while( 0 )
|
||||
|
||||
#else /* MBEDTLS_ECP_RESTARTABLE */
|
||||
|
||||
#define ECDSA_RS_ECP NULL
|
||||
|
||||
#define ECDSA_BUDGET( ops ) /* no-op; for compatibility */
|
||||
|
||||
#define ECDSA_RS_ENTER( SUB ) (void) rs_ctx
|
||||
#define ECDSA_RS_LEAVE( SUB ) (void) rs_ctx
|
||||
|
||||
#endif /* MBEDTLS_ECP_RESTARTABLE */
|
||||
|
||||
/*
|
||||
* Derive a suitable integer for group grp from a buffer of length len
|
||||
* SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3
|
||||
|
|
@ -70,13 +242,17 @@ cleanup:
|
|||
* Compute ECDSA signature of a hashed message (SEC1 4.1.3)
|
||||
* Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message)
|
||||
*/
|
||||
int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
|
||||
static int ecdsa_sign_restartable( mbedtls_ecp_group *grp,
|
||||
mbedtls_mpi *r, mbedtls_mpi *s,
|
||||
const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
|
||||
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
|
||||
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
|
||||
mbedtls_ecdsa_restart_ctx *rs_ctx )
|
||||
{
|
||||
int ret, key_tries, sign_tries, blind_tries;
|
||||
int ret, key_tries, sign_tries;
|
||||
int *p_sign_tries = &sign_tries, *p_key_tries = &key_tries;
|
||||
mbedtls_ecp_point R;
|
||||
mbedtls_mpi k, e, t;
|
||||
mbedtls_mpi *pk = &k, *pr = r;
|
||||
|
||||
/* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */
|
||||
if( grp->N.p == NULL )
|
||||
|
|
@ -89,26 +265,72 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
|
|||
mbedtls_ecp_point_init( &R );
|
||||
mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t );
|
||||
|
||||
sign_tries = 0;
|
||||
ECDSA_RS_ENTER( sig );
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( rs_ctx != NULL && rs_ctx->sig != NULL )
|
||||
{
|
||||
/* redirect to our context */
|
||||
p_sign_tries = &rs_ctx->sig->sign_tries;
|
||||
p_key_tries = &rs_ctx->sig->key_tries;
|
||||
pk = &rs_ctx->sig->k;
|
||||
pr = &rs_ctx->sig->r;
|
||||
|
||||
/* jump to current step */
|
||||
if( rs_ctx->sig->state == ecdsa_sig_mul )
|
||||
goto mul;
|
||||
if( rs_ctx->sig->state == ecdsa_sig_modn )
|
||||
goto modn;
|
||||
}
|
||||
#endif /* MBEDTLS_ECP_RESTARTABLE */
|
||||
|
||||
*p_sign_tries = 0;
|
||||
do
|
||||
{
|
||||
if( *p_sign_tries++ > 10 )
|
||||
{
|
||||
ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Steps 1-3: generate a suitable ephemeral keypair
|
||||
* and set r = xR mod n
|
||||
*/
|
||||
key_tries = 0;
|
||||
*p_key_tries = 0;
|
||||
do
|
||||
{
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( grp, &k, &R, f_rng, p_rng ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( r, &R.X, &grp->N ) );
|
||||
|
||||
if( key_tries++ > 10 )
|
||||
if( *p_key_tries++ > 10 )
|
||||
{
|
||||
ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, pk, f_rng, p_rng ) );
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( rs_ctx != NULL && rs_ctx->sig != NULL )
|
||||
rs_ctx->sig->state = ecdsa_sig_mul;
|
||||
|
||||
mul:
|
||||
#endif
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &R, pk, &grp->G,
|
||||
f_rng, p_rng, ECDSA_RS_ECP ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pr, &R.X, &grp->N ) );
|
||||
}
|
||||
while( mbedtls_mpi_cmp_int( r, 0 ) == 0 );
|
||||
while( mbedtls_mpi_cmp_int( pr, 0 ) == 0 );
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( rs_ctx != NULL && rs_ctx->sig != NULL )
|
||||
rs_ctx->sig->state = ecdsa_sig_modn;
|
||||
|
||||
modn:
|
||||
#endif
|
||||
/*
|
||||
* Accounting for everything up to the end of the loop
|
||||
* (step 6, but checking now avoids saving e and t)
|
||||
*/
|
||||
ECDSA_BUDGET( MBEDTLS_ECP_OPS_INV + 4 );
|
||||
|
||||
/*
|
||||
* Step 5: derive MPI from hashed message
|
||||
|
|
@ -119,57 +341,60 @@ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
|
|||
* Generate a random value to blind inv_mod in next step,
|
||||
* avoiding a potential timing leak.
|
||||
*/
|
||||
blind_tries = 0;
|
||||
do
|
||||
{
|
||||
size_t n_size = ( grp->nbits + 7 ) / 8;
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng, p_rng ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &t, 8 * n_size - grp->nbits ) );
|
||||
|
||||
/* See mbedtls_ecp_gen_keypair() */
|
||||
if( ++blind_tries > 30 )
|
||||
return( MBEDTLS_ERR_ECP_RANDOM_FAILED );
|
||||
}
|
||||
while( mbedtls_mpi_cmp_int( &t, 1 ) < 0 ||
|
||||
mbedtls_mpi_cmp_mpi( &t, &grp->N ) >= 0 );
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, &t, f_rng, p_rng ) );
|
||||
|
||||
/*
|
||||
* Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n
|
||||
*/
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, r, d ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, pr, d ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &e, &e, s ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &e, &e, &t ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &k, &k, &t ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, &k, &grp->N ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pk, pk, &t ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, pk, &grp->N ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) );
|
||||
|
||||
if( sign_tries++ > 10 )
|
||||
{
|
||||
ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
while( mbedtls_mpi_cmp_int( s, 0 ) == 0 );
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( rs_ctx != NULL && rs_ctx->sig != NULL )
|
||||
mbedtls_mpi_copy( r, pr );
|
||||
#endif
|
||||
|
||||
cleanup:
|
||||
mbedtls_ecp_point_free( &R );
|
||||
mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t );
|
||||
|
||||
ECDSA_RS_LEAVE( sig );
|
||||
|
||||
return( ret );
|
||||
}
|
||||
#endif /* MBEDTLS_ECDSA_SIGN_ALT */
|
||||
|
||||
/*
|
||||
* Compute ECDSA signature of a hashed message
|
||||
*/
|
||||
int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
|
||||
const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
|
||||
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
|
||||
{
|
||||
return( ecdsa_sign_restartable( grp, r, s, d, buf, blen,
|
||||
f_rng, p_rng, NULL ) );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
|
||||
/*
|
||||
* Deterministic signature wrapper
|
||||
*/
|
||||
int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
|
||||
static int ecdsa_sign_det_restartable( mbedtls_ecp_group *grp,
|
||||
mbedtls_mpi *r, mbedtls_mpi *s,
|
||||
const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
|
||||
mbedtls_md_type_t md_alg )
|
||||
mbedtls_md_type_t md_alg,
|
||||
mbedtls_ecdsa_restart_ctx *rs_ctx )
|
||||
{
|
||||
int ret;
|
||||
mbedtls_hmac_drbg_context rng_ctx;
|
||||
mbedtls_hmac_drbg_context *p_rng = &rng_ctx;
|
||||
unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES];
|
||||
size_t grp_len = ( grp->nbits + 7 ) / 8;
|
||||
const mbedtls_md_info_t *md_info;
|
||||
|
|
@ -181,21 +406,53 @@ int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi
|
|||
mbedtls_mpi_init( &h );
|
||||
mbedtls_hmac_drbg_init( &rng_ctx );
|
||||
|
||||
ECDSA_RS_ENTER( det );
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( rs_ctx != NULL && rs_ctx->det != NULL )
|
||||
{
|
||||
/* redirect to our context */
|
||||
p_rng = &rs_ctx->det->rng_ctx;
|
||||
|
||||
/* jump to current step */
|
||||
if( rs_ctx->det->state == ecdsa_det_sign )
|
||||
goto sign;
|
||||
}
|
||||
#endif /* MBEDTLS_ECP_RESTARTABLE */
|
||||
|
||||
/* Use private key and message hash (reduced) to initialize HMAC_DRBG */
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, data, grp_len ) );
|
||||
MBEDTLS_MPI_CHK( derive_mpi( grp, &h, buf, blen ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) );
|
||||
mbedtls_hmac_drbg_seed_buf( &rng_ctx, md_info, data, 2 * grp_len );
|
||||
mbedtls_hmac_drbg_seed_buf( p_rng, md_info, data, 2 * grp_len );
|
||||
|
||||
ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen,
|
||||
mbedtls_hmac_drbg_random, &rng_ctx );
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( rs_ctx != NULL && rs_ctx->det != NULL )
|
||||
rs_ctx->det->state = ecdsa_det_sign;
|
||||
|
||||
sign:
|
||||
#endif
|
||||
ret = ecdsa_sign_restartable( grp, r, s, d, buf, blen,
|
||||
mbedtls_hmac_drbg_random, p_rng, rs_ctx );
|
||||
|
||||
cleanup:
|
||||
mbedtls_hmac_drbg_free( &rng_ctx );
|
||||
mbedtls_mpi_free( &h );
|
||||
|
||||
ECDSA_RS_LEAVE( det );
|
||||
|
||||
return( ret );
|
||||
}
|
||||
|
||||
/*
|
||||
* Deterministic signature wrapper
|
||||
*/
|
||||
int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
|
||||
const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
|
||||
mbedtls_md_type_t md_alg )
|
||||
{
|
||||
return( ecdsa_sign_det_restartable( grp, r, s, d, buf, blen, md_alg, NULL ) );
|
||||
}
|
||||
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
|
||||
|
||||
#if !defined(MBEDTLS_ECDSA_VERIFY_ALT)
|
||||
|
|
@ -203,21 +460,40 @@ cleanup:
|
|||
* Verify ECDSA signature of hashed message (SEC1 4.1.4)
|
||||
* Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message)
|
||||
*/
|
||||
int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
|
||||
const unsigned char *buf, size_t blen,
|
||||
const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s)
|
||||
static int ecdsa_verify_restartable( mbedtls_ecp_group *grp,
|
||||
const unsigned char *buf, size_t blen,
|
||||
const mbedtls_ecp_point *Q,
|
||||
const mbedtls_mpi *r, const mbedtls_mpi *s,
|
||||
mbedtls_ecdsa_restart_ctx *rs_ctx )
|
||||
{
|
||||
int ret;
|
||||
mbedtls_mpi e, s_inv, u1, u2;
|
||||
mbedtls_ecp_point R;
|
||||
mbedtls_mpi *pu1 = &u1, *pu2 = &u2;
|
||||
|
||||
mbedtls_ecp_point_init( &R );
|
||||
mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv ); mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 );
|
||||
mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv );
|
||||
mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 );
|
||||
|
||||
/* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */
|
||||
if( grp->N.p == NULL )
|
||||
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
|
||||
|
||||
ECDSA_RS_ENTER( ver );
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( rs_ctx != NULL && rs_ctx->ver != NULL )
|
||||
{
|
||||
/* redirect to our context */
|
||||
pu1 = &rs_ctx->ver->u1;
|
||||
pu2 = &rs_ctx->ver->u2;
|
||||
|
||||
/* jump to current step */
|
||||
if( rs_ctx->ver->state == ecdsa_ver_muladd )
|
||||
goto muladd;
|
||||
}
|
||||
#endif /* MBEDTLS_ECP_RESTARTABLE */
|
||||
|
||||
/*
|
||||
* Step 1: make sure r and s are in range 1..n-1
|
||||
*/
|
||||
|
|
@ -228,11 +504,6 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Additional precaution: make sure Q is valid
|
||||
*/
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) );
|
||||
|
||||
/*
|
||||
* Step 3: derive MPI from hashed message
|
||||
*/
|
||||
|
|
@ -241,21 +512,27 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
|
|||
/*
|
||||
* Step 4: u1 = e / s mod n, u2 = r / s mod n
|
||||
*/
|
||||
ECDSA_BUDGET( MBEDTLS_ECP_OPS_CHK + MBEDTLS_ECP_OPS_INV + 2 );
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) );
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u1, &e, &s_inv ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u1, &u1, &grp->N ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu1, &e, &s_inv ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu1, pu1, &grp->N ) );
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u2, r, &s_inv ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u2, &u2, &grp->N ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu2, r, &s_inv ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu2, pu2, &grp->N ) );
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( rs_ctx != NULL && rs_ctx->ver != NULL )
|
||||
rs_ctx->ver->state = ecdsa_ver_muladd;
|
||||
|
||||
muladd:
|
||||
#endif
|
||||
/*
|
||||
* Step 5: R = u1 G + u2 Q
|
||||
*
|
||||
* Since we're not using any secret data, no need to pass a RNG to
|
||||
* mbedtls_ecp_mul() for countermesures.
|
||||
*/
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, &R, &u1, &grp->G, &u2, Q ) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecp_muladd_restartable( grp,
|
||||
&R, pu1, &grp->G, pu2, Q, ECDSA_RS_ECP ) );
|
||||
|
||||
if( mbedtls_ecp_is_zero( &R ) )
|
||||
{
|
||||
|
|
@ -280,12 +557,25 @@ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
|
|||
|
||||
cleanup:
|
||||
mbedtls_ecp_point_free( &R );
|
||||
mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv ); mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 );
|
||||
mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv );
|
||||
mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 );
|
||||
|
||||
ECDSA_RS_LEAVE( ver );
|
||||
|
||||
return( ret );
|
||||
}
|
||||
#endif /* MBEDTLS_ECDSA_VERIFY_ALT */
|
||||
|
||||
/*
|
||||
* Verify ECDSA signature of hashed message
|
||||
*/
|
||||
int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp,
|
||||
const unsigned char *buf, size_t blen,
|
||||
const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s)
|
||||
{
|
||||
return( ecdsa_verify_restartable( grp, buf, blen, Q, r, s, NULL ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a signature (given by context) to ASN.1
|
||||
*/
|
||||
|
|
@ -313,11 +603,13 @@ static int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s,
|
|||
/*
|
||||
* Compute and write signature
|
||||
*/
|
||||
int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg,
|
||||
int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx,
|
||||
mbedtls_md_type_t md_alg,
|
||||
const unsigned char *hash, size_t hlen,
|
||||
unsigned char *sig, size_t *slen,
|
||||
int (*f_rng)(void *, unsigned char *, size_t),
|
||||
void *p_rng )
|
||||
void *p_rng,
|
||||
mbedtls_ecdsa_restart_ctx *rs_ctx )
|
||||
{
|
||||
int ret;
|
||||
mbedtls_mpi r, s;
|
||||
|
|
@ -329,13 +621,13 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t
|
|||
(void) f_rng;
|
||||
(void) p_rng;
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det( &ctx->grp, &r, &s, &ctx->d,
|
||||
hash, hlen, md_alg ) );
|
||||
MBEDTLS_MPI_CHK( ecdsa_sign_det_restartable( &ctx->grp, &r, &s, &ctx->d,
|
||||
hash, hlen, md_alg, rs_ctx ) );
|
||||
#else
|
||||
(void) md_alg;
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d,
|
||||
hash, hlen, f_rng, p_rng ) );
|
||||
MBEDTLS_MPI_CHK( ecdsa_sign_restartable( &ctx->grp, &r, &s, &ctx->d,
|
||||
hash, hlen, f_rng, p_rng, rs_ctx ) );
|
||||
#endif
|
||||
|
||||
MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) );
|
||||
|
|
@ -347,6 +639,19 @@ cleanup:
|
|||
return( ret );
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute and write signature
|
||||
*/
|
||||
int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg,
|
||||
const unsigned char *hash, size_t hlen,
|
||||
unsigned char *sig, size_t *slen,
|
||||
int (*f_rng)(void *, unsigned char *, size_t),
|
||||
void *p_rng )
|
||||
{
|
||||
return( mbedtls_ecdsa_write_signature_restartable(
|
||||
ctx, md_alg, hash, hlen, sig, slen, f_rng, p_rng, NULL ) );
|
||||
}
|
||||
|
||||
#if ! defined(MBEDTLS_DEPRECATED_REMOVED) && \
|
||||
defined(MBEDTLS_ECDSA_DETERMINISTIC)
|
||||
int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx,
|
||||
|
|
@ -365,6 +670,18 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx,
|
|||
int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx,
|
||||
const unsigned char *hash, size_t hlen,
|
||||
const unsigned char *sig, size_t slen )
|
||||
{
|
||||
return( mbedtls_ecdsa_read_signature_restartable(
|
||||
ctx, hash, hlen, sig, slen, NULL ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Restartable read and check signature
|
||||
*/
|
||||
int mbedtls_ecdsa_read_signature_restartable( mbedtls_ecdsa_context *ctx,
|
||||
const unsigned char *hash, size_t hlen,
|
||||
const unsigned char *sig, size_t slen,
|
||||
mbedtls_ecdsa_restart_ctx *rs_ctx )
|
||||
{
|
||||
int ret;
|
||||
unsigned char *p = (unsigned char *) sig;
|
||||
|
|
@ -396,8 +713,8 @@ int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen,
|
||||
&ctx->Q, &r, &s ) ) != 0 )
|
||||
if( ( ret = ecdsa_verify_restartable( &ctx->grp, hash, hlen,
|
||||
&ctx->Q, &r, &s, rs_ctx ) ) != 0 )
|
||||
goto cleanup;
|
||||
|
||||
/* At this point we know that the buffer starts with a valid signature.
|
||||
|
|
@ -458,4 +775,42 @@ void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx )
|
|||
mbedtls_ecp_keypair_free( ctx );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
/*
|
||||
* Initialize a restart context
|
||||
*/
|
||||
void mbedtls_ecdsa_restart_init( mbedtls_ecdsa_restart_ctx *ctx )
|
||||
{
|
||||
mbedtls_ecp_restart_init( &ctx->ecp );
|
||||
|
||||
ctx->ver = NULL;
|
||||
ctx->sig = NULL;
|
||||
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
|
||||
ctx->det = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the components of a restart context
|
||||
*/
|
||||
void mbedtls_ecdsa_restart_free( mbedtls_ecdsa_restart_ctx *ctx )
|
||||
{
|
||||
mbedtls_ecp_restart_free( &ctx->ecp );
|
||||
|
||||
ecdsa_restart_ver_free( ctx->ver );
|
||||
mbedtls_free( ctx->ver );
|
||||
ctx->ver = NULL;
|
||||
|
||||
ecdsa_restart_sig_free( ctx->sig );
|
||||
mbedtls_free( ctx->sig );
|
||||
ctx->sig = NULL;
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
|
||||
ecdsa_restart_det_free( ctx->det );
|
||||
mbedtls_free( ctx->det );
|
||||
ctx->det = NULL;
|
||||
#endif
|
||||
}
|
||||
#endif /* MBEDTLS_ECP_RESTARTABLE */
|
||||
|
||||
#endif /* MBEDTLS_ECDSA_C */
|
||||
|
|
|
|||
1050
library/ecp.c
1050
library/ecp.c
File diff suppressed because it is too large
Load diff
|
|
@ -289,6 +289,8 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
|
|||
mbedtls_snprintf( buf, buflen, "ECP - The buffer contains a valid signature followed by more data" );
|
||||
if( use_ret == -(MBEDTLS_ERR_ECP_HW_ACCEL_FAILED) )
|
||||
mbedtls_snprintf( buf, buflen, "ECP - The ECP hardware accelerator failed" );
|
||||
if( use_ret == -(MBEDTLS_ERR_ECP_IN_PROGRESS) )
|
||||
mbedtls_snprintf( buf, buflen, "ECP - Operation in progress, call again with the same parameters to continue" );
|
||||
#endif /* MBEDTLS_ECP_C */
|
||||
|
||||
#if defined(MBEDTLS_MD_C)
|
||||
|
|
@ -517,6 +519,8 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
|
|||
mbedtls_snprintf( buf, buflen, "SSL - The asynchronous operation is not completed yet" );
|
||||
if( use_ret == -(MBEDTLS_ERR_SSL_EARLY_MESSAGE) )
|
||||
mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that a message arrived early" );
|
||||
if( use_ret == -(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) )
|
||||
mbedtls_snprintf( buf, buflen, "SSL - A cryptographic operation is in progress. Try again later" );
|
||||
#endif /* MBEDTLS_SSL_TLS_C */
|
||||
|
||||
#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
|
||||
|
|
|
|||
161
library/pk.c
161
library/pk.c
|
|
@ -69,6 +69,34 @@ void mbedtls_pk_free( mbedtls_pk_context *ctx )
|
|||
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_pk_context ) );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
/*
|
||||
* Initialize a restart context
|
||||
*/
|
||||
void mbedtls_pk_restart_init( mbedtls_pk_restart_ctx *ctx )
|
||||
{
|
||||
ctx->pk_info = NULL;
|
||||
ctx->rs_ctx = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the components of a restart context
|
||||
*/
|
||||
void mbedtls_pk_restart_free( mbedtls_pk_restart_ctx *ctx )
|
||||
{
|
||||
if( ctx == NULL || ctx->pk_info == NULL ||
|
||||
ctx->pk_info->rs_free_func == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->pk_info->rs_free_func( ctx->rs_ctx );
|
||||
|
||||
ctx->pk_info = NULL;
|
||||
ctx->rs_ctx = NULL;
|
||||
}
|
||||
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
|
||||
|
||||
/*
|
||||
* Get pk_info structure from type
|
||||
*/
|
||||
|
|
@ -171,6 +199,73 @@ static inline int pk_hashlen_helper( mbedtls_md_type_t md_alg, size_t *hash_len
|
|||
return( 0 );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
/*
|
||||
* Helper to set up a restart context if needed
|
||||
*/
|
||||
static int pk_restart_setup( mbedtls_pk_restart_ctx *ctx,
|
||||
const mbedtls_pk_info_t *info )
|
||||
{
|
||||
/* Don't do anything if already set up or invalid */
|
||||
if( ctx == NULL || ctx->pk_info != NULL )
|
||||
return( 0 );
|
||||
|
||||
/* Should never happen when we're called */
|
||||
if( info->rs_alloc_func == NULL || info->rs_free_func == NULL )
|
||||
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
||||
|
||||
if( ( ctx->rs_ctx = info->rs_alloc_func() ) == NULL )
|
||||
return( MBEDTLS_ERR_PK_ALLOC_FAILED );
|
||||
|
||||
ctx->pk_info = info;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
|
||||
|
||||
/*
|
||||
* Verify a signature (restartable)
|
||||
*/
|
||||
int mbedtls_pk_verify_restartable( mbedtls_pk_context *ctx,
|
||||
mbedtls_md_type_t md_alg,
|
||||
const unsigned char *hash, size_t hash_len,
|
||||
const unsigned char *sig, size_t sig_len,
|
||||
mbedtls_pk_restart_ctx *rs_ctx )
|
||||
{
|
||||
if( ctx == NULL || ctx->pk_info == NULL ||
|
||||
pk_hashlen_helper( md_alg, &hash_len ) != 0 )
|
||||
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
/* optimization: use non-restartable version if restart disabled */
|
||||
if( rs_ctx != NULL &&
|
||||
mbedtls_ecp_restart_is_enabled() &&
|
||||
ctx->pk_info->verify_rs_func != NULL )
|
||||
{
|
||||
int ret;
|
||||
|
||||
if( ( ret = pk_restart_setup( rs_ctx, ctx->pk_info ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
ret = ctx->pk_info->verify_rs_func( ctx->pk_ctx,
|
||||
md_alg, hash, hash_len, sig, sig_len, rs_ctx->rs_ctx );
|
||||
|
||||
if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
|
||||
mbedtls_pk_restart_free( rs_ctx );
|
||||
|
||||
return( ret );
|
||||
}
|
||||
#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
|
||||
(void) rs_ctx;
|
||||
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
|
||||
|
||||
if( ctx->pk_info->verify_func == NULL )
|
||||
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
|
||||
|
||||
return( ctx->pk_info->verify_func( ctx->pk_ctx, md_alg, hash, hash_len,
|
||||
sig, sig_len ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify a signature
|
||||
*/
|
||||
|
|
@ -178,15 +273,8 @@ int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
|
|||
const unsigned char *hash, size_t hash_len,
|
||||
const unsigned char *sig, size_t sig_len )
|
||||
{
|
||||
if( ctx == NULL || ctx->pk_info == NULL ||
|
||||
pk_hashlen_helper( md_alg, &hash_len ) != 0 )
|
||||
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
||||
|
||||
if( ctx->pk_info->verify_func == NULL )
|
||||
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
|
||||
|
||||
return( ctx->pk_info->verify_func( ctx->pk_ctx, md_alg, hash, hash_len,
|
||||
sig, sig_len ) );
|
||||
return( mbedtls_pk_verify_restartable( ctx, md_alg, hash, hash_len,
|
||||
sig, sig_len, NULL ) );
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -247,6 +335,50 @@ int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options,
|
|||
return( mbedtls_pk_verify( ctx, md_alg, hash, hash_len, sig, sig_len ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a signature (restartable)
|
||||
*/
|
||||
int mbedtls_pk_sign_restartable( mbedtls_pk_context *ctx,
|
||||
mbedtls_md_type_t md_alg,
|
||||
const unsigned char *hash, size_t hash_len,
|
||||
unsigned char *sig, size_t *sig_len,
|
||||
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
|
||||
mbedtls_pk_restart_ctx *rs_ctx )
|
||||
{
|
||||
if( ctx == NULL || ctx->pk_info == NULL ||
|
||||
pk_hashlen_helper( md_alg, &hash_len ) != 0 )
|
||||
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
/* optimization: use non-restartable version if restart disabled */
|
||||
if( rs_ctx != NULL &&
|
||||
mbedtls_ecp_restart_is_enabled() &&
|
||||
ctx->pk_info->sign_rs_func != NULL )
|
||||
{
|
||||
int ret;
|
||||
|
||||
if( ( ret = pk_restart_setup( rs_ctx, ctx->pk_info ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
ret = ctx->pk_info->sign_rs_func( ctx->pk_ctx, md_alg,
|
||||
hash, hash_len, sig, sig_len, f_rng, p_rng, rs_ctx->rs_ctx );
|
||||
|
||||
if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
|
||||
mbedtls_pk_restart_free( rs_ctx );
|
||||
|
||||
return( ret );
|
||||
}
|
||||
#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
|
||||
(void) rs_ctx;
|
||||
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
|
||||
|
||||
if( ctx->pk_info->sign_func == NULL )
|
||||
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
|
||||
|
||||
return( ctx->pk_info->sign_func( ctx->pk_ctx, md_alg, hash, hash_len,
|
||||
sig, sig_len, f_rng, p_rng ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a signature
|
||||
*/
|
||||
|
|
@ -255,15 +387,8 @@ int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
|
|||
unsigned char *sig, size_t *sig_len,
|
||||
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
|
||||
{
|
||||
if( ctx == NULL || ctx->pk_info == NULL ||
|
||||
pk_hashlen_helper( md_alg, &hash_len ) != 0 )
|
||||
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
||||
|
||||
if( ctx->pk_info->sign_func == NULL )
|
||||
return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
|
||||
|
||||
return( ctx->pk_info->sign_func( ctx->pk_ctx, md_alg, hash, hash_len,
|
||||
sig, sig_len, f_rng, p_rng ) );
|
||||
return( mbedtls_pk_sign_restartable( ctx, md_alg, hash, hash_len,
|
||||
sig, sig_len, f_rng, p_rng, NULL ) );
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -190,11 +190,19 @@ const mbedtls_pk_info_t mbedtls_rsa_info = {
|
|||
rsa_can_do,
|
||||
rsa_verify_wrap,
|
||||
rsa_sign_wrap,
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
NULL,
|
||||
NULL,
|
||||
#endif
|
||||
rsa_decrypt_wrap,
|
||||
rsa_encrypt_wrap,
|
||||
rsa_check_pair_wrap,
|
||||
rsa_alloc_wrap,
|
||||
rsa_free_wrap,
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
NULL,
|
||||
NULL,
|
||||
#endif
|
||||
rsa_debug,
|
||||
};
|
||||
#endif /* MBEDTLS_RSA_C */
|
||||
|
|
@ -262,6 +270,110 @@ static int eckey_sign_wrap( void *ctx, mbedtls_md_type_t md_alg,
|
|||
return( ret );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
/* Forward declarations */
|
||||
static int ecdsa_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg,
|
||||
const unsigned char *hash, size_t hash_len,
|
||||
const unsigned char *sig, size_t sig_len,
|
||||
void *rs_ctx );
|
||||
|
||||
static int ecdsa_sign_rs_wrap( void *ctx, mbedtls_md_type_t md_alg,
|
||||
const unsigned char *hash, size_t hash_len,
|
||||
unsigned char *sig, size_t *sig_len,
|
||||
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
|
||||
void *rs_ctx );
|
||||
|
||||
/*
|
||||
* Restart context for ECDSA operations with ECKEY context
|
||||
*
|
||||
* We need to store an actual ECDSA context, as we need to pass the same to
|
||||
* the underlying ecdsa function, so we can't create it on the fly every time.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
mbedtls_ecdsa_restart_ctx ecdsa_rs;
|
||||
mbedtls_ecdsa_context ecdsa_ctx;
|
||||
} eckey_restart_ctx;
|
||||
|
||||
static void *eckey_rs_alloc( void )
|
||||
{
|
||||
eckey_restart_ctx *rs_ctx;
|
||||
|
||||
void *ctx = mbedtls_calloc( 1, sizeof( eckey_restart_ctx ) );
|
||||
|
||||
if( ctx != NULL )
|
||||
{
|
||||
rs_ctx = ctx;
|
||||
mbedtls_ecdsa_restart_init( &rs_ctx->ecdsa_rs );
|
||||
mbedtls_ecdsa_init( &rs_ctx->ecdsa_ctx );
|
||||
}
|
||||
|
||||
return( ctx );
|
||||
}
|
||||
|
||||
static void eckey_rs_free( void *ctx )
|
||||
{
|
||||
eckey_restart_ctx *rs_ctx;
|
||||
|
||||
if( ctx == NULL)
|
||||
return;
|
||||
|
||||
rs_ctx = ctx;
|
||||
mbedtls_ecdsa_restart_free( &rs_ctx->ecdsa_rs );
|
||||
mbedtls_ecdsa_free( &rs_ctx->ecdsa_ctx );
|
||||
|
||||
mbedtls_free( ctx );
|
||||
}
|
||||
|
||||
static int eckey_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg,
|
||||
const unsigned char *hash, size_t hash_len,
|
||||
const unsigned char *sig, size_t sig_len,
|
||||
void *rs_ctx )
|
||||
{
|
||||
int ret;
|
||||
eckey_restart_ctx *rs = rs_ctx;
|
||||
|
||||
/* Should never happen */
|
||||
if( rs == NULL )
|
||||
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
||||
|
||||
/* set up our own sub-context if needed (that is, on first run) */
|
||||
if( rs->ecdsa_ctx.grp.pbits == 0 )
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecdsa_from_keypair( &rs->ecdsa_ctx, ctx ) );
|
||||
|
||||
MBEDTLS_MPI_CHK( ecdsa_verify_rs_wrap( &rs->ecdsa_ctx,
|
||||
md_alg, hash, hash_len,
|
||||
sig, sig_len, &rs->ecdsa_rs ) );
|
||||
|
||||
cleanup:
|
||||
return( ret );
|
||||
}
|
||||
|
||||
static int eckey_sign_rs_wrap( void *ctx, mbedtls_md_type_t md_alg,
|
||||
const unsigned char *hash, size_t hash_len,
|
||||
unsigned char *sig, size_t *sig_len,
|
||||
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
|
||||
void *rs_ctx )
|
||||
{
|
||||
int ret;
|
||||
eckey_restart_ctx *rs = rs_ctx;
|
||||
|
||||
/* Should never happen */
|
||||
if( rs == NULL )
|
||||
return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
|
||||
|
||||
/* set up our own sub-context if needed (that is, on first run) */
|
||||
if( rs->ecdsa_ctx.grp.pbits == 0 )
|
||||
MBEDTLS_MPI_CHK( mbedtls_ecdsa_from_keypair( &rs->ecdsa_ctx, ctx ) );
|
||||
|
||||
MBEDTLS_MPI_CHK( ecdsa_sign_rs_wrap( &rs->ecdsa_ctx, md_alg,
|
||||
hash, hash_len, sig, sig_len,
|
||||
f_rng, p_rng, &rs->ecdsa_rs ) );
|
||||
|
||||
cleanup:
|
||||
return( ret );
|
||||
}
|
||||
#endif /* MBEDTLS_ECP_RESTARTABLE */
|
||||
#endif /* MBEDTLS_ECDSA_C */
|
||||
|
||||
static int eckey_check_pair( const void *pub, const void *prv )
|
||||
|
|
@ -301,15 +413,23 @@ const mbedtls_pk_info_t mbedtls_eckey_info = {
|
|||
#if defined(MBEDTLS_ECDSA_C)
|
||||
eckey_verify_wrap,
|
||||
eckey_sign_wrap,
|
||||
#else
|
||||
NULL,
|
||||
NULL,
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
eckey_verify_rs_wrap,
|
||||
eckey_sign_rs_wrap,
|
||||
#endif
|
||||
#else /* MBEDTLS_ECDSA_C */
|
||||
NULL,
|
||||
NULL,
|
||||
#endif /* MBEDTLS_ECDSA_C */
|
||||
NULL,
|
||||
NULL,
|
||||
eckey_check_pair,
|
||||
eckey_alloc_wrap,
|
||||
eckey_free_wrap,
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
eckey_rs_alloc,
|
||||
eckey_rs_free,
|
||||
#endif
|
||||
eckey_debug,
|
||||
};
|
||||
|
||||
|
|
@ -329,11 +449,19 @@ const mbedtls_pk_info_t mbedtls_eckeydh_info = {
|
|||
eckeydh_can_do,
|
||||
NULL,
|
||||
NULL,
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
NULL,
|
||||
NULL,
|
||||
#endif
|
||||
NULL,
|
||||
NULL,
|
||||
eckey_check_pair,
|
||||
eckey_alloc_wrap, /* Same underlying key structure */
|
||||
eckey_free_wrap, /* Same underlying key structure */
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
NULL,
|
||||
NULL,
|
||||
#endif
|
||||
eckey_debug, /* Same underlying key structure */
|
||||
};
|
||||
#endif /* MBEDTLS_ECP_C */
|
||||
|
|
@ -369,6 +497,40 @@ static int ecdsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg,
|
|||
md_alg, hash, hash_len, sig, sig_len, f_rng, p_rng ) );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
static int ecdsa_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg,
|
||||
const unsigned char *hash, size_t hash_len,
|
||||
const unsigned char *sig, size_t sig_len,
|
||||
void *rs_ctx )
|
||||
{
|
||||
int ret;
|
||||
((void) md_alg);
|
||||
|
||||
ret = mbedtls_ecdsa_read_signature_restartable(
|
||||
(mbedtls_ecdsa_context *) ctx,
|
||||
hash, hash_len, sig, sig_len,
|
||||
(mbedtls_ecdsa_restart_ctx *) rs_ctx );
|
||||
|
||||
if( ret == MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH )
|
||||
return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH );
|
||||
|
||||
return( ret );
|
||||
}
|
||||
|
||||
static int ecdsa_sign_rs_wrap( void *ctx, mbedtls_md_type_t md_alg,
|
||||
const unsigned char *hash, size_t hash_len,
|
||||
unsigned char *sig, size_t *sig_len,
|
||||
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
|
||||
void *rs_ctx )
|
||||
{
|
||||
return( mbedtls_ecdsa_write_signature_restartable(
|
||||
(mbedtls_ecdsa_context *) ctx,
|
||||
md_alg, hash, hash_len, sig, sig_len, f_rng, p_rng,
|
||||
(mbedtls_ecdsa_restart_ctx *) rs_ctx ) );
|
||||
|
||||
}
|
||||
#endif /* MBEDTLS_ECP_RESTARTABLE */
|
||||
|
||||
static void *ecdsa_alloc_wrap( void )
|
||||
{
|
||||
void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecdsa_context ) );
|
||||
|
|
@ -385,6 +547,24 @@ static void ecdsa_free_wrap( void *ctx )
|
|||
mbedtls_free( ctx );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
static void *ecdsa_rs_alloc( void )
|
||||
{
|
||||
void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecdsa_restart_ctx ) );
|
||||
|
||||
if( ctx != NULL )
|
||||
mbedtls_ecdsa_restart_init( ctx );
|
||||
|
||||
return( ctx );
|
||||
}
|
||||
|
||||
static void ecdsa_rs_free( void *ctx )
|
||||
{
|
||||
mbedtls_ecdsa_restart_free( ctx );
|
||||
mbedtls_free( ctx );
|
||||
}
|
||||
#endif /* MBEDTLS_ECP_RESTARTABLE */
|
||||
|
||||
const mbedtls_pk_info_t mbedtls_ecdsa_info = {
|
||||
MBEDTLS_PK_ECDSA,
|
||||
"ECDSA",
|
||||
|
|
@ -392,11 +572,19 @@ const mbedtls_pk_info_t mbedtls_ecdsa_info = {
|
|||
ecdsa_can_do,
|
||||
ecdsa_verify_wrap,
|
||||
ecdsa_sign_wrap,
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
ecdsa_verify_rs_wrap,
|
||||
ecdsa_sign_rs_wrap,
|
||||
#endif
|
||||
NULL,
|
||||
NULL,
|
||||
eckey_check_pair, /* Compatible key structures */
|
||||
ecdsa_alloc_wrap,
|
||||
ecdsa_free_wrap,
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
ecdsa_rs_alloc,
|
||||
ecdsa_rs_free,
|
||||
#endif
|
||||
eckey_debug, /* Compatible key structures */
|
||||
};
|
||||
#endif /* MBEDTLS_ECDSA_C */
|
||||
|
|
@ -506,6 +694,10 @@ const mbedtls_pk_info_t mbedtls_rsa_alt_info = {
|
|||
rsa_alt_can_do,
|
||||
NULL,
|
||||
rsa_alt_sign_wrap,
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
NULL,
|
||||
NULL,
|
||||
#endif
|
||||
rsa_alt_decrypt_wrap,
|
||||
NULL,
|
||||
#if defined(MBEDTLS_RSA_C)
|
||||
|
|
@ -515,6 +707,10 @@ const mbedtls_pk_info_t mbedtls_rsa_alt_info = {
|
|||
#endif
|
||||
rsa_alt_alloc_wrap,
|
||||
rsa_alt_free_wrap,
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
NULL,
|
||||
NULL,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1763,6 +1763,14 @@ static int ssl_parse_server_hello( mbedtls_ssl_context *ssl )
|
|||
|
||||
MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s", suite_info->name ) );
|
||||
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( suite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA &&
|
||||
ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
|
||||
{
|
||||
ssl->handshake->ecrs_enabled = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( comp != MBEDTLS_SSL_COMPRESS_NULL
|
||||
#if defined(MBEDTLS_ZLIB_SUPPORT)
|
||||
&& comp != MBEDTLS_SSL_COMPRESS_DEFLATE
|
||||
|
|
@ -2068,6 +2076,10 @@ static int ssl_parse_server_ecdh_params( mbedtls_ssl_context *ssl,
|
|||
(const unsigned char **) p, end ) ) != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_read_params" ), ret );
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
|
||||
ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS;
|
||||
#endif
|
||||
return( ret );
|
||||
}
|
||||
|
||||
|
|
@ -2349,6 +2361,14 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl )
|
|||
#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED ||
|
||||
MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */
|
||||
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ssl->handshake->ecrs_enabled &&
|
||||
ssl->handshake->ecrs_state == ssl_ecrs_ske_start_processing )
|
||||
{
|
||||
goto start_processing;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
|
||||
|
|
@ -2386,6 +2406,12 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl )
|
|||
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ssl->handshake->ecrs_enabled )
|
||||
ssl->handshake->ecrs_state = ssl_ecrs_ske_start_processing;
|
||||
|
||||
start_processing:
|
||||
#endif
|
||||
p = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl );
|
||||
end = ssl->in_msg + ssl->in_hslen;
|
||||
MBEDTLS_SSL_DEBUG_BUF( 3, "server key exchange", p, end - p );
|
||||
|
|
@ -2478,6 +2504,7 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl )
|
|||
mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE;
|
||||
unsigned char *params = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl );
|
||||
size_t params_len = p - params;
|
||||
void *rs_ctx = NULL;
|
||||
|
||||
/*
|
||||
* Handle the digitally-signed structure
|
||||
|
|
@ -2600,12 +2627,25 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl )
|
|||
return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH );
|
||||
}
|
||||
|
||||
if( ( ret = mbedtls_pk_verify( &ssl->session_negotiate->peer_cert->pk,
|
||||
md_alg, hash, hashlen, p, sig_len ) ) != 0 )
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ssl->handshake->ecrs_enabled )
|
||||
rs_ctx = &ssl->handshake->ecrs_ctx.pk;
|
||||
#endif
|
||||
|
||||
if( ( ret = mbedtls_pk_verify_restartable(
|
||||
&ssl->session_negotiate->peer_cert->pk,
|
||||
md_alg, hash, hashlen, p, sig_len, rs_ctx ) ) != 0 )
|
||||
{
|
||||
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
|
||||
MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR );
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
|
||||
#endif
|
||||
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
|
||||
MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR );
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret );
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
|
||||
ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS;
|
||||
#endif
|
||||
return( ret );
|
||||
}
|
||||
}
|
||||
|
|
@ -2903,6 +2943,16 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl )
|
|||
*/
|
||||
i = 4;
|
||||
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ssl->handshake->ecrs_enabled )
|
||||
{
|
||||
if( ssl->handshake->ecrs_state == ssl_ecrs_cke_ecdh_calc_secret )
|
||||
goto ecdh_calc_secret;
|
||||
|
||||
mbedtls_ecdh_enable_restart( &ssl->handshake->ecdh_ctx );
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx,
|
||||
&n,
|
||||
&ssl->out_msg[i], 1000,
|
||||
|
|
@ -2910,11 +2960,26 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl )
|
|||
if( ret != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_public", ret );
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
|
||||
ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS;
|
||||
#endif
|
||||
return( ret );
|
||||
}
|
||||
|
||||
MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q", &ssl->handshake->ecdh_ctx.Q );
|
||||
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ssl->handshake->ecrs_enabled )
|
||||
{
|
||||
ssl->handshake->ecrs_n = n;
|
||||
ssl->handshake->ecrs_state = ssl_ecrs_cke_ecdh_calc_secret;
|
||||
}
|
||||
|
||||
ecdh_calc_secret:
|
||||
if( ssl->handshake->ecrs_enabled )
|
||||
n = ssl->handshake->ecrs_n;
|
||||
#endif
|
||||
if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx,
|
||||
&ssl->handshake->pmslen,
|
||||
ssl->handshake->premaster,
|
||||
|
|
@ -2922,6 +2987,10 @@ static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl )
|
|||
ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret );
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
|
||||
ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS;
|
||||
#endif
|
||||
return( ret );
|
||||
}
|
||||
|
||||
|
|
@ -3140,9 +3209,18 @@ static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
|
|||
unsigned char *hash_start = hash;
|
||||
mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE;
|
||||
unsigned int hashlen;
|
||||
void *rs_ctx = NULL;
|
||||
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) );
|
||||
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ssl->handshake->ecrs_enabled &&
|
||||
ssl->handshake->ecrs_state == ssl_ecrs_crt_vrfy_sign )
|
||||
{
|
||||
goto sign;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret );
|
||||
|
|
@ -3174,8 +3252,15 @@ static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
|
|||
}
|
||||
|
||||
/*
|
||||
* Make an RSA signature of the handshake digests
|
||||
* Make a signature of the handshake digests
|
||||
*/
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ssl->handshake->ecrs_enabled )
|
||||
ssl->handshake->ecrs_state = ssl_ecrs_crt_vrfy_sign;
|
||||
|
||||
sign:
|
||||
#endif
|
||||
|
||||
ssl->handshake->calc_verify( ssl, hash );
|
||||
|
||||
#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
|
||||
|
|
@ -3252,11 +3337,21 @@ static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
|
|||
return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
|
||||
}
|
||||
|
||||
if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), md_alg, hash_start, hashlen,
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ssl->handshake->ecrs_enabled )
|
||||
rs_ctx = &ssl->handshake->ecrs_ctx.pk;
|
||||
#endif
|
||||
|
||||
if( ( ret = mbedtls_pk_sign_restartable( mbedtls_ssl_own_key( ssl ),
|
||||
md_alg, hash_start, hashlen,
|
||||
ssl->out_msg + 6 + offset, &n,
|
||||
ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
|
||||
ssl->conf->f_rng, ssl->conf->p_rng, rs_ctx ) ) != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret );
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
|
||||
ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS;
|
||||
#endif
|
||||
return( ret );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5432,60 +5432,16 @@ write_msg:
|
|||
return( ret );
|
||||
}
|
||||
|
||||
int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
|
||||
/*
|
||||
* Once the certificate message is read, parse it into a cert chain and
|
||||
* perform basic checks, but leave actual verification to the caller
|
||||
*/
|
||||
static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl )
|
||||
{
|
||||
int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
|
||||
int ret;
|
||||
size_t i, n;
|
||||
const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info;
|
||||
int authmode = ssl->conf->authmode;
|
||||
uint8_t alert;
|
||||
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) );
|
||||
|
||||
if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
|
||||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
|
||||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
|
||||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
|
||||
ssl->state++;
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_SSL_SRV_C)
|
||||
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
|
||||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
|
||||
ssl->state++;
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
|
||||
if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET )
|
||||
authmode = ssl->handshake->sni_authmode;
|
||||
#endif
|
||||
|
||||
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
|
||||
authmode == MBEDTLS_SSL_VERIFY_NONE )
|
||||
{
|
||||
ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_SKIP_VERIFY;
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
|
||||
ssl->state++;
|
||||
return( 0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
|
||||
{
|
||||
/* mbedtls_ssl_read_record may have sent an alert already. We
|
||||
let it decide whether to alert. */
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
|
||||
return( ret );
|
||||
}
|
||||
|
||||
ssl->state++;
|
||||
|
||||
#if defined(MBEDTLS_SSL_SRV_C)
|
||||
#if defined(MBEDTLS_SSL_PROTO_SSL3)
|
||||
/*
|
||||
|
|
@ -5505,10 +5461,7 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
|
|||
one. The client should know what's going on, so we
|
||||
don't send an alert. */
|
||||
ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING;
|
||||
if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
|
||||
return( 0 );
|
||||
else
|
||||
return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
|
||||
return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
|
||||
}
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_PROTO_SSL3 */
|
||||
|
|
@ -5529,10 +5482,7 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
|
|||
one. The client should know what's going on, so we
|
||||
don't send an alert. */
|
||||
ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING;
|
||||
if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
|
||||
return( 0 );
|
||||
else
|
||||
return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
|
||||
return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
|
||||
}
|
||||
}
|
||||
#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \
|
||||
|
|
@ -5682,6 +5632,94 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
|
|||
}
|
||||
#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
|
||||
{
|
||||
int ret;
|
||||
const mbedtls_ssl_ciphersuite_t * const ciphersuite_info =
|
||||
ssl->transform_negotiate->ciphersuite_info;
|
||||
#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
|
||||
const int authmode = ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET
|
||||
? ssl->handshake->sni_authmode
|
||||
: ssl->conf->authmode;
|
||||
#else
|
||||
const int authmode = ssl->conf->authmode;
|
||||
#endif
|
||||
void *rs_ctx = NULL;
|
||||
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) );
|
||||
|
||||
if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
|
||||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
|
||||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
|
||||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
|
||||
ssl->state++;
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_SSL_SRV_C)
|
||||
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
|
||||
ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
|
||||
ssl->state++;
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
|
||||
authmode == MBEDTLS_SSL_VERIFY_NONE )
|
||||
{
|
||||
ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_SKIP_VERIFY;
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
|
||||
|
||||
ssl->state++;
|
||||
return( 0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ssl->handshake->ecrs_enabled &&
|
||||
ssl->handshake->ecrs_state == ssl_ecrs_crt_verify )
|
||||
{
|
||||
goto crt_verify;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
|
||||
{
|
||||
/* mbedtls_ssl_read_record may have sent an alert already. We
|
||||
let it decide whether to alert. */
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
|
||||
return( ret );
|
||||
}
|
||||
|
||||
if( ( ret = ssl_parse_certificate_chain( ssl ) ) != 0 )
|
||||
{
|
||||
#if defined(MBEDTLS_SSL_SRV_C)
|
||||
if( ret == MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE &&
|
||||
authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
|
||||
{
|
||||
ret = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ssl->state++;
|
||||
return( ret );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ssl->handshake->ecrs_enabled)
|
||||
ssl->handshake->ecrs_state = ssl_ecrs_crt_verify;
|
||||
|
||||
crt_verify:
|
||||
if( ssl->handshake->ecrs_enabled)
|
||||
rs_ctx = &ssl->handshake->ecrs_ctx;
|
||||
#endif
|
||||
|
||||
if( authmode != MBEDTLS_SSL_VERIFY_NONE )
|
||||
{
|
||||
mbedtls_x509_crt *ca_chain;
|
||||
|
|
@ -5703,19 +5741,24 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
|
|||
/*
|
||||
* Main check: verify certificate
|
||||
*/
|
||||
ret = mbedtls_x509_crt_verify_with_profile(
|
||||
ret = mbedtls_x509_crt_verify_restartable(
|
||||
ssl->session_negotiate->peer_cert,
|
||||
ca_chain, ca_crl,
|
||||
ssl->conf->cert_profile,
|
||||
ssl->hostname,
|
||||
&ssl->session_negotiate->verify_result,
|
||||
ssl->conf->f_vrfy, ssl->conf->p_vrfy );
|
||||
ssl->conf->f_vrfy, ssl->conf->p_vrfy, rs_ctx );
|
||||
|
||||
if( ret != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
|
||||
return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Secondary checks: always done, but change 'ret' only if it was 0
|
||||
*/
|
||||
|
|
@ -5768,6 +5811,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
|
|||
|
||||
if( ret != 0 )
|
||||
{
|
||||
uint8_t alert;
|
||||
|
||||
/* The certificate may have been rejected for several reasons.
|
||||
Pick one and send the corresponding alert. Which alert to send
|
||||
may be a subject of debate in some cases. */
|
||||
|
|
@ -5810,6 +5855,8 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
|
|||
#endif /* MBEDTLS_DEBUG_C */
|
||||
}
|
||||
|
||||
ssl->state++;
|
||||
|
||||
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) );
|
||||
|
||||
return( ret );
|
||||
|
|
@ -6587,6 +6634,10 @@ static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake )
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
mbedtls_x509_crt_restart_init( &handshake->ecrs_ctx );
|
||||
#endif
|
||||
|
||||
#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
|
||||
handshake->sni_authmode = MBEDTLS_SSL_VERIFY_UNSET;
|
||||
#endif
|
||||
|
|
@ -8834,6 +8885,10 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl )
|
|||
}
|
||||
#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_SERVER_NAME_INDICATION */
|
||||
|
||||
#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
|
||||
mbedtls_x509_crt_restart_free( &handshake->ecrs_ctx );
|
||||
#endif
|
||||
|
||||
#if defined(MBEDTLS_SSL_PROTO_DTLS)
|
||||
mbedtls_free( handshake->verify_cookie );
|
||||
ssl_flight_free( handshake->flight );
|
||||
|
|
|
|||
|
|
@ -339,6 +339,9 @@ static const char *features[] = {
|
|||
#if defined(MBEDTLS_ECP_NIST_OPTIM)
|
||||
"MBEDTLS_ECP_NIST_OPTIM",
|
||||
#endif /* MBEDTLS_ECP_NIST_OPTIM */
|
||||
#if defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
"MBEDTLS_ECP_RESTARTABLE",
|
||||
#endif /* MBEDTLS_ECP_RESTARTABLE */
|
||||
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
|
||||
"MBEDTLS_ECDSA_DETERMINISTIC",
|
||||
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
|
||||
|
|
|
|||
|
|
@ -227,6 +227,23 @@ static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile,
|
|||
return( -1 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset (init or clear) a verify_chain
|
||||
*/
|
||||
static void x509_crt_verify_chain_reset(
|
||||
mbedtls_x509_crt_verify_chain *ver_chain )
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for( i = 0; i < MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE; i++ )
|
||||
{
|
||||
ver_chain->items[i].crt = NULL;
|
||||
ver_chain->items[i].flags = -1;
|
||||
}
|
||||
|
||||
ver_chain->len = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
|
||||
*/
|
||||
|
|
@ -1873,7 +1890,8 @@ static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b
|
|||
* Check the signature of a certificate by its parent
|
||||
*/
|
||||
static int x509_crt_check_signature( const mbedtls_x509_crt *child,
|
||||
mbedtls_x509_crt *parent )
|
||||
mbedtls_x509_crt *parent,
|
||||
mbedtls_x509_crt_restart_ctx *rs_ctx )
|
||||
{
|
||||
const mbedtls_md_info_t *md_info;
|
||||
unsigned char hash[MBEDTLS_MD_MAX_SIZE];
|
||||
|
|
@ -1885,14 +1903,24 @@ static int x509_crt_check_signature( const mbedtls_x509_crt *child,
|
|||
return( -1 );
|
||||
}
|
||||
|
||||
if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk,
|
||||
child->sig_md, hash, mbedtls_md_get_size( md_info ),
|
||||
child->sig.p, child->sig.len ) != 0 )
|
||||
{
|
||||
/* Skip expensive computation on obvious mismatch */
|
||||
if( ! mbedtls_pk_can_do( &parent->pk, child->sig_pk ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( rs_ctx != NULL && child->sig_pk == MBEDTLS_PK_ECDSA )
|
||||
{
|
||||
return( mbedtls_pk_verify_restartable( &parent->pk,
|
||||
child->sig_md, hash, mbedtls_md_get_size( md_info ),
|
||||
child->sig.p, child->sig.len, &rs_ctx->pk ) );
|
||||
}
|
||||
#else
|
||||
(void) rs_ctx;
|
||||
#endif
|
||||
|
||||
return( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk,
|
||||
child->sig_md, hash, mbedtls_md_get_size( md_info ),
|
||||
child->sig.p, child->sig.len ) );
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1939,6 +1967,7 @@ static int x509_crt_check_parent( const mbedtls_x509_crt *child,
|
|||
* 1. subject name matches child's issuer
|
||||
* 2. if necessary, the CA bit is set and key usage allows signing certs
|
||||
* 3. for trusted roots, the signature is correct
|
||||
* (for intermediates, the signature is checked and the result reported)
|
||||
* 4. pathlen constraints are satisfied
|
||||
*
|
||||
* If there's a suitable candidate which is also time-valid, return the first
|
||||
|
|
@ -1961,23 +1990,54 @@ static int x509_crt_check_parent( const mbedtls_x509_crt *child,
|
|||
* Arguments:
|
||||
* - [in] child: certificate for which we're looking for a parent
|
||||
* - [in] candidates: chained list of potential parents
|
||||
* - [out] r_parent: parent found (or NULL)
|
||||
* - [out] r_signature_is_good: 1 if child signature by parent is valid, or 0
|
||||
* - [in] top: 1 if candidates consists of trusted roots, ie we're at the top
|
||||
* of the chain, 0 otherwise
|
||||
* - [in] path_cnt: number of intermediates seen so far
|
||||
* - [in] self_cnt: number of self-signed intermediates seen so far
|
||||
* (will never be greater than path_cnt)
|
||||
* - [in-out] rs_ctx: context for restarting operations
|
||||
*
|
||||
* Return value:
|
||||
* - the first suitable parent found (see above regarding time-validity)
|
||||
* - NULL if no suitable parent was found
|
||||
* - 0 on success
|
||||
* - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise
|
||||
*/
|
||||
static mbedtls_x509_crt *x509_crt_find_parent_in( mbedtls_x509_crt *child,
|
||||
mbedtls_x509_crt *candidates,
|
||||
int top,
|
||||
size_t path_cnt,
|
||||
size_t self_cnt )
|
||||
static int x509_crt_find_parent_in(
|
||||
mbedtls_x509_crt *child,
|
||||
mbedtls_x509_crt *candidates,
|
||||
mbedtls_x509_crt **r_parent,
|
||||
int *r_signature_is_good,
|
||||
int top,
|
||||
unsigned path_cnt,
|
||||
unsigned self_cnt,
|
||||
mbedtls_x509_crt_restart_ctx *rs_ctx )
|
||||
{
|
||||
mbedtls_x509_crt *parent, *badtime_parent = NULL;
|
||||
int ret;
|
||||
mbedtls_x509_crt *parent, *fallback_parent;
|
||||
int signature_is_good, fallback_signature_is_good;
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
/* did we have something in progress? */
|
||||
if( rs_ctx != NULL && rs_ctx->parent != NULL )
|
||||
{
|
||||
/* restore saved state */
|
||||
parent = rs_ctx->parent;
|
||||
fallback_parent = rs_ctx->fallback_parent;
|
||||
fallback_signature_is_good = rs_ctx->fallback_signature_is_good;
|
||||
|
||||
/* clear saved state */
|
||||
rs_ctx->parent = NULL;
|
||||
rs_ctx->fallback_parent = NULL;
|
||||
rs_ctx->fallback_signature_is_good = 0;
|
||||
|
||||
/* resume where we left */
|
||||
goto check_signature;
|
||||
}
|
||||
#endif
|
||||
|
||||
fallback_parent = NULL;
|
||||
fallback_signature_is_good = 0;
|
||||
|
||||
for( parent = candidates; parent != NULL; parent = parent->next )
|
||||
{
|
||||
|
|
@ -1993,17 +2053,38 @@ static mbedtls_x509_crt *x509_crt_find_parent_in( mbedtls_x509_crt *child,
|
|||
}
|
||||
|
||||
/* Signature */
|
||||
if( top && x509_crt_check_signature( child, parent ) != 0 )
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
check_signature:
|
||||
#endif
|
||||
ret = x509_crt_check_signature( child, parent, rs_ctx );
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
|
||||
{
|
||||
continue;
|
||||
/* save state */
|
||||
rs_ctx->parent = parent;
|
||||
rs_ctx->fallback_parent = fallback_parent;
|
||||
rs_ctx->fallback_signature_is_good = fallback_signature_is_good;
|
||||
|
||||
return( ret );
|
||||
}
|
||||
#else
|
||||
(void) ret;
|
||||
#endif
|
||||
|
||||
signature_is_good = ret == 0;
|
||||
if( top && ! signature_is_good )
|
||||
continue;
|
||||
|
||||
/* optional time check */
|
||||
if( mbedtls_x509_time_is_past( &parent->valid_to ) ||
|
||||
mbedtls_x509_time_is_future( &parent->valid_from ) )
|
||||
{
|
||||
if( badtime_parent == NULL )
|
||||
badtime_parent = parent;
|
||||
if( fallback_parent == NULL )
|
||||
{
|
||||
fallback_parent = parent;
|
||||
fallback_signature_is_good = signature_is_good;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
|
@ -2011,10 +2092,18 @@ static mbedtls_x509_crt *x509_crt_find_parent_in( mbedtls_x509_crt *child,
|
|||
break;
|
||||
}
|
||||
|
||||
if( parent == NULL )
|
||||
parent = badtime_parent;
|
||||
if( parent != NULL )
|
||||
{
|
||||
*r_parent = parent;
|
||||
*r_signature_is_good = signature_is_good;
|
||||
}
|
||||
else
|
||||
{
|
||||
*r_parent = fallback_parent;
|
||||
*r_signature_is_good = fallback_signature_is_good;
|
||||
}
|
||||
|
||||
return( parent );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2026,34 +2115,78 @@ static mbedtls_x509_crt *x509_crt_find_parent_in( mbedtls_x509_crt *child,
|
|||
* Arguments:
|
||||
* - [in] child: certificate for which we're looking for a parent, followed
|
||||
* by a chain of possible intermediates
|
||||
* - [in] trust_ca: locally trusted CAs
|
||||
* - [out] 1 if parent was found in trust_ca, 0 if found in provided chain
|
||||
* - [in] path_cnt: number of intermediates seen so far
|
||||
* - [in] self_cnt: number of self-signed intermediates seen so far
|
||||
* - [in] trust_ca: list of locally trusted certificates
|
||||
* - [out] parent: parent found (or NULL)
|
||||
* - [out] parent_is_trusted: 1 if returned `parent` is trusted, or 0
|
||||
* - [out] signature_is_good: 1 if child signature by parent is valid, or 0
|
||||
* - [in] path_cnt: number of links in the chain so far (EE -> ... -> child)
|
||||
* - [in] self_cnt: number of self-signed certs in the chain so far
|
||||
* (will always be no greater than path_cnt)
|
||||
* - [in-out] rs_ctx: context for restarting operations
|
||||
*
|
||||
* Return value:
|
||||
* - the first suitable parent found (see find_parent_in() for "suitable")
|
||||
* - NULL if no suitable parent was found
|
||||
* - 0 on success
|
||||
* - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise
|
||||
*/
|
||||
static mbedtls_x509_crt *x509_crt_find_parent( mbedtls_x509_crt *child,
|
||||
mbedtls_x509_crt *trust_ca,
|
||||
int *parent_is_trusted,
|
||||
size_t path_cnt,
|
||||
size_t self_cnt )
|
||||
static int x509_crt_find_parent(
|
||||
mbedtls_x509_crt *child,
|
||||
mbedtls_x509_crt *trust_ca,
|
||||
mbedtls_x509_crt **parent,
|
||||
int *parent_is_trusted,
|
||||
int *signature_is_good,
|
||||
unsigned path_cnt,
|
||||
unsigned self_cnt,
|
||||
mbedtls_x509_crt_restart_ctx *rs_ctx )
|
||||
{
|
||||
mbedtls_x509_crt *parent;
|
||||
int ret;
|
||||
mbedtls_x509_crt *search_list;
|
||||
|
||||
/* Look for a parent in trusted CAs */
|
||||
*parent_is_trusted = 1;
|
||||
parent = x509_crt_find_parent_in( child, trust_ca, 1, path_cnt, self_cnt );
|
||||
|
||||
if( parent != NULL )
|
||||
return( parent );
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
/* restore then clear saved state if we have some stored */
|
||||
if( rs_ctx != NULL && rs_ctx->parent_is_trusted != -1 )
|
||||
{
|
||||
*parent_is_trusted = rs_ctx->parent_is_trusted;
|
||||
rs_ctx->parent_is_trusted = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Look for a parent upwards the chain */
|
||||
*parent_is_trusted = 0;
|
||||
return( x509_crt_find_parent_in( child, child->next, 0, path_cnt, self_cnt ) );
|
||||
while( 1 ) {
|
||||
search_list = *parent_is_trusted ? trust_ca : child->next;
|
||||
|
||||
ret = x509_crt_find_parent_in( child, search_list,
|
||||
parent, signature_is_good,
|
||||
*parent_is_trusted,
|
||||
path_cnt, self_cnt, rs_ctx );
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
|
||||
{
|
||||
/* save state */
|
||||
rs_ctx->parent_is_trusted = *parent_is_trusted;
|
||||
return( ret );
|
||||
}
|
||||
#else
|
||||
(void) ret;
|
||||
#endif
|
||||
|
||||
/* stop here if found or already in second iteration */
|
||||
if( *parent != NULL || *parent_is_trusted == 0 )
|
||||
break;
|
||||
|
||||
/* prepare second iteration */
|
||||
*parent_is_trusted = 0;
|
||||
}
|
||||
|
||||
/* extra precaution against mistakes in the caller */
|
||||
if( parent == NULL )
|
||||
{
|
||||
*parent_is_trusted = 0;
|
||||
*signature_is_good = 0;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2102,11 +2235,24 @@ static int x509_crt_check_ee_locally_trusted(
|
|||
* - EE, Ci1, ..., Ciq cannot be continued with a trusted root
|
||||
* -> return that chain with NOT_TRUSTED set on Ciq
|
||||
*
|
||||
* Tests for (aspects of) this function should include at least:
|
||||
* - trusted EE
|
||||
* - EE -> trusted root
|
||||
* - EE -> intermedate CA -> trusted root
|
||||
* - if relevant: EE untrusted
|
||||
* - if relevant: EE -> intermediate, untrusted
|
||||
* with the aspect under test checked at each relevant level (EE, int, root).
|
||||
* For some aspects longer chains are required, but usually length 2 is
|
||||
* enough (but length 1 is not in general).
|
||||
*
|
||||
* Arguments:
|
||||
* - [in] crt: the cert list EE, C1, ..., Cn
|
||||
* - [in] trust_ca: the trusted list R1, ..., Rp
|
||||
* - [in] ca_crl, profile: as in verify_with_profile()
|
||||
* - [out] ver_chain, chain_len: the built and verified chain
|
||||
* - [out] ver_chain: the built and verified chain
|
||||
* Only valid when return value is 0, may contain garbage otherwise!
|
||||
* Restart note: need not be the same when calling again to resume.
|
||||
* - [in-out] rs_ctx: context for restarting operations
|
||||
*
|
||||
* Return value:
|
||||
* - non-zero if the chain could not be fully built and examined
|
||||
|
|
@ -2118,24 +2264,50 @@ static int x509_crt_verify_chain(
|
|||
mbedtls_x509_crt *trust_ca,
|
||||
mbedtls_x509_crl *ca_crl,
|
||||
const mbedtls_x509_crt_profile *profile,
|
||||
x509_crt_verify_chain_item ver_chain[X509_MAX_VERIFY_CHAIN_SIZE],
|
||||
size_t *chain_len )
|
||||
mbedtls_x509_crt_verify_chain *ver_chain,
|
||||
mbedtls_x509_crt_restart_ctx *rs_ctx )
|
||||
{
|
||||
/* Don't initialize any of those variables here, so that the compiler can
|
||||
* catch potential issues with jumping ahead when restarting */
|
||||
int ret;
|
||||
uint32_t *flags;
|
||||
mbedtls_x509_crt_verify_chain_item *cur;
|
||||
mbedtls_x509_crt *child;
|
||||
mbedtls_x509_crt *parent;
|
||||
int parent_is_trusted = 0;
|
||||
int child_is_trusted = 0;
|
||||
size_t self_cnt = 0;
|
||||
int parent_is_trusted;
|
||||
int child_is_trusted;
|
||||
int signature_is_good;
|
||||
unsigned self_cnt;
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
/* resume if we had an operation in progress */
|
||||
if( rs_ctx != NULL && rs_ctx->in_progress == x509_crt_rs_find_parent )
|
||||
{
|
||||
/* restore saved state */
|
||||
*ver_chain = rs_ctx->ver_chain; /* struct copy */
|
||||
self_cnt = rs_ctx->self_cnt;
|
||||
|
||||
/* restore derived state */
|
||||
cur = &ver_chain->items[ver_chain->len - 1];
|
||||
child = cur->crt;
|
||||
flags = &cur->flags;
|
||||
|
||||
goto find_parent;
|
||||
}
|
||||
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
|
||||
|
||||
child = crt;
|
||||
*chain_len = 0;
|
||||
self_cnt = 0;
|
||||
parent_is_trusted = 0;
|
||||
child_is_trusted = 0;
|
||||
|
||||
while( 1 ) {
|
||||
/* Add certificate to the verification chain */
|
||||
ver_chain[*chain_len].crt = child;
|
||||
flags = &ver_chain[*chain_len].flags;
|
||||
++*chain_len;
|
||||
cur = &ver_chain->items[ver_chain->len];
|
||||
cur->crt = child;
|
||||
cur->flags = 0;
|
||||
ver_chain->len++;
|
||||
flags = &cur->flags;
|
||||
|
||||
/* Check time-validity (all certificates) */
|
||||
if( mbedtls_x509_time_is_past( &child->valid_to ) )
|
||||
|
|
@ -2156,15 +2328,33 @@ static int x509_crt_verify_chain(
|
|||
*flags |= MBEDTLS_X509_BADCERT_BAD_PK;
|
||||
|
||||
/* Special case: EE certs that are locally trusted */
|
||||
if( *chain_len == 1 &&
|
||||
if( ver_chain->len == 1 &&
|
||||
x509_crt_check_ee_locally_trusted( child, trust_ca ) == 0 )
|
||||
{
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
find_parent:
|
||||
#endif
|
||||
/* Look for a parent in trusted CAs or up the chain */
|
||||
parent = x509_crt_find_parent( child, trust_ca, &parent_is_trusted,
|
||||
*chain_len - 1, self_cnt );
|
||||
ret = x509_crt_find_parent( child, trust_ca, &parent,
|
||||
&parent_is_trusted, &signature_is_good,
|
||||
ver_chain->len - 1, self_cnt, rs_ctx );
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
|
||||
{
|
||||
/* save state */
|
||||
rs_ctx->in_progress = x509_crt_rs_find_parent;
|
||||
rs_ctx->self_cnt = self_cnt;
|
||||
rs_ctx->ver_chain = *ver_chain; /* struct copy */
|
||||
|
||||
return( ret );
|
||||
}
|
||||
#else
|
||||
(void) ret;
|
||||
#endif
|
||||
|
||||
/* No parent? We're done here */
|
||||
if( parent == NULL )
|
||||
|
|
@ -2176,7 +2366,7 @@ static int x509_crt_verify_chain(
|
|||
/* Count intermediate self-issued (not necessarily self-signed) certs.
|
||||
* These can occur with some strategies for key rollover, see [SIRO],
|
||||
* and should be excluded from max_pathlen checks. */
|
||||
if( *chain_len != 1 &&
|
||||
if( ver_chain->len != 1 &&
|
||||
x509_name_cmp( &child->issuer, &child->subject ) == 0 )
|
||||
{
|
||||
self_cnt++;
|
||||
|
|
@ -2185,14 +2375,14 @@ static int x509_crt_verify_chain(
|
|||
/* path_cnt is 0 for the first intermediate CA,
|
||||
* and if parent is trusted it's not an intermediate CA */
|
||||
if( ! parent_is_trusted &&
|
||||
*chain_len > MBEDTLS_X509_MAX_INTERMEDIATE_CA )
|
||||
ver_chain->len > MBEDTLS_X509_MAX_INTERMEDIATE_CA )
|
||||
{
|
||||
/* return immediately to avoid overflow the chain array */
|
||||
return( MBEDTLS_ERR_X509_FATAL_ERROR );
|
||||
}
|
||||
|
||||
/* if parent is trusted, the signature was checked by find_parent() */
|
||||
if( ! parent_is_trusted && x509_crt_check_signature( child, parent ) != 0 )
|
||||
/* signature was checked while searching parent */
|
||||
if( ! signature_is_good )
|
||||
*flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;
|
||||
|
||||
/* check size of signing key */
|
||||
|
|
@ -2210,6 +2400,7 @@ static int x509_crt_verify_chain(
|
|||
child = parent;
|
||||
parent = NULL;
|
||||
child_is_trusted = parent_is_trusted;
|
||||
signature_is_good = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2278,21 +2469,22 @@ static void x509_crt_verify_name( const mbedtls_x509_crt *crt,
|
|||
*/
|
||||
static int x509_crt_merge_flags_with_cb(
|
||||
uint32_t *flags,
|
||||
x509_crt_verify_chain_item ver_chain[X509_MAX_VERIFY_CHAIN_SIZE],
|
||||
size_t chain_len,
|
||||
const mbedtls_x509_crt_verify_chain *ver_chain,
|
||||
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
|
||||
void *p_vrfy )
|
||||
{
|
||||
int ret;
|
||||
size_t i;
|
||||
unsigned i;
|
||||
uint32_t cur_flags;
|
||||
const mbedtls_x509_crt_verify_chain_item *cur;
|
||||
|
||||
for( i = chain_len; i != 0; --i )
|
||||
for( i = ver_chain->len; i != 0; --i )
|
||||
{
|
||||
cur_flags = ver_chain[i-1].flags;
|
||||
cur = &ver_chain->items[i-1];
|
||||
cur_flags = cur->flags;
|
||||
|
||||
if( NULL != f_vrfy )
|
||||
if( ( ret = f_vrfy( p_vrfy, ver_chain[i-1].crt, (int) i-1, &cur_flags ) ) != 0 )
|
||||
if( ( ret = f_vrfy( p_vrfy, cur->crt, (int) i-1, &cur_flags ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
*flags |= cur_flags;
|
||||
|
|
@ -2302,7 +2494,7 @@ static int x509_crt_merge_flags_with_cb(
|
|||
}
|
||||
|
||||
/*
|
||||
* Verify the certificate validity
|
||||
* Verify the certificate validity (default profile, not restartable)
|
||||
*/
|
||||
int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt,
|
||||
mbedtls_x509_crt *trust_ca,
|
||||
|
|
@ -2311,19 +2503,13 @@ int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt,
|
|||
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
|
||||
void *p_vrfy )
|
||||
{
|
||||
return( mbedtls_x509_crt_verify_with_profile( crt, trust_ca, ca_crl,
|
||||
&mbedtls_x509_crt_profile_default, cn, flags, f_vrfy, p_vrfy ) );
|
||||
return( mbedtls_x509_crt_verify_restartable( crt, trust_ca, ca_crl,
|
||||
&mbedtls_x509_crt_profile_default, cn, flags,
|
||||
f_vrfy, p_vrfy, NULL ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify the certificate validity, with profile
|
||||
*
|
||||
* This function:
|
||||
* - checks the requested CN (if any)
|
||||
* - checks the type and size of the EE cert's key,
|
||||
* as that isn't done as part of chain building/verification currently
|
||||
* - builds and verifies the chain
|
||||
* - then calls the callback and merges the flags
|
||||
* Verify the certificate validity (user-chosen profile, not restartable)
|
||||
*/
|
||||
int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
|
||||
mbedtls_x509_crt *trust_ca,
|
||||
|
|
@ -2332,16 +2518,38 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
|
|||
const char *cn, uint32_t *flags,
|
||||
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
|
||||
void *p_vrfy )
|
||||
{
|
||||
return( mbedtls_x509_crt_verify_restartable( crt, trust_ca, ca_crl,
|
||||
profile, cn, flags, f_vrfy, p_vrfy, NULL ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify the certificate validity, with profile, restartable version
|
||||
*
|
||||
* This function:
|
||||
* - checks the requested CN (if any)
|
||||
* - checks the type and size of the EE cert's key,
|
||||
* as that isn't done as part of chain building/verification currently
|
||||
* - builds and verifies the chain
|
||||
* - then calls the callback and merges the flags
|
||||
*/
|
||||
int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt,
|
||||
mbedtls_x509_crt *trust_ca,
|
||||
mbedtls_x509_crl *ca_crl,
|
||||
const mbedtls_x509_crt_profile *profile,
|
||||
const char *cn, uint32_t *flags,
|
||||
int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *),
|
||||
void *p_vrfy,
|
||||
mbedtls_x509_crt_restart_ctx *rs_ctx )
|
||||
{
|
||||
int ret;
|
||||
mbedtls_pk_type_t pk_type;
|
||||
x509_crt_verify_chain_item ver_chain[X509_MAX_VERIFY_CHAIN_SIZE];
|
||||
size_t chain_len;
|
||||
uint32_t *ee_flags = &ver_chain[0].flags;
|
||||
mbedtls_x509_crt_verify_chain ver_chain;
|
||||
uint32_t ee_flags;
|
||||
|
||||
*flags = 0;
|
||||
memset( ver_chain, 0, sizeof( ver_chain ) );
|
||||
chain_len = 0;
|
||||
ee_flags = 0;
|
||||
x509_crt_verify_chain_reset( &ver_chain );
|
||||
|
||||
if( profile == NULL )
|
||||
{
|
||||
|
|
@ -2351,28 +2559,36 @@ int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt,
|
|||
|
||||
/* check name if requested */
|
||||
if( cn != NULL )
|
||||
x509_crt_verify_name( crt, cn, ee_flags );
|
||||
x509_crt_verify_name( crt, cn, &ee_flags );
|
||||
|
||||
/* Check the type and size of the key */
|
||||
pk_type = mbedtls_pk_get_type( &crt->pk );
|
||||
|
||||
if( x509_profile_check_pk_alg( profile, pk_type ) != 0 )
|
||||
*ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK;
|
||||
ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK;
|
||||
|
||||
if( x509_profile_check_key( profile, &crt->pk ) != 0 )
|
||||
*ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
|
||||
ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
|
||||
|
||||
/* Check the chain */
|
||||
ret = x509_crt_verify_chain( crt, trust_ca, ca_crl, profile,
|
||||
ver_chain, &chain_len );
|
||||
&ver_chain, rs_ctx );
|
||||
|
||||
if( ret != 0 )
|
||||
goto exit;
|
||||
|
||||
/* Merge end-entity flags */
|
||||
ver_chain.items[0].flags |= ee_flags;
|
||||
|
||||
/* Build final flags, calling callback on the way if any */
|
||||
ret = x509_crt_merge_flags_with_cb( flags,
|
||||
ver_chain, chain_len, f_vrfy, p_vrfy );
|
||||
ret = x509_crt_merge_flags_with_cb( flags, &ver_chain, f_vrfy, p_vrfy );
|
||||
|
||||
exit:
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if( rs_ctx != NULL && ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
|
||||
mbedtls_x509_crt_restart_free( rs_ctx );
|
||||
#endif
|
||||
|
||||
/* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by
|
||||
* the SSL module for authmode optional, but non-zero return from the
|
||||
* callback means a fatal error so it shouldn't be ignored */
|
||||
|
|
@ -2483,4 +2699,36 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt )
|
|||
while( cert_cur != NULL );
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
/*
|
||||
* Initialize a restart context
|
||||
*/
|
||||
void mbedtls_x509_crt_restart_init( mbedtls_x509_crt_restart_ctx *ctx )
|
||||
{
|
||||
mbedtls_pk_restart_init( &ctx->pk );
|
||||
|
||||
ctx->parent = NULL;
|
||||
ctx->fallback_parent = NULL;
|
||||
ctx->fallback_signature_is_good = 0;
|
||||
|
||||
ctx->parent_is_trusted = -1;
|
||||
|
||||
ctx->in_progress = x509_crt_rs_none;
|
||||
ctx->self_cnt = 0;
|
||||
x509_crt_verify_chain_reset( &ctx->ver_chain );
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the components of a restart context
|
||||
*/
|
||||
void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx )
|
||||
{
|
||||
if( ctx == NULL )
|
||||
return;
|
||||
|
||||
mbedtls_pk_restart_free( &ctx->pk );
|
||||
mbedtls_x509_crt_restart_init( ctx );
|
||||
}
|
||||
#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
|
||||
|
||||
#endif /* MBEDTLS_X509_CRT_PARSE_C */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue