mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2024-11-29 23:54:15 +01:00
2036508538
mbedtls_rsa_rsaes_pkcs1_v15_decrypt takes care not to reveal whether the padding is valid or not, even through timing or memory access patterns. This is a defense against an attack published by Bleichenbacher. The attacker can also obtain the same information by observing the length of the plaintext. The current implementation leaks the length of the plaintext through timing and memory access patterns. This commit is a first step towards fixing this leak. It reduces the leak to a single memmove call inside the working buffer.
1971 lines
59 KiB
C
1971 lines
59 KiB
C
/*
|
|
* The RSA public-key cryptosystem
|
|
*
|
|
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
* not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* This file is part of mbed TLS (https://tls.mbed.org)
|
|
*/
|
|
/*
|
|
* RSA was designed by Ron Rivest, Adi Shamir and Len Adleman.
|
|
*
|
|
* http://theory.lcs.mit.edu/~rivest/rsapaper.pdf
|
|
* http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf
|
|
* [3] Malware Guard Extension: Using SGX to Conceal Cache Attacks
|
|
* Michael Schwarz, Samuel Weiser, Daniel Gruss, Clémentine Maurice and
|
|
* Stefan Mangard
|
|
* https://arxiv.org/abs/1702.08719v2
|
|
*
|
|
*/
|
|
|
|
#if !defined(MBEDTLS_CONFIG_FILE)
|
|
#include "mbedtls/config.h"
|
|
#else
|
|
#include MBEDTLS_CONFIG_FILE
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_RSA_C)
|
|
|
|
#include "mbedtls/rsa.h"
|
|
#include "mbedtls/oid.h"
|
|
|
|
#include <string.h>
|
|
|
|
#if defined(MBEDTLS_PKCS1_V21)
|
|
#include "mbedtls/md.h"
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_PKCS1_V15) && !defined(__OpenBSD__)
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_PLATFORM_C)
|
|
#include "mbedtls/platform.h"
|
|
#else
|
|
#include <stdio.h>
|
|
#define mbedtls_printf printf
|
|
#define mbedtls_calloc calloc
|
|
#define mbedtls_free free
|
|
#endif
|
|
|
|
/* Implementation that should never be optimized out by the compiler */
|
|
static void mbedtls_zeroize( void *v, size_t n ) {
|
|
volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
|
|
}
|
|
|
|
/*
|
|
* Initialize an RSA context
|
|
*/
|
|
void mbedtls_rsa_init( mbedtls_rsa_context *ctx,
|
|
int padding,
|
|
int hash_id )
|
|
{
|
|
memset( ctx, 0, sizeof( mbedtls_rsa_context ) );
|
|
|
|
mbedtls_rsa_set_padding( ctx, padding, hash_id );
|
|
|
|
#if defined(MBEDTLS_THREADING_C)
|
|
mbedtls_mutex_init( &ctx->mutex );
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Set padding for an existing RSA context
|
|
*/
|
|
void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, int hash_id )
|
|
{
|
|
ctx->padding = padding;
|
|
ctx->hash_id = hash_id;
|
|
}
|
|
|
|
#if defined(MBEDTLS_GENPRIME)
|
|
|
|
/*
|
|
* Generate an RSA keypair
|
|
*/
|
|
int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
unsigned int nbits, int exponent )
|
|
{
|
|
int ret;
|
|
mbedtls_mpi P1, Q1, H, G;
|
|
|
|
if( f_rng == NULL || nbits < 128 || exponent < 3 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
if( nbits % 2 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 );
|
|
mbedtls_mpi_init( &H ); mbedtls_mpi_init( &G );
|
|
|
|
/*
|
|
* find primes P and Q with Q < P so that:
|
|
* GCD( E, (P-1)*(Q-1) ) == 1
|
|
*/
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->E, exponent ) );
|
|
|
|
do
|
|
{
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->P, nbits >> 1, 0,
|
|
f_rng, p_rng ) );
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->Q, nbits >> 1, 0,
|
|
f_rng, p_rng ) );
|
|
|
|
if( mbedtls_mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 )
|
|
continue;
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) );
|
|
if( mbedtls_mpi_bitlen( &ctx->N ) != nbits )
|
|
continue;
|
|
|
|
if( mbedtls_mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 )
|
|
mbedtls_mpi_swap( &ctx->P, &ctx->Q );
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &P1, &Q1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) );
|
|
}
|
|
while( mbedtls_mpi_cmp_int( &G, 1 ) != 0 );
|
|
|
|
/*
|
|
* D = E^-1 mod ((P-1)*(Q-1))
|
|
* DP = D mod (P - 1)
|
|
* DQ = D mod (Q - 1)
|
|
* QP = Q^-1 mod P
|
|
*/
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->D , &ctx->E, &H ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) );
|
|
|
|
ctx->len = ( mbedtls_mpi_bitlen( &ctx->N ) + 7 ) >> 3;
|
|
|
|
cleanup:
|
|
|
|
mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 ); mbedtls_mpi_free( &H ); mbedtls_mpi_free( &G );
|
|
|
|
if( ret != 0 )
|
|
{
|
|
mbedtls_rsa_free( ctx );
|
|
return( MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
#endif /* MBEDTLS_GENPRIME */
|
|
|
|
/*
|
|
* Check a public RSA key
|
|
*/
|
|
int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx )
|
|
{
|
|
if( !ctx->N.p || !ctx->E.p )
|
|
return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
|
|
|
|
if( ( ctx->N.p[0] & 1 ) == 0 ||
|
|
( ctx->E.p[0] & 1 ) == 0 )
|
|
return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
|
|
|
|
if( mbedtls_mpi_bitlen( &ctx->N ) < 128 ||
|
|
mbedtls_mpi_bitlen( &ctx->N ) > MBEDTLS_MPI_MAX_BITS )
|
|
return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
|
|
|
|
if( mbedtls_mpi_bitlen( &ctx->E ) < 2 ||
|
|
mbedtls_mpi_cmp_mpi( &ctx->E, &ctx->N ) >= 0 )
|
|
return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/*
|
|
* Check a private RSA key
|
|
*/
|
|
int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx )
|
|
{
|
|
int ret;
|
|
mbedtls_mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2, DP, DQ, QP;
|
|
|
|
if( ( ret = mbedtls_rsa_check_pubkey( ctx ) ) != 0 )
|
|
return( ret );
|
|
|
|
if( !ctx->P.p || !ctx->Q.p || !ctx->D.p )
|
|
return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
|
|
|
|
mbedtls_mpi_init( &PQ ); mbedtls_mpi_init( &DE ); mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 );
|
|
mbedtls_mpi_init( &H ); mbedtls_mpi_init( &I ); mbedtls_mpi_init( &G ); mbedtls_mpi_init( &G2 );
|
|
mbedtls_mpi_init( &L1 ); mbedtls_mpi_init( &L2 ); mbedtls_mpi_init( &DP ); mbedtls_mpi_init( &DQ );
|
|
mbedtls_mpi_init( &QP );
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &P1, &Q1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) );
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G2, &P1, &Q1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &L1, &L2, &H, &G2 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &I, &DE, &L1 ) );
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &DP, &ctx->D, &P1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &DQ, &ctx->D, &Q1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &QP, &ctx->Q, &ctx->P ) );
|
|
/*
|
|
* Check for a valid PKCS1v2 private key
|
|
*/
|
|
if( mbedtls_mpi_cmp_mpi( &PQ, &ctx->N ) != 0 ||
|
|
mbedtls_mpi_cmp_mpi( &DP, &ctx->DP ) != 0 ||
|
|
mbedtls_mpi_cmp_mpi( &DQ, &ctx->DQ ) != 0 ||
|
|
mbedtls_mpi_cmp_mpi( &QP, &ctx->QP ) != 0 ||
|
|
mbedtls_mpi_cmp_int( &L2, 0 ) != 0 ||
|
|
mbedtls_mpi_cmp_int( &I, 1 ) != 0 ||
|
|
mbedtls_mpi_cmp_int( &G, 1 ) != 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
|
|
}
|
|
|
|
cleanup:
|
|
mbedtls_mpi_free( &PQ ); mbedtls_mpi_free( &DE ); mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 );
|
|
mbedtls_mpi_free( &H ); mbedtls_mpi_free( &I ); mbedtls_mpi_free( &G ); mbedtls_mpi_free( &G2 );
|
|
mbedtls_mpi_free( &L1 ); mbedtls_mpi_free( &L2 ); mbedtls_mpi_free( &DP ); mbedtls_mpi_free( &DQ );
|
|
mbedtls_mpi_free( &QP );
|
|
|
|
if( ret == MBEDTLS_ERR_RSA_KEY_CHECK_FAILED )
|
|
return( ret );
|
|
|
|
if( ret != 0 )
|
|
return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED + ret );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/*
|
|
* Check if contexts holding a public and private key match
|
|
*/
|
|
int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, const mbedtls_rsa_context *prv )
|
|
{
|
|
if( mbedtls_rsa_check_pubkey( pub ) != 0 ||
|
|
mbedtls_rsa_check_privkey( prv ) != 0 )
|
|
{
|
|
return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
|
|
}
|
|
|
|
if( mbedtls_mpi_cmp_mpi( &pub->N, &prv->N ) != 0 ||
|
|
mbedtls_mpi_cmp_mpi( &pub->E, &prv->E ) != 0 )
|
|
{
|
|
return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/*
|
|
* Do an RSA public key operation
|
|
*/
|
|
int mbedtls_rsa_public( mbedtls_rsa_context *ctx,
|
|
const unsigned char *input,
|
|
unsigned char *output )
|
|
{
|
|
int ret;
|
|
size_t olen;
|
|
mbedtls_mpi T;
|
|
|
|
mbedtls_mpi_init( &T );
|
|
|
|
#if defined(MBEDTLS_THREADING_C)
|
|
if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
|
|
return( ret );
|
|
#endif
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) );
|
|
|
|
if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
|
|
goto cleanup;
|
|
}
|
|
|
|
olen = ctx->len;
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) );
|
|
|
|
cleanup:
|
|
#if defined(MBEDTLS_THREADING_C)
|
|
if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
|
|
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
|
|
#endif
|
|
|
|
mbedtls_mpi_free( &T );
|
|
|
|
if( ret != 0 )
|
|
return( MBEDTLS_ERR_RSA_PUBLIC_FAILED + ret );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/*
|
|
* Generate or update blinding values, see section 10 of:
|
|
* KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
|
|
* DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
|
|
* Berlin Heidelberg, 1996. p. 104-113.
|
|
*/
|
|
static int rsa_prepare_blinding( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
|
|
{
|
|
int ret, count = 0;
|
|
|
|
if( ctx->Vf.p != NULL )
|
|
{
|
|
/* We already have blinding values, just update them by squaring */
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->N ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->N ) );
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Unblinding value: Vf = random number, invertible mod N */
|
|
do {
|
|
if( count++ > 10 )
|
|
return( MBEDTLS_ERR_RSA_RNG_FAILED );
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vf, ctx->len - 1, f_rng, p_rng ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &ctx->Vi, &ctx->Vf, &ctx->N ) );
|
|
} while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 );
|
|
|
|
/* Blinding value: Vi = Vf^(-e) mod N */
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vi, &ctx->Vf, &ctx->N ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vi, &ctx->Vi, &ctx->E, &ctx->N, &ctx->RN ) );
|
|
|
|
|
|
cleanup:
|
|
return( ret );
|
|
}
|
|
|
|
/*
|
|
* Exponent blinding supposed to prevent side-channel attacks using multiple
|
|
* traces of measurements to recover the RSA key. The more collisions are there,
|
|
* the more bits of the key can be recovered. See [3].
|
|
*
|
|
* Collecting n collisions with m bit long blinding value requires 2^(m-m/n)
|
|
* observations on avarage.
|
|
*
|
|
* For example with 28 byte blinding to achieve 2 collisions the adversary has
|
|
* to make 2^112 observations on avarage.
|
|
*
|
|
* (With the currently (as of 2017 April) known best algorithms breaking 2048
|
|
* bit RSA requires approximately as much time as trying out 2^112 random keys.
|
|
* Thus in this sense with 28 byte blinding the security is not reduced by
|
|
* side-channel attacks like the one in [3])
|
|
*
|
|
* This countermeasure does not help if the key recovery is possible with a
|
|
* single trace.
|
|
*/
|
|
#define RSA_EXPONENT_BLINDING 28
|
|
|
|
/*
|
|
* Do an RSA private key operation
|
|
*/
|
|
int mbedtls_rsa_private( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
const unsigned char *input,
|
|
unsigned char *output )
|
|
{
|
|
int ret;
|
|
size_t olen;
|
|
mbedtls_mpi T, T1, T2;
|
|
mbedtls_mpi P1, Q1, R;
|
|
#if defined(MBEDTLS_RSA_NO_CRT)
|
|
mbedtls_mpi D_blind;
|
|
mbedtls_mpi *D = &ctx->D;
|
|
#else
|
|
mbedtls_mpi DP_blind, DQ_blind;
|
|
mbedtls_mpi *DP = &ctx->DP;
|
|
mbedtls_mpi *DQ = &ctx->DQ;
|
|
#endif
|
|
|
|
/* Temporaries holding the initial input and the double
|
|
* checked result; should be the same in the end. */
|
|
mbedtls_mpi I, C;
|
|
|
|
/* Make sure we have private key info, prevent possible misuse */
|
|
#if defined(MBEDTLS_RSA_NO_CRT)
|
|
if( mbedtls_mpi_cmp_int( &ctx->N, 0 ) == 0 ||
|
|
mbedtls_mpi_cmp_int( &ctx->D, 0 ) == 0 ||
|
|
mbedtls_mpi_cmp_int( &ctx->E, 0 ) == 0 ||
|
|
( f_rng != NULL && mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) ||
|
|
( f_rng != NULL && mbedtls_mpi_cmp_int( &ctx->Q, 0 ) == 0 ) )
|
|
{
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
}
|
|
#else /* ! MBEDTLS_RSA_NO_CRT */
|
|
if( mbedtls_mpi_cmp_int( &ctx->N, 0 ) == 0 ||
|
|
mbedtls_mpi_cmp_int( &ctx->E, 0 ) == 0 ||
|
|
mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ||
|
|
mbedtls_mpi_cmp_int( &ctx->Q, 0 ) == 0 ||
|
|
mbedtls_mpi_cmp_int( &ctx->DP, 0 ) == 0 ||
|
|
mbedtls_mpi_cmp_int( &ctx->DQ, 0 ) == 0 ||
|
|
mbedtls_mpi_cmp_int( &ctx->QP, 0 ) == 0 )
|
|
{
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
}
|
|
#endif /* ! MBEDTLS_RSA_NO_CRT */
|
|
|
|
|
|
#if defined(MBEDTLS_THREADING_C)
|
|
if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
|
|
return( ret );
|
|
#endif
|
|
|
|
mbedtls_mpi_init( &I );
|
|
mbedtls_mpi_init( &C );
|
|
|
|
mbedtls_mpi_init( &T ); mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 );
|
|
mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 ); mbedtls_mpi_init( &R );
|
|
|
|
|
|
if( f_rng != NULL )
|
|
{
|
|
#if defined(MBEDTLS_RSA_NO_CRT)
|
|
mbedtls_mpi_init( &D_blind );
|
|
#else
|
|
mbedtls_mpi_init( &DP_blind );
|
|
mbedtls_mpi_init( &DQ_blind );
|
|
#endif
|
|
}
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) );
|
|
if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
|
|
goto cleanup;
|
|
}
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &I, &T ) );
|
|
|
|
if( f_rng != NULL )
|
|
{
|
|
/*
|
|
* Blinding
|
|
* T = T * Vi mod N
|
|
*/
|
|
MBEDTLS_MPI_CHK( rsa_prepare_blinding( ctx, f_rng, p_rng ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &T, &ctx->Vi ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) );
|
|
|
|
/*
|
|
* Exponent blinding
|
|
*/
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) );
|
|
|
|
#if defined(MBEDTLS_RSA_NO_CRT)
|
|
/*
|
|
* D_blind = ( P - 1 ) * ( Q - 1 ) * R + D
|
|
*/
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
|
|
f_rng, p_rng ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &D_blind, &P1, &Q1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &D_blind, &D_blind, &R ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &D_blind, &D_blind, &ctx->D ) );
|
|
|
|
D = &D_blind;
|
|
#else
|
|
/*
|
|
* DP_blind = ( P - 1 ) * R + DP
|
|
*/
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
|
|
f_rng, p_rng ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DP_blind, &P1, &R ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &DP_blind, &DP_blind,
|
|
&ctx->DP ) );
|
|
|
|
DP = &DP_blind;
|
|
|
|
/*
|
|
* DQ_blind = ( Q - 1 ) * R + DQ
|
|
*/
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
|
|
f_rng, p_rng ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DQ_blind, &Q1, &R ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &DQ_blind, &DQ_blind,
|
|
&ctx->DQ ) );
|
|
|
|
DQ = &DQ_blind;
|
|
#endif /* MBEDTLS_RSA_NO_CRT */
|
|
}
|
|
|
|
#if defined(MBEDTLS_RSA_NO_CRT)
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T, &T, D, &ctx->N, &ctx->RN ) );
|
|
#else
|
|
/*
|
|
* Faster decryption using the CRT
|
|
*
|
|
* T1 = input ^ dP mod P
|
|
* T2 = input ^ dQ mod Q
|
|
*/
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T1, &T, DP, &ctx->P, &ctx->RP ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T2, &T, DQ, &ctx->Q, &ctx->RQ ) );
|
|
|
|
/*
|
|
* T = (T1 - T2) * (Q^-1 mod P) mod P
|
|
*/
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T1, &T2 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T, &ctx->QP ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T1, &ctx->P ) );
|
|
|
|
/*
|
|
* T = T2 + T * Q
|
|
*/
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T, &ctx->Q ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T, &T2, &T1 ) );
|
|
#endif /* MBEDTLS_RSA_NO_CRT */
|
|
|
|
if( f_rng != NULL )
|
|
{
|
|
/*
|
|
* Unblind
|
|
* T = T * Vf mod N
|
|
*/
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &T, &ctx->Vf ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) );
|
|
}
|
|
|
|
/* Verify the result to prevent glitching attacks. */
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &C, &T, &ctx->E,
|
|
&ctx->N, &ctx->RN ) );
|
|
if( mbedtls_mpi_cmp_mpi( &C, &I ) != 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_VERIFY_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
olen = ctx->len;
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) );
|
|
|
|
cleanup:
|
|
#if defined(MBEDTLS_THREADING_C)
|
|
if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
|
|
return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
|
|
#endif
|
|
|
|
mbedtls_mpi_free( &T ); mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 );
|
|
mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 ); mbedtls_mpi_free( &R );
|
|
|
|
if( f_rng != NULL )
|
|
{
|
|
#if defined(MBEDTLS_RSA_NO_CRT)
|
|
mbedtls_mpi_free( &D_blind );
|
|
#else
|
|
mbedtls_mpi_free( &DP_blind );
|
|
mbedtls_mpi_free( &DQ_blind );
|
|
#endif
|
|
}
|
|
|
|
mbedtls_mpi_free( &C );
|
|
mbedtls_mpi_free( &I );
|
|
|
|
if( ret != 0 )
|
|
return( MBEDTLS_ERR_RSA_PRIVATE_FAILED + ret );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
#if defined(MBEDTLS_PKCS1_V21)
|
|
/**
|
|
* Generate and apply the MGF1 operation (from PKCS#1 v2.1) to a buffer.
|
|
*
|
|
* \param dst buffer to mask
|
|
* \param dlen length of destination buffer
|
|
* \param src source of the mask generation
|
|
* \param slen length of the source buffer
|
|
* \param md_ctx message digest context to use
|
|
*/
|
|
static void mgf_mask( unsigned char *dst, size_t dlen, unsigned char *src,
|
|
size_t slen, mbedtls_md_context_t *md_ctx )
|
|
{
|
|
unsigned char mask[MBEDTLS_MD_MAX_SIZE];
|
|
unsigned char counter[4];
|
|
unsigned char *p;
|
|
unsigned int hlen;
|
|
size_t i, use_len;
|
|
|
|
memset( mask, 0, MBEDTLS_MD_MAX_SIZE );
|
|
memset( counter, 0, 4 );
|
|
|
|
hlen = mbedtls_md_get_size( md_ctx->md_info );
|
|
|
|
// Generate and apply dbMask
|
|
//
|
|
p = dst;
|
|
|
|
while( dlen > 0 )
|
|
{
|
|
use_len = hlen;
|
|
if( dlen < hlen )
|
|
use_len = dlen;
|
|
|
|
mbedtls_md_starts( md_ctx );
|
|
mbedtls_md_update( md_ctx, src, slen );
|
|
mbedtls_md_update( md_ctx, counter, 4 );
|
|
mbedtls_md_finish( md_ctx, mask );
|
|
|
|
for( i = 0; i < use_len; ++i )
|
|
*p++ ^= mask[i];
|
|
|
|
counter[3]++;
|
|
|
|
dlen -= use_len;
|
|
}
|
|
|
|
mbedtls_zeroize( mask, sizeof( mask ) );
|
|
}
|
|
#endif /* MBEDTLS_PKCS1_V21 */
|
|
|
|
#if defined(MBEDTLS_PKCS1_V21)
|
|
/*
|
|
* Implementation of the PKCS#1 v2.1 RSAES-OAEP-ENCRYPT function
|
|
*/
|
|
int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
int mode,
|
|
const unsigned char *label, size_t label_len,
|
|
size_t ilen,
|
|
const unsigned char *input,
|
|
unsigned char *output )
|
|
{
|
|
size_t olen;
|
|
int ret;
|
|
unsigned char *p = output;
|
|
unsigned int hlen;
|
|
const mbedtls_md_info_t *md_info;
|
|
mbedtls_md_context_t md_ctx;
|
|
|
|
if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
if( f_rng == NULL )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id );
|
|
if( md_info == NULL )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
olen = ctx->len;
|
|
hlen = mbedtls_md_get_size( md_info );
|
|
|
|
// first comparison checks for overflow
|
|
if( ilen + 2 * hlen + 2 < ilen || olen < ilen + 2 * hlen + 2 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
memset( output, 0, olen );
|
|
|
|
*p++ = 0;
|
|
|
|
// Generate a random octet string seed
|
|
//
|
|
if( ( ret = f_rng( p_rng, p, hlen ) ) != 0 )
|
|
return( MBEDTLS_ERR_RSA_RNG_FAILED + ret );
|
|
|
|
p += hlen;
|
|
|
|
// Construct DB
|
|
//
|
|
mbedtls_md( md_info, label, label_len, p );
|
|
p += hlen;
|
|
p += olen - 2 * hlen - 2 - ilen;
|
|
*p++ = 1;
|
|
memcpy( p, input, ilen );
|
|
|
|
mbedtls_md_init( &md_ctx );
|
|
if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
|
|
{
|
|
mbedtls_md_free( &md_ctx );
|
|
return( ret );
|
|
}
|
|
|
|
// maskedDB: Apply dbMask to DB
|
|
//
|
|
mgf_mask( output + hlen + 1, olen - hlen - 1, output + 1, hlen,
|
|
&md_ctx );
|
|
|
|
// maskedSeed: Apply seedMask to seed
|
|
//
|
|
mgf_mask( output + 1, hlen, output + hlen + 1, olen - hlen - 1,
|
|
&md_ctx );
|
|
|
|
mbedtls_md_free( &md_ctx );
|
|
|
|
return( ( mode == MBEDTLS_RSA_PUBLIC )
|
|
? mbedtls_rsa_public( ctx, output, output )
|
|
: mbedtls_rsa_private( ctx, f_rng, p_rng, output, output ) );
|
|
}
|
|
#endif /* MBEDTLS_PKCS1_V21 */
|
|
|
|
#if defined(MBEDTLS_PKCS1_V15)
|
|
/*
|
|
* Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function
|
|
*/
|
|
int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
int mode, size_t ilen,
|
|
const unsigned char *input,
|
|
unsigned char *output )
|
|
{
|
|
size_t nb_pad, olen;
|
|
int ret;
|
|
unsigned char *p = output;
|
|
|
|
if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
// We don't check p_rng because it won't be dereferenced here
|
|
if( f_rng == NULL || input == NULL || output == NULL )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
olen = ctx->len;
|
|
|
|
// first comparison checks for overflow
|
|
if( ilen + 11 < ilen || olen < ilen + 11 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
nb_pad = olen - 3 - ilen;
|
|
|
|
*p++ = 0;
|
|
if( mode == MBEDTLS_RSA_PUBLIC )
|
|
{
|
|
*p++ = MBEDTLS_RSA_CRYPT;
|
|
|
|
while( nb_pad-- > 0 )
|
|
{
|
|
int rng_dl = 100;
|
|
|
|
do {
|
|
ret = f_rng( p_rng, p, 1 );
|
|
} while( *p == 0 && --rng_dl && ret == 0 );
|
|
|
|
// Check if RNG failed to generate data
|
|
//
|
|
if( rng_dl == 0 || ret != 0 )
|
|
return( MBEDTLS_ERR_RSA_RNG_FAILED + ret );
|
|
|
|
p++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*p++ = MBEDTLS_RSA_SIGN;
|
|
|
|
while( nb_pad-- > 0 )
|
|
*p++ = 0xFF;
|
|
}
|
|
|
|
*p++ = 0;
|
|
memcpy( p, input, ilen );
|
|
|
|
return( ( mode == MBEDTLS_RSA_PUBLIC )
|
|
? mbedtls_rsa_public( ctx, output, output )
|
|
: mbedtls_rsa_private( ctx, f_rng, p_rng, output, output ) );
|
|
}
|
|
#endif /* MBEDTLS_PKCS1_V15 */
|
|
|
|
/*
|
|
* Add the message padding, then do an RSA operation
|
|
*/
|
|
int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
int mode, size_t ilen,
|
|
const unsigned char *input,
|
|
unsigned char *output )
|
|
{
|
|
switch( ctx->padding )
|
|
{
|
|
#if defined(MBEDTLS_PKCS1_V15)
|
|
case MBEDTLS_RSA_PKCS_V15:
|
|
return mbedtls_rsa_rsaes_pkcs1_v15_encrypt( ctx, f_rng, p_rng, mode, ilen,
|
|
input, output );
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_PKCS1_V21)
|
|
case MBEDTLS_RSA_PKCS_V21:
|
|
return mbedtls_rsa_rsaes_oaep_encrypt( ctx, f_rng, p_rng, mode, NULL, 0,
|
|
ilen, input, output );
|
|
#endif
|
|
|
|
default:
|
|
return( MBEDTLS_ERR_RSA_INVALID_PADDING );
|
|
}
|
|
}
|
|
|
|
#if defined(MBEDTLS_PKCS1_V21)
|
|
/*
|
|
* Implementation of the PKCS#1 v2.1 RSAES-OAEP-DECRYPT function
|
|
*/
|
|
int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
int mode,
|
|
const unsigned char *label, size_t label_len,
|
|
size_t *olen,
|
|
const unsigned char *input,
|
|
unsigned char *output,
|
|
size_t output_max_len )
|
|
{
|
|
int ret;
|
|
size_t ilen, i, pad_len;
|
|
unsigned char *p, bad, pad_done;
|
|
unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
|
|
unsigned char lhash[MBEDTLS_MD_MAX_SIZE];
|
|
unsigned int hlen;
|
|
const mbedtls_md_info_t *md_info;
|
|
mbedtls_md_context_t md_ctx;
|
|
|
|
/*
|
|
* Parameters sanity checks
|
|
*/
|
|
if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
ilen = ctx->len;
|
|
|
|
if( ilen < 16 || ilen > sizeof( buf ) )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id );
|
|
if( md_info == NULL )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
hlen = mbedtls_md_get_size( md_info );
|
|
|
|
// checking for integer underflow
|
|
if( 2 * hlen + 2 > ilen )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
/*
|
|
* RSA operation
|
|
*/
|
|
ret = ( mode == MBEDTLS_RSA_PUBLIC )
|
|
? mbedtls_rsa_public( ctx, input, buf )
|
|
: mbedtls_rsa_private( ctx, f_rng, p_rng, input, buf );
|
|
|
|
if( ret != 0 )
|
|
goto cleanup;
|
|
|
|
/*
|
|
* Unmask data and generate lHash
|
|
*/
|
|
mbedtls_md_init( &md_ctx );
|
|
if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
|
|
{
|
|
mbedtls_md_free( &md_ctx );
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
/* Generate lHash */
|
|
mbedtls_md( md_info, label, label_len, lhash );
|
|
|
|
/* seed: Apply seedMask to maskedSeed */
|
|
mgf_mask( buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1,
|
|
&md_ctx );
|
|
|
|
/* DB: Apply dbMask to maskedDB */
|
|
mgf_mask( buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen,
|
|
&md_ctx );
|
|
|
|
mbedtls_md_free( &md_ctx );
|
|
|
|
/*
|
|
* Check contents, in "constant-time"
|
|
*/
|
|
p = buf;
|
|
bad = 0;
|
|
|
|
bad |= *p++; /* First byte must be 0 */
|
|
|
|
p += hlen; /* Skip seed */
|
|
|
|
/* Check lHash */
|
|
for( i = 0; i < hlen; i++ )
|
|
bad |= lhash[i] ^ *p++;
|
|
|
|
/* Get zero-padding len, but always read till end of buffer
|
|
* (minus one, for the 01 byte) */
|
|
pad_len = 0;
|
|
pad_done = 0;
|
|
for( i = 0; i < ilen - 2 * hlen - 2; i++ )
|
|
{
|
|
pad_done |= p[i];
|
|
pad_len += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1;
|
|
}
|
|
|
|
p += pad_len;
|
|
bad |= *p++ ^ 0x01;
|
|
|
|
/*
|
|
* The only information "leaked" is whether the padding was correct or not
|
|
* (eg, no data is copied if it was not correct). This meets the
|
|
* recommendations in PKCS#1 v2.2: an opponent cannot distinguish between
|
|
* the different error conditions.
|
|
*/
|
|
if( bad != 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_INVALID_PADDING;
|
|
goto cleanup;
|
|
}
|
|
|
|
if( ilen - ( p - buf ) > output_max_len )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE;
|
|
goto cleanup;
|
|
}
|
|
|
|
*olen = ilen - (p - buf);
|
|
memcpy( output, p, *olen );
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
mbedtls_zeroize( buf, sizeof( buf ) );
|
|
mbedtls_zeroize( lhash, sizeof( lhash ) );
|
|
|
|
return( ret );
|
|
}
|
|
#endif /* MBEDTLS_PKCS1_V21 */
|
|
|
|
#if defined(MBEDTLS_PKCS1_V15)
|
|
/** Turn zero-or-nonzero into zero-or-all-bits-one, without branches.
|
|
*
|
|
* \param value The value to analyze.
|
|
* \return Zero if \p value is zero, otherwise all-bits-one.
|
|
*/
|
|
static unsigned all_or_nothing_int( unsigned value )
|
|
{
|
|
/* MSVC has a warning about unary minus on unsigned, but this is
|
|
* well-defined and precisely what we want to do here */
|
|
#if defined(_MSC_VER)
|
|
#pragma warning( push )
|
|
#pragma warning( disable : 4146 )
|
|
#endif
|
|
return( - ( ( value | - value ) >> ( sizeof( value ) * 8 - 1 ) ) );
|
|
#if defined(_MSC_VER)
|
|
#pragma warning( pop )
|
|
#endif
|
|
}
|
|
|
|
/** Choose between two integer values, without branches.
|
|
*
|
|
* This is equivalent to `cond ? if1 : if0`, but is likely to be compiled
|
|
* to code using bitwise operation rather than a branch.
|
|
*
|
|
* \param cond Condition to test.
|
|
* \param if1 Value to use if \p cond is nonzero.
|
|
* \param if0 Value to use if \p cond is zero.
|
|
* \return \c if1 if \p cond is nonzero, otherwise \c if0.
|
|
*/
|
|
static unsigned if_int( unsigned cond, unsigned if1, unsigned if0 )
|
|
{
|
|
unsigned mask = all_or_nothing_int( cond );
|
|
return( ( mask & if1 ) | (~mask & if0 ) );
|
|
}
|
|
|
|
/*
|
|
* Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function
|
|
*/
|
|
int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
int mode, size_t *olen,
|
|
const unsigned char *input,
|
|
unsigned char *output,
|
|
size_t output_max_len )
|
|
{
|
|
int ret;
|
|
size_t ilen = ctx->len;
|
|
size_t pad_count = 0;
|
|
size_t i;
|
|
unsigned bad = 0;
|
|
unsigned char pad_done = 0;
|
|
size_t plaintext_size = 0;
|
|
size_t plaintext_max_size = ( output_max_len > ilen - 11 ?
|
|
ilen - 11 :
|
|
output_max_len );
|
|
unsigned output_too_large;
|
|
unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
|
|
unsigned char *p = buf;
|
|
|
|
if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
if( ilen < 16 || ilen > sizeof( buf ) )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
ret = ( mode == MBEDTLS_RSA_PUBLIC )
|
|
? mbedtls_rsa_public( ctx, input, buf )
|
|
: mbedtls_rsa_private( ctx, f_rng, p_rng, input, buf );
|
|
|
|
if( ret != 0 )
|
|
goto cleanup;
|
|
|
|
/*
|
|
* Check and get padding len in "constant-time"
|
|
*/
|
|
bad |= *p++; /* First byte must be 0 */
|
|
|
|
/* This test does not depend on secret data */
|
|
if( mode == MBEDTLS_RSA_PRIVATE )
|
|
{
|
|
bad |= *p++ ^ MBEDTLS_RSA_CRYPT;
|
|
|
|
/* Get padding len, but always read till end of buffer
|
|
* (minus one, for the 00 byte) */
|
|
for( i = 0; i < ilen - 3; i++ )
|
|
{
|
|
pad_done |= ((p[i] | (unsigned char)-p[i]) >> 7) ^ 1;
|
|
pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1;
|
|
}
|
|
|
|
p += pad_count;
|
|
bad |= *p++; /* Must be zero */
|
|
}
|
|
else
|
|
{
|
|
bad |= *p++ ^ MBEDTLS_RSA_SIGN;
|
|
|
|
/* Get padding len, but always read till end of buffer
|
|
* (minus one, for the 00 byte) */
|
|
for( i = 0; i < ilen - 3; i++ )
|
|
{
|
|
pad_done |= ( p[i] != 0xFF );
|
|
pad_count += ( pad_done == 0 );
|
|
}
|
|
|
|
p += pad_count;
|
|
bad |= *p++; /* Must be zero */
|
|
}
|
|
|
|
/* There must be at least 8 bytes of padding. */
|
|
bad |= ( pad_count < 8 );
|
|
|
|
/* If the padding is valid, set plaintext_size to the number of
|
|
* remaining bytes after stripping the padding. If the padding
|
|
* is invalid, avoid leaking this fact through the size of the
|
|
* output: use the maximum message size that fits in the output
|
|
* buffer. Do it without branches to avoid leaking the padding
|
|
* validity through timing. RSA keys are small enough that all the
|
|
* size_t values involved fit in unsigned int. */
|
|
plaintext_size = if_int( bad,
|
|
(unsigned) plaintext_max_size,
|
|
(unsigned) ( ilen - ( p - buf ) ) );
|
|
|
|
/* Set output_too_large to 0 if the plaintext fits in the output
|
|
* buffer and to 1 otherwise. This is the sign bit (1 for negative)
|
|
* of (output_max_len - plaintext_size). */
|
|
output_too_large = ( ( output_max_len - plaintext_size ) >>
|
|
( ( sizeof( output_max_len ) * 8 - 1 ) ) );
|
|
|
|
/* Set ret without branches to avoid timing attacks. Return:
|
|
* - INVALID_PADDING if the padding is bad (bad != 0).
|
|
* - OUTPUT_TOO_LARGE if the padding is good but the decrypted
|
|
* plaintext does not fit in the output buffer.
|
|
* - 0 if the padding is correct. */
|
|
ret = - if_int( bad, - MBEDTLS_ERR_RSA_INVALID_PADDING,
|
|
if_int( output_too_large, - MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE,
|
|
0 ) );
|
|
|
|
/* If the padding is bad or the plaintext is too large, zero the
|
|
* data that we're about to copy to the output buffer.
|
|
* We need to copy the same amount of data
|
|
* from the same buffer whether the padding is good or not to
|
|
* avoid leaking the padding validity through overall timing or
|
|
* through memory or cache access patterns. */
|
|
for( i = 11; i < ilen; i++ )
|
|
buf[i] &= ~( bad | output_too_large );
|
|
|
|
/* If the plaintext is too large, truncate it to the buffer size.
|
|
* Copy anyway to avoid revealing the length through timing, because
|
|
* revealing the length is as bad as revealing the padding validity
|
|
* for a Bleichenbacher attack. */
|
|
plaintext_size = if_int( output_too_large,
|
|
(unsigned) plaintext_max_size,
|
|
(unsigned) plaintext_size );
|
|
|
|
/* Move the plaintext to the beginning of the working buffer so that
|
|
* its position no longer depends on the padding and we have enough
|
|
* room from the beginning of the plaintext to copy a number of bytes
|
|
* that does not depend on the padding. */
|
|
/* FIXME: we need a constant-time, constant-trace memmove here. */
|
|
memmove( buf, p, plaintext_size );
|
|
|
|
/* Finally copy the decrypted plaintext plus trailing data
|
|
* into the output buffer. */
|
|
memcpy( output, buf, plaintext_max_size );
|
|
|
|
/* Report the amount of data we copied to the output buffer. In case
|
|
* of errors (bad padding or output too large), the value of *olen
|
|
* when this function returns is not specified. Making it equivalent
|
|
* to the good case limits the risks of leaking the padding validity. */
|
|
*olen = plaintext_size;
|
|
|
|
cleanup:
|
|
mbedtls_zeroize( buf, sizeof( buf ) );
|
|
|
|
return( ret );
|
|
}
|
|
#endif /* MBEDTLS_PKCS1_V15 */
|
|
|
|
/*
|
|
* Do an RSA operation, then remove the message padding
|
|
*/
|
|
int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
int mode, size_t *olen,
|
|
const unsigned char *input,
|
|
unsigned char *output,
|
|
size_t output_max_len)
|
|
{
|
|
switch( ctx->padding )
|
|
{
|
|
#if defined(MBEDTLS_PKCS1_V15)
|
|
case MBEDTLS_RSA_PKCS_V15:
|
|
return mbedtls_rsa_rsaes_pkcs1_v15_decrypt( ctx, f_rng, p_rng, mode, olen,
|
|
input, output, output_max_len );
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_PKCS1_V21)
|
|
case MBEDTLS_RSA_PKCS_V21:
|
|
return mbedtls_rsa_rsaes_oaep_decrypt( ctx, f_rng, p_rng, mode, NULL, 0,
|
|
olen, input, output,
|
|
output_max_len );
|
|
#endif
|
|
|
|
default:
|
|
return( MBEDTLS_ERR_RSA_INVALID_PADDING );
|
|
}
|
|
}
|
|
|
|
#if defined(MBEDTLS_PKCS1_V21)
|
|
/*
|
|
* Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function
|
|
*/
|
|
int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
int mode,
|
|
mbedtls_md_type_t md_alg,
|
|
unsigned int hashlen,
|
|
const unsigned char *hash,
|
|
unsigned char *sig )
|
|
{
|
|
size_t olen;
|
|
unsigned char *p = sig;
|
|
unsigned char salt[MBEDTLS_MD_MAX_SIZE];
|
|
unsigned int slen, hlen, offset = 0;
|
|
int ret;
|
|
size_t msb;
|
|
const mbedtls_md_info_t *md_info;
|
|
mbedtls_md_context_t md_ctx;
|
|
|
|
if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
if( f_rng == NULL )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
olen = ctx->len;
|
|
|
|
if( md_alg != MBEDTLS_MD_NONE )
|
|
{
|
|
// Gather length of hash to sign
|
|
//
|
|
md_info = mbedtls_md_info_from_type( md_alg );
|
|
if( md_info == NULL )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
hashlen = mbedtls_md_get_size( md_info );
|
|
}
|
|
|
|
md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id );
|
|
if( md_info == NULL )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
hlen = mbedtls_md_get_size( md_info );
|
|
slen = hlen;
|
|
|
|
if( olen < hlen + slen + 2 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
memset( sig, 0, olen );
|
|
|
|
// Generate salt of length slen
|
|
//
|
|
if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 )
|
|
return( MBEDTLS_ERR_RSA_RNG_FAILED + ret );
|
|
|
|
// Note: EMSA-PSS encoding is over the length of N - 1 bits
|
|
//
|
|
msb = mbedtls_mpi_bitlen( &ctx->N ) - 1;
|
|
p += olen - hlen * 2 - 2;
|
|
*p++ = 0x01;
|
|
memcpy( p, salt, slen );
|
|
p += slen;
|
|
|
|
mbedtls_md_init( &md_ctx );
|
|
if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
|
|
{
|
|
mbedtls_md_free( &md_ctx );
|
|
/* No need to zeroize salt: we didn't use it. */
|
|
return( ret );
|
|
}
|
|
|
|
// Generate H = Hash( M' )
|
|
//
|
|
mbedtls_md_starts( &md_ctx );
|
|
mbedtls_md_update( &md_ctx, p, 8 );
|
|
mbedtls_md_update( &md_ctx, hash, hashlen );
|
|
mbedtls_md_update( &md_ctx, salt, slen );
|
|
mbedtls_md_finish( &md_ctx, p );
|
|
mbedtls_zeroize( salt, sizeof( salt ) );
|
|
|
|
// Compensate for boundary condition when applying mask
|
|
//
|
|
if( msb % 8 == 0 )
|
|
offset = 1;
|
|
|
|
// maskedDB: Apply dbMask to DB
|
|
//
|
|
mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen, &md_ctx );
|
|
|
|
mbedtls_md_free( &md_ctx );
|
|
|
|
msb = mbedtls_mpi_bitlen( &ctx->N ) - 1;
|
|
sig[0] &= 0xFF >> ( olen * 8 - msb );
|
|
|
|
p += hlen;
|
|
*p++ = 0xBC;
|
|
|
|
return( ( mode == MBEDTLS_RSA_PUBLIC )
|
|
? mbedtls_rsa_public( ctx, sig, sig )
|
|
: mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig ) );
|
|
}
|
|
#endif /* MBEDTLS_PKCS1_V21 */
|
|
|
|
#if defined(MBEDTLS_PKCS1_V15)
|
|
/*
|
|
* Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function
|
|
*/
|
|
/*
|
|
* Do an RSA operation to sign the message digest
|
|
*/
|
|
int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
int mode,
|
|
mbedtls_md_type_t md_alg,
|
|
unsigned int hashlen,
|
|
const unsigned char *hash,
|
|
unsigned char *sig )
|
|
{
|
|
size_t nb_pad, olen, oid_size = 0;
|
|
unsigned char *p = sig;
|
|
const char *oid = NULL;
|
|
|
|
if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
olen = ctx->len;
|
|
nb_pad = olen - 3;
|
|
|
|
if( md_alg != MBEDTLS_MD_NONE )
|
|
{
|
|
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg );
|
|
if( md_info == NULL )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
if( mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
nb_pad -= 10 + oid_size;
|
|
|
|
hashlen = mbedtls_md_get_size( md_info );
|
|
}
|
|
|
|
nb_pad -= hashlen;
|
|
|
|
if( ( nb_pad < 8 ) || ( nb_pad > olen ) )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
*p++ = 0;
|
|
*p++ = MBEDTLS_RSA_SIGN;
|
|
memset( p, 0xFF, nb_pad );
|
|
p += nb_pad;
|
|
*p++ = 0;
|
|
|
|
if( md_alg == MBEDTLS_MD_NONE )
|
|
{
|
|
memcpy( p, hash, hashlen );
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* DigestInfo ::= SEQUENCE {
|
|
* digestAlgorithm DigestAlgorithmIdentifier,
|
|
* digest Digest }
|
|
*
|
|
* DigestAlgorithmIdentifier ::= AlgorithmIdentifier
|
|
*
|
|
* Digest ::= OCTET STRING
|
|
*/
|
|
*p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
|
|
*p++ = (unsigned char) ( 0x08 + oid_size + hashlen );
|
|
*p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
|
|
*p++ = (unsigned char) ( 0x04 + oid_size );
|
|
*p++ = MBEDTLS_ASN1_OID;
|
|
*p++ = oid_size & 0xFF;
|
|
memcpy( p, oid, oid_size );
|
|
p += oid_size;
|
|
*p++ = MBEDTLS_ASN1_NULL;
|
|
*p++ = 0x00;
|
|
*p++ = MBEDTLS_ASN1_OCTET_STRING;
|
|
*p++ = hashlen;
|
|
memcpy( p, hash, hashlen );
|
|
}
|
|
|
|
if( mode == MBEDTLS_RSA_PUBLIC )
|
|
return( mbedtls_rsa_public( ctx, sig, sig ) );
|
|
|
|
return( mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig ) );
|
|
}
|
|
#endif /* MBEDTLS_PKCS1_V15 */
|
|
|
|
/*
|
|
* Do an RSA operation to sign the message digest
|
|
*/
|
|
int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
int mode,
|
|
mbedtls_md_type_t md_alg,
|
|
unsigned int hashlen,
|
|
const unsigned char *hash,
|
|
unsigned char *sig )
|
|
{
|
|
switch( ctx->padding )
|
|
{
|
|
#if defined(MBEDTLS_PKCS1_V15)
|
|
case MBEDTLS_RSA_PKCS_V15:
|
|
return mbedtls_rsa_rsassa_pkcs1_v15_sign( ctx, f_rng, p_rng, mode, md_alg,
|
|
hashlen, hash, sig );
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_PKCS1_V21)
|
|
case MBEDTLS_RSA_PKCS_V21:
|
|
return mbedtls_rsa_rsassa_pss_sign( ctx, f_rng, p_rng, mode, md_alg,
|
|
hashlen, hash, sig );
|
|
#endif
|
|
|
|
default:
|
|
return( MBEDTLS_ERR_RSA_INVALID_PADDING );
|
|
}
|
|
}
|
|
|
|
#if defined(MBEDTLS_PKCS1_V21)
|
|
/*
|
|
* Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function
|
|
*/
|
|
int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
int mode,
|
|
mbedtls_md_type_t md_alg,
|
|
unsigned int hashlen,
|
|
const unsigned char *hash,
|
|
mbedtls_md_type_t mgf1_hash_id,
|
|
int expected_salt_len,
|
|
const unsigned char *sig )
|
|
{
|
|
int ret;
|
|
size_t siglen;
|
|
unsigned char *p;
|
|
unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
|
|
unsigned char *hash_start;
|
|
unsigned char result[MBEDTLS_MD_MAX_SIZE];
|
|
unsigned char zeros[8];
|
|
unsigned int hlen;
|
|
size_t observed_salt_len, msb;
|
|
const mbedtls_md_info_t *md_info;
|
|
mbedtls_md_context_t md_ctx;
|
|
|
|
if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
siglen = ctx->len;
|
|
|
|
if( siglen < 16 || siglen > sizeof( buf ) )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
ret = ( mode == MBEDTLS_RSA_PUBLIC )
|
|
? mbedtls_rsa_public( ctx, sig, buf )
|
|
: mbedtls_rsa_private( ctx, f_rng, p_rng, sig, buf );
|
|
|
|
if( ret != 0 )
|
|
return( ret );
|
|
|
|
p = buf;
|
|
|
|
if( buf[siglen - 1] != 0xBC )
|
|
return( MBEDTLS_ERR_RSA_INVALID_PADDING );
|
|
|
|
if( md_alg != MBEDTLS_MD_NONE )
|
|
{
|
|
// Gather length of hash to sign
|
|
//
|
|
md_info = mbedtls_md_info_from_type( md_alg );
|
|
if( md_info == NULL )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
hashlen = mbedtls_md_get_size( md_info );
|
|
}
|
|
|
|
md_info = mbedtls_md_info_from_type( mgf1_hash_id );
|
|
if( md_info == NULL )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
hlen = mbedtls_md_get_size( md_info );
|
|
|
|
memset( zeros, 0, 8 );
|
|
|
|
// Note: EMSA-PSS verification is over the length of N - 1 bits
|
|
//
|
|
msb = mbedtls_mpi_bitlen( &ctx->N ) - 1;
|
|
|
|
if( buf[0] >> ( 8 - siglen * 8 + msb ) )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
/* Compensate for boundary condition when applying mask */
|
|
if( msb % 8 == 0 )
|
|
{
|
|
p++;
|
|
siglen -= 1;
|
|
}
|
|
|
|
if( siglen < hlen + 2 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
hash_start = p + siglen - hlen - 1;
|
|
|
|
mbedtls_md_init( &md_ctx );
|
|
if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
|
|
{
|
|
mbedtls_md_free( &md_ctx );
|
|
return( ret );
|
|
}
|
|
|
|
mgf_mask( p, siglen - hlen - 1, hash_start, hlen, &md_ctx );
|
|
|
|
buf[0] &= 0xFF >> ( siglen * 8 - msb );
|
|
|
|
while( p < hash_start - 1 && *p == 0 )
|
|
p++;
|
|
|
|
if( *p++ != 0x01 )
|
|
{
|
|
mbedtls_md_free( &md_ctx );
|
|
return( MBEDTLS_ERR_RSA_INVALID_PADDING );
|
|
}
|
|
|
|
observed_salt_len = hash_start - p;
|
|
|
|
if( expected_salt_len != MBEDTLS_RSA_SALT_LEN_ANY &&
|
|
observed_salt_len != (size_t) expected_salt_len )
|
|
{
|
|
mbedtls_md_free( &md_ctx );
|
|
return( MBEDTLS_ERR_RSA_INVALID_PADDING );
|
|
}
|
|
|
|
// Generate H = Hash( M' )
|
|
//
|
|
mbedtls_md_starts( &md_ctx );
|
|
mbedtls_md_update( &md_ctx, zeros, 8 );
|
|
mbedtls_md_update( &md_ctx, hash, hashlen );
|
|
mbedtls_md_update( &md_ctx, p, observed_salt_len );
|
|
mbedtls_md_finish( &md_ctx, result );
|
|
|
|
mbedtls_md_free( &md_ctx );
|
|
|
|
if( memcmp( hash_start, result, hlen ) == 0 )
|
|
return( 0 );
|
|
else
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
}
|
|
|
|
/*
|
|
* Simplified PKCS#1 v2.1 RSASSA-PSS-VERIFY function
|
|
*/
|
|
int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
int mode,
|
|
mbedtls_md_type_t md_alg,
|
|
unsigned int hashlen,
|
|
const unsigned char *hash,
|
|
const unsigned char *sig )
|
|
{
|
|
mbedtls_md_type_t mgf1_hash_id = ( ctx->hash_id != MBEDTLS_MD_NONE )
|
|
? (mbedtls_md_type_t) ctx->hash_id
|
|
: md_alg;
|
|
|
|
return( mbedtls_rsa_rsassa_pss_verify_ext( ctx, f_rng, p_rng, mode,
|
|
md_alg, hashlen, hash,
|
|
mgf1_hash_id, MBEDTLS_RSA_SALT_LEN_ANY,
|
|
sig ) );
|
|
|
|
}
|
|
#endif /* MBEDTLS_PKCS1_V21 */
|
|
|
|
#if defined(MBEDTLS_PKCS1_V15)
|
|
/*
|
|
* Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function
|
|
*/
|
|
int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
int mode,
|
|
mbedtls_md_type_t md_alg,
|
|
unsigned int hashlen,
|
|
const unsigned char *hash,
|
|
const unsigned char *sig )
|
|
{
|
|
int ret;
|
|
size_t len, siglen, asn1_len;
|
|
unsigned char *p, *p0, *end;
|
|
unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
|
|
mbedtls_md_type_t msg_md_alg;
|
|
const mbedtls_md_info_t *md_info;
|
|
mbedtls_asn1_buf oid;
|
|
|
|
if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
siglen = ctx->len;
|
|
|
|
if( siglen < 16 || siglen > sizeof( buf ) )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
|
|
ret = ( mode == MBEDTLS_RSA_PUBLIC )
|
|
? mbedtls_rsa_public( ctx, sig, buf )
|
|
: mbedtls_rsa_private( ctx, f_rng, p_rng, sig, buf );
|
|
|
|
if( ret != 0 )
|
|
return( ret );
|
|
|
|
p = buf;
|
|
|
|
if( *p++ != 0 || *p++ != MBEDTLS_RSA_SIGN )
|
|
return( MBEDTLS_ERR_RSA_INVALID_PADDING );
|
|
|
|
while( *p != 0 )
|
|
{
|
|
if( p >= buf + siglen - 1 || *p != 0xFF )
|
|
return( MBEDTLS_ERR_RSA_INVALID_PADDING );
|
|
p++;
|
|
}
|
|
p++; /* skip 00 byte */
|
|
|
|
/* We've read: 00 01 PS 00 where PS must be at least 8 bytes */
|
|
if( p - buf < 11 )
|
|
return( MBEDTLS_ERR_RSA_INVALID_PADDING );
|
|
|
|
len = siglen - ( p - buf );
|
|
|
|
if( len == hashlen && md_alg == MBEDTLS_MD_NONE )
|
|
{
|
|
if( memcmp( p, hash, hashlen ) == 0 )
|
|
return( 0 );
|
|
else
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
}
|
|
|
|
md_info = mbedtls_md_info_from_type( md_alg );
|
|
if( md_info == NULL )
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
hashlen = mbedtls_md_get_size( md_info );
|
|
|
|
end = p + len;
|
|
|
|
/*
|
|
* Parse the ASN.1 structure inside the PKCS#1 v1.5 structure.
|
|
* Insist on 2-byte length tags, to protect against variants of
|
|
* Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification.
|
|
*/
|
|
p0 = p;
|
|
if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len,
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
if( p != p0 + 2 || asn1_len + 2 != len )
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
|
|
p0 = p;
|
|
if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len,
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
if( p != p0 + 2 || asn1_len + 6 + hashlen != len )
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
|
|
p0 = p;
|
|
if( ( ret = mbedtls_asn1_get_tag( &p, end, &oid.len, MBEDTLS_ASN1_OID ) ) != 0 )
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
if( p != p0 + 2 )
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
|
|
oid.p = p;
|
|
p += oid.len;
|
|
|
|
if( mbedtls_oid_get_md_alg( &oid, &msg_md_alg ) != 0 )
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
|
|
if( md_alg != msg_md_alg )
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
|
|
/*
|
|
* assume the algorithm parameters must be NULL
|
|
*/
|
|
p0 = p;
|
|
if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_NULL ) ) != 0 )
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
if( p != p0 + 2 )
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
|
|
p0 = p;
|
|
if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
if( p != p0 + 2 || asn1_len != hashlen )
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
|
|
if( memcmp( p, hash, hashlen ) != 0 )
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
|
|
p += hashlen;
|
|
|
|
if( p != end )
|
|
return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
|
|
|
|
return( 0 );
|
|
}
|
|
#endif /* MBEDTLS_PKCS1_V15 */
|
|
|
|
/*
|
|
* Do an RSA operation and check the message digest
|
|
*/
|
|
int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng,
|
|
int mode,
|
|
mbedtls_md_type_t md_alg,
|
|
unsigned int hashlen,
|
|
const unsigned char *hash,
|
|
const unsigned char *sig )
|
|
{
|
|
switch( ctx->padding )
|
|
{
|
|
#if defined(MBEDTLS_PKCS1_V15)
|
|
case MBEDTLS_RSA_PKCS_V15:
|
|
return mbedtls_rsa_rsassa_pkcs1_v15_verify( ctx, f_rng, p_rng, mode, md_alg,
|
|
hashlen, hash, sig );
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_PKCS1_V21)
|
|
case MBEDTLS_RSA_PKCS_V21:
|
|
return mbedtls_rsa_rsassa_pss_verify( ctx, f_rng, p_rng, mode, md_alg,
|
|
hashlen, hash, sig );
|
|
#endif
|
|
|
|
default:
|
|
return( MBEDTLS_ERR_RSA_INVALID_PADDING );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Copy the components of an RSA key
|
|
*/
|
|
int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src )
|
|
{
|
|
int ret;
|
|
|
|
dst->ver = src->ver;
|
|
dst->len = src->len;
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->N, &src->N ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->E, &src->E ) );
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->D, &src->D ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->P, &src->P ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Q, &src->Q ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->DP, &src->DP ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->DQ, &src->DQ ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->QP, &src->QP ) );
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RN, &src->RN ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RP, &src->RP ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RQ, &src->RQ ) );
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Vi, &src->Vi ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Vf, &src->Vf ) );
|
|
|
|
dst->padding = src->padding;
|
|
dst->hash_id = src->hash_id;
|
|
|
|
cleanup:
|
|
if( ret != 0 )
|
|
mbedtls_rsa_free( dst );
|
|
|
|
return( ret );
|
|
}
|
|
|
|
/*
|
|
* Free the components of an RSA key
|
|
*/
|
|
void mbedtls_rsa_free( mbedtls_rsa_context *ctx )
|
|
{
|
|
mbedtls_mpi_free( &ctx->Vi ); mbedtls_mpi_free( &ctx->Vf );
|
|
mbedtls_mpi_free( &ctx->RQ ); mbedtls_mpi_free( &ctx->RP ); mbedtls_mpi_free( &ctx->RN );
|
|
mbedtls_mpi_free( &ctx->QP ); mbedtls_mpi_free( &ctx->DQ ); mbedtls_mpi_free( &ctx->DP );
|
|
mbedtls_mpi_free( &ctx->Q ); mbedtls_mpi_free( &ctx->P ); mbedtls_mpi_free( &ctx->D );
|
|
mbedtls_mpi_free( &ctx->E ); mbedtls_mpi_free( &ctx->N );
|
|
|
|
#if defined(MBEDTLS_THREADING_C)
|
|
mbedtls_mutex_free( &ctx->mutex );
|
|
#endif
|
|
}
|
|
|
|
#if defined(MBEDTLS_SELF_TEST)
|
|
|
|
#include "mbedtls/sha1.h"
|
|
|
|
/*
|
|
* Example RSA-1024 keypair, for test purposes
|
|
*/
|
|
#define KEY_LEN 128
|
|
|
|
#define RSA_N "9292758453063D803DD603D5E777D788" \
|
|
"8ED1D5BF35786190FA2F23EBC0848AEA" \
|
|
"DDA92CA6C3D80B32C4D109BE0F36D6AE" \
|
|
"7130B9CED7ACDF54CFC7555AC14EEBAB" \
|
|
"93A89813FBF3C4F8066D2D800F7C38A8" \
|
|
"1AE31942917403FF4946B0A83D3D3E05" \
|
|
"EE57C6F5F5606FB5D4BC6CD34EE0801A" \
|
|
"5E94BB77B07507233A0BC7BAC8F90F79"
|
|
|
|
#define RSA_E "10001"
|
|
|
|
#define RSA_D "24BF6185468786FDD303083D25E64EFC" \
|
|
"66CA472BC44D253102F8B4A9D3BFA750" \
|
|
"91386C0077937FE33FA3252D28855837" \
|
|
"AE1B484A8A9A45F7EE8C0C634F99E8CD" \
|
|
"DF79C5CE07EE72C7F123142198164234" \
|
|
"CABB724CF78B8173B9F880FC86322407" \
|
|
"AF1FEDFDDE2BEB674CA15F3E81A1521E" \
|
|
"071513A1E85B5DFA031F21ECAE91A34D"
|
|
|
|
#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \
|
|
"2C01CAD19EA484A87EA4377637E75500" \
|
|
"FCB2005C5C7DD6EC4AC023CDA285D796" \
|
|
"C3D9E75E1EFC42488BB4F1D13AC30A57"
|
|
|
|
#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \
|
|
"E211C2B9E5DB1ED0BF61D0D9899620F4" \
|
|
"910E4168387E3C30AA1E00C339A79508" \
|
|
"8452DD96A9A5EA5D9DCA68DA636032AF"
|
|
|
|
#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \
|
|
"3C94D22288ACD763FD8E5600ED4A702D" \
|
|
"F84198A5F06C2E72236AE490C93F07F8" \
|
|
"3CC559CD27BC2D1CA488811730BB5725"
|
|
|
|
#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \
|
|
"D8AAEA56749EA28623272E4F7D0592AF" \
|
|
"7C1F1313CAC9471B5C523BFE592F517B" \
|
|
"407A1BD76C164B93DA2D32A383E58357"
|
|
|
|
#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \
|
|
"F38D18D2B2F0E2DD275AA977E2BF4411" \
|
|
"F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \
|
|
"A74206CEC169D74BF5A8C50D6F48EA08"
|
|
|
|
#define PT_LEN 24
|
|
#define RSA_PT "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \
|
|
"\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD"
|
|
|
|
#if defined(MBEDTLS_PKCS1_V15)
|
|
static int myrand( void *rng_state, unsigned char *output, size_t len )
|
|
{
|
|
#if !defined(__OpenBSD__)
|
|
size_t i;
|
|
|
|
if( rng_state != NULL )
|
|
rng_state = NULL;
|
|
|
|
for( i = 0; i < len; ++i )
|
|
output[i] = rand();
|
|
#else
|
|
if( rng_state != NULL )
|
|
rng_state = NULL;
|
|
|
|
arc4random_buf( output, len );
|
|
#endif /* !OpenBSD */
|
|
|
|
return( 0 );
|
|
}
|
|
#endif /* MBEDTLS_PKCS1_V15 */
|
|
|
|
/*
|
|
* Checkup routine
|
|
*/
|
|
int mbedtls_rsa_self_test( int verbose )
|
|
{
|
|
int ret = 0;
|
|
#if defined(MBEDTLS_PKCS1_V15)
|
|
size_t len;
|
|
mbedtls_rsa_context rsa;
|
|
unsigned char rsa_plaintext[PT_LEN];
|
|
unsigned char rsa_decrypted[PT_LEN];
|
|
unsigned char rsa_ciphertext[KEY_LEN];
|
|
#if defined(MBEDTLS_SHA1_C)
|
|
unsigned char sha1sum[20];
|
|
#endif
|
|
|
|
mbedtls_rsa_init( &rsa, MBEDTLS_RSA_PKCS_V15, 0 );
|
|
|
|
rsa.len = KEY_LEN;
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.N , 16, RSA_N ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.E , 16, RSA_E ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.D , 16, RSA_D ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.P , 16, RSA_P ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.Q , 16, RSA_Q ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.DP, 16, RSA_DP ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.DQ, 16, RSA_DQ ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.QP, 16, RSA_QP ) );
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( " RSA key validation: " );
|
|
|
|
if( mbedtls_rsa_check_pubkey( &rsa ) != 0 ||
|
|
mbedtls_rsa_check_privkey( &rsa ) != 0 )
|
|
{
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "failed\n" );
|
|
|
|
ret = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "passed\n PKCS#1 encryption : " );
|
|
|
|
memcpy( rsa_plaintext, RSA_PT, PT_LEN );
|
|
|
|
if( mbedtls_rsa_pkcs1_encrypt( &rsa, myrand, NULL, MBEDTLS_RSA_PUBLIC, PT_LEN,
|
|
rsa_plaintext, rsa_ciphertext ) != 0 )
|
|
{
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "failed\n" );
|
|
|
|
ret = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "passed\n PKCS#1 decryption : " );
|
|
|
|
if( mbedtls_rsa_pkcs1_decrypt( &rsa, myrand, NULL, MBEDTLS_RSA_PRIVATE, &len,
|
|
rsa_ciphertext, rsa_decrypted,
|
|
sizeof(rsa_decrypted) ) != 0 )
|
|
{
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "failed\n" );
|
|
|
|
ret = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 )
|
|
{
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "failed\n" );
|
|
|
|
ret = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "passed\n" );
|
|
|
|
#if defined(MBEDTLS_SHA1_C)
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "PKCS#1 data sign : " );
|
|
|
|
mbedtls_sha1( rsa_plaintext, PT_LEN, sha1sum );
|
|
|
|
if( mbedtls_rsa_pkcs1_sign( &rsa, myrand, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 0,
|
|
sha1sum, rsa_ciphertext ) != 0 )
|
|
{
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "failed\n" );
|
|
|
|
ret = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "passed\n PKCS#1 sig. verify: " );
|
|
|
|
if( mbedtls_rsa_pkcs1_verify( &rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 0,
|
|
sha1sum, rsa_ciphertext ) != 0 )
|
|
{
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "failed\n" );
|
|
|
|
ret = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "passed\n" );
|
|
#endif /* MBEDTLS_SHA1_C */
|
|
|
|
if( verbose != 0 )
|
|
mbedtls_printf( "\n" );
|
|
|
|
cleanup:
|
|
mbedtls_rsa_free( &rsa );
|
|
#else /* MBEDTLS_PKCS1_V15 */
|
|
((void) verbose);
|
|
#endif /* MBEDTLS_PKCS1_V15 */
|
|
return( ret );
|
|
}
|
|
|
|
#endif /* MBEDTLS_SELF_TEST */
|
|
|
|
#endif /* MBEDTLS_RSA_C */
|