mbedtls/library/rsa.c
Gilles Peskine 28474f41a0 RSA PSS: remove redundant check; changelog
Remove a check introduced in the previous buffer overflow fix with keys of
size 8N+1 which the subsequent fix for buffer start calculations made
redundant.

Added a changelog entry for the buffer start calculation fix.
2017-10-19 17:50:35 +02:00

1875 lines
51 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* The RSA public-key cryptosystem
*
* Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
*
* This file is part of mbed TLS (https://tls.mbed.org)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* 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(POLARSSL_CONFIG_FILE)
#include "polarssl/config.h"
#else
#include POLARSSL_CONFIG_FILE
#endif
#if defined(POLARSSL_RSA_C)
#include "polarssl/rsa.h"
#include "polarssl/oid.h"
#include <string.h>
#if defined(POLARSSL_PKCS1_V21)
#include "polarssl/md.h"
#endif
#if defined(POLARSSL_PKCS1_V15) && !defined(__OpenBSD__)
#include <stdlib.h>
#endif
#if defined(POLARSSL_PLATFORM_C)
#include "polarssl/platform.h"
#else
#include <stdio.h>
#define polarssl_printf printf
#define polarssl_malloc malloc
#define polarssl_free free
#endif
/* Implementation that should never be optimized out by the compiler */
static void polarssl_zeroize( void *v, size_t n ) {
volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
}
/*
* Initialize an RSA context
*/
void rsa_init( rsa_context *ctx,
int padding,
int hash_id )
{
memset( ctx, 0, sizeof( rsa_context ) );
rsa_set_padding( ctx, padding, hash_id );
#if defined(POLARSSL_THREADING_C)
polarssl_mutex_init( &ctx->mutex );
#endif
}
/*
* Set padding for an existing RSA context
*/
void rsa_set_padding( rsa_context *ctx, int padding, int hash_id )
{
ctx->padding = padding;
ctx->hash_id = hash_id;
}
#if defined(POLARSSL_GENPRIME)
/*
* Generate an RSA keypair
*/
int rsa_gen_key( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
unsigned int nbits, int exponent )
{
int ret;
mpi P1, Q1, H, G;
if( f_rng == NULL || nbits < 128 || exponent < 3 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
if( nbits % 2 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
mpi_init( &P1 ); mpi_init( &Q1 );
mpi_init( &H ); mpi_init( &G );
/*
* find primes P and Q with Q < P so that:
* GCD( E, (P-1)*(Q-1) ) == 1
*/
MPI_CHK( mpi_lset( &ctx->E, exponent ) );
do
{
MPI_CHK( mpi_gen_prime( &ctx->P, nbits >> 1, 0,
f_rng, p_rng ) );
MPI_CHK( mpi_gen_prime( &ctx->Q, nbits >> 1, 0,
f_rng, p_rng ) );
if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 )
continue;
MPI_CHK( mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) );
if( mpi_msb( &ctx->N ) != nbits )
continue;
if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 )
mpi_swap( &ctx->P, &ctx->Q );
MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
MPI_CHK( mpi_gcd( &G, &ctx->E, &H ) );
}
while( 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
*/
MPI_CHK( mpi_inv_mod( &ctx->D , &ctx->E, &H ) );
MPI_CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) );
MPI_CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) );
MPI_CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) );
ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3;
cleanup:
mpi_free( &P1 ); mpi_free( &Q1 ); mpi_free( &H ); mpi_free( &G );
if( ret != 0 )
{
rsa_free( ctx );
return( POLARSSL_ERR_RSA_KEY_GEN_FAILED + ret );
}
return( 0 );
}
#endif /* POLARSSL_GENPRIME */
/*
* Check a public RSA key
*/
int rsa_check_pubkey( const rsa_context *ctx )
{
if( !ctx->N.p || !ctx->E.p )
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
if( ( ctx->N.p[0] & 1 ) == 0 ||
( ctx->E.p[0] & 1 ) == 0 )
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
if( mpi_msb( &ctx->N ) < 128 ||
mpi_msb( &ctx->N ) > POLARSSL_MPI_MAX_BITS )
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
if( mpi_msb( &ctx->E ) < 2 ||
mpi_cmp_mpi( &ctx->E, &ctx->N ) >= 0 )
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
return( 0 );
}
/*
* Check a private RSA key
*/
int rsa_check_privkey( const rsa_context *ctx )
{
int ret;
mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2, DP, DQ, QP;
if( ( ret = rsa_check_pubkey( ctx ) ) != 0 )
return( ret );
if( !ctx->P.p || !ctx->Q.p || !ctx->D.p )
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
mpi_init( &PQ ); mpi_init( &DE ); mpi_init( &P1 ); mpi_init( &Q1 );
mpi_init( &H ); mpi_init( &I ); mpi_init( &G ); mpi_init( &G2 );
mpi_init( &L1 ); mpi_init( &L2 ); mpi_init( &DP ); mpi_init( &DQ );
mpi_init( &QP );
MPI_CHK( mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) );
MPI_CHK( mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) );
MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
MPI_CHK( mpi_gcd( &G, &ctx->E, &H ) );
MPI_CHK( mpi_gcd( &G2, &P1, &Q1 ) );
MPI_CHK( mpi_div_mpi( &L1, &L2, &H, &G2 ) );
MPI_CHK( mpi_mod_mpi( &I, &DE, &L1 ) );
MPI_CHK( mpi_mod_mpi( &DP, &ctx->D, &P1 ) );
MPI_CHK( mpi_mod_mpi( &DQ, &ctx->D, &Q1 ) );
MPI_CHK( mpi_inv_mod( &QP, &ctx->Q, &ctx->P ) );
/*
* Check for a valid PKCS1v2 private key
*/
if( mpi_cmp_mpi( &PQ, &ctx->N ) != 0 ||
mpi_cmp_mpi( &DP, &ctx->DP ) != 0 ||
mpi_cmp_mpi( &DQ, &ctx->DQ ) != 0 ||
mpi_cmp_mpi( &QP, &ctx->QP ) != 0 ||
mpi_cmp_int( &L2, 0 ) != 0 ||
mpi_cmp_int( &I, 1 ) != 0 ||
mpi_cmp_int( &G, 1 ) != 0 )
{
ret = POLARSSL_ERR_RSA_KEY_CHECK_FAILED;
}
cleanup:
mpi_free( &PQ ); mpi_free( &DE ); mpi_free( &P1 ); mpi_free( &Q1 );
mpi_free( &H ); mpi_free( &I ); mpi_free( &G ); mpi_free( &G2 );
mpi_free( &L1 ); mpi_free( &L2 ); mpi_free( &DP ); mpi_free( &DQ );
mpi_free( &QP );
if( ret == POLARSSL_ERR_RSA_KEY_CHECK_FAILED )
return( ret );
if( ret != 0 )
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED + ret );
return( 0 );
}
/*
* Check if contexts holding a public and private key match
*/
int rsa_check_pub_priv( const rsa_context *pub, const rsa_context *prv )
{
if( rsa_check_pubkey( pub ) != 0 ||
rsa_check_privkey( prv ) != 0 )
{
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
}
if( mpi_cmp_mpi( &pub->N, &prv->N ) != 0 ||
mpi_cmp_mpi( &pub->E, &prv->E ) != 0 )
{
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );
}
return( 0 );
}
/*
* Do an RSA public key operation
*/
int rsa_public( rsa_context *ctx,
const unsigned char *input,
unsigned char *output )
{
int ret;
size_t olen;
mpi T;
mpi_init( &T );
#if defined(POLARSSL_THREADING_C)
if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
return( ret );
#endif
MPI_CHK( mpi_read_binary( &T, input, ctx->len ) );
if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
{
ret = POLARSSL_ERR_MPI_BAD_INPUT_DATA;
goto cleanup;
}
olen = ctx->len;
MPI_CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) );
MPI_CHK( mpi_write_binary( &T, output, olen ) );
cleanup:
#if defined(POLARSSL_THREADING_C)
if( polarssl_mutex_unlock( &ctx->mutex ) != 0 )
return( POLARSSL_ERR_THREADING_MUTEX_ERROR );
#endif
mpi_free( &T );
if( ret != 0 )
return( POLARSSL_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—CRYPTO96. Springer
* Berlin Heidelberg, 1996. p. 104-113.
*/
static int rsa_prepare_blinding( 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 */
MPI_CHK( mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) );
MPI_CHK( mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->N ) );
MPI_CHK( mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) );
MPI_CHK( mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->N ) );
goto cleanup;
}
/* Unblinding value: Vf = random number, invertible mod N */
do {
if( count++ > 10 )
return( POLARSSL_ERR_RSA_RNG_FAILED );
MPI_CHK( mpi_fill_random( &ctx->Vf, ctx->len - 1, f_rng, p_rng ) );
MPI_CHK( mpi_gcd( &ctx->Vi, &ctx->Vf, &ctx->N ) );
} while( mpi_cmp_int( &ctx->Vi, 1 ) != 0 );
/* Blinding value: Vi = Vf^(-e) mod N */
MPI_CHK( mpi_inv_mod( &ctx->Vi, &ctx->Vf, &ctx->N ) );
MPI_CHK( 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 rsa_private( 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;
mpi T, T1, T2;
mpi P1, Q1, R;
#if defined(POLARSSL_RSA_NO_CRT)
mpi D_blind;
mpi *D = &ctx->D;
#else
mpi DP_blind, DQ_blind;
mpi *DP = &ctx->DP;
mpi *DQ = &ctx->DQ;
#endif
mpi_init( &T ); mpi_init( &T1 ); mpi_init( &T2 );
mpi_init( &P1 ); mpi_init( &Q1 ); mpi_init( &R );
if( f_rng != NULL )
{
#if defined(POLARSSL_RSA_NO_CRT)
mpi_init( &D_blind );
#else
mpi_init( &DP_blind );
mpi_init( &DQ_blind );
#endif
}
#if defined(POLARSSL_THREADING_C)
if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
return( ret );
#endif
MPI_CHK( mpi_read_binary( &T, input, ctx->len ) );
if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
{
ret = POLARSSL_ERR_MPI_BAD_INPUT_DATA;
goto cleanup;
}
if( f_rng != NULL )
{
/*
* Blinding
* T = T * Vi mod N
*/
MPI_CHK( rsa_prepare_blinding( ctx, f_rng, p_rng ) );
MPI_CHK( mpi_mul_mpi( &T, &T, &ctx->Vi ) );
MPI_CHK( mpi_mod_mpi( &T, &T, &ctx->N ) );
/*
* Exponent blinding
*/
MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
#if defined(POLARSSL_RSA_NO_CRT)
/*
* D_blind = ( P - 1 ) * ( Q - 1 ) * R + D
*/
MPI_CHK( mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
f_rng, p_rng ) );
MPI_CHK( mpi_mul_mpi( &D_blind, &P1, &Q1 ) );
MPI_CHK( mpi_mul_mpi( &D_blind, &D_blind, &R ) );
MPI_CHK( mpi_add_mpi( &D_blind, &D_blind, &ctx->D ) );
D = &D_blind;
#else
/*
* DP_blind = ( P - 1 ) * R + DP
*/
MPI_CHK( mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
f_rng, p_rng ) );
MPI_CHK( mpi_mul_mpi( &DP_blind, &P1, &R ) );
MPI_CHK( mpi_add_mpi( &DP_blind, &DP_blind,
&ctx->DP ) );
DP = &DP_blind;
/*
* DQ_blind = ( Q - 1 ) * R + DQ
*/
MPI_CHK( mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
f_rng, p_rng ) );
MPI_CHK( mpi_mul_mpi( &DQ_blind, &Q1, &R ) );
MPI_CHK( mpi_add_mpi( &DQ_blind, &DQ_blind,
&ctx->DQ ) );
DQ = &DQ_blind;
#endif /* POLARSSL_RSA_NO_CRT */
}
#if defined(POLARSSL_RSA_NO_CRT)
MPI_CHK( 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
*/
MPI_CHK( mpi_exp_mod( &T1, &T, DP, &ctx->P, &ctx->RP ) );
MPI_CHK( mpi_exp_mod( &T2, &T, DQ, &ctx->Q, &ctx->RQ ) );
/*
* T = (T1 - T2) * (Q^-1 mod P) mod P
*/
MPI_CHK( mpi_sub_mpi( &T, &T1, &T2 ) );
MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->QP ) );
MPI_CHK( mpi_mod_mpi( &T, &T1, &ctx->P ) );
/*
* T = T2 + T * Q
*/
MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) );
MPI_CHK( mpi_add_mpi( &T, &T2, &T1 ) );
#endif /* POLARSSL_RSA_NO_CRT */
if( f_rng != NULL )
{
/*
* Unblind
* T = T * Vf mod N
*/
MPI_CHK( mpi_mul_mpi( &T, &T, &ctx->Vf ) );
MPI_CHK( mpi_mod_mpi( &T, &T, &ctx->N ) );
}
olen = ctx->len;
MPI_CHK( mpi_write_binary( &T, output, olen ) );
cleanup:
#if defined(POLARSSL_THREADING_C)
if( polarssl_mutex_unlock( &ctx->mutex ) != 0 )
return( POLARSSL_ERR_THREADING_MUTEX_ERROR );
#endif
mpi_free( &T ); mpi_free( &T1 ); mpi_free( &T2 );
mpi_free( &P1 ); mpi_free( &Q1 ); mpi_free( &R );
if( f_rng != NULL )
{
#if defined(POLARSSL_RSA_NO_CRT)
mpi_free( &D_blind );
#else
mpi_free( &DP_blind );
mpi_free( &DQ_blind );
#endif
}
if( ret != 0 )
return( POLARSSL_ERR_RSA_PRIVATE_FAILED + ret );
return( 0 );
}
#if defined(POLARSSL_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, md_context_t *md_ctx )
{
unsigned char mask[POLARSSL_MD_MAX_SIZE];
unsigned char counter[4];
unsigned char *p;
unsigned int hlen;
size_t i, use_len;
memset( mask, 0, POLARSSL_MD_MAX_SIZE );
memset( counter, 0, 4 );
hlen = md_ctx->md_info->size;
// Generate and apply dbMask
//
p = dst;
while( dlen > 0 )
{
use_len = hlen;
if( dlen < hlen )
use_len = dlen;
md_starts( md_ctx );
md_update( md_ctx, src, slen );
md_update( md_ctx, counter, 4 );
md_finish( md_ctx, mask );
for( i = 0; i < use_len; ++i )
*p++ ^= mask[i];
counter[3]++;
dlen -= use_len;
}
polarssl_zeroize( mask, sizeof( mask ) );
}
#endif /* POLARSSL_PKCS1_V21 */
#if defined(POLARSSL_PKCS1_V21)
/*
* Implementation of the PKCS#1 v2.1 RSAES-OAEP-ENCRYPT function
*/
int rsa_rsaes_oaep_encrypt( 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 md_info_t *md_info;
md_context_t md_ctx;
if( mode == RSA_PRIVATE && ctx->padding != RSA_PKCS_V21 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
if( f_rng == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
md_info = md_info_from_type( (md_type_t) ctx->hash_id );
if( md_info == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
olen = ctx->len;
hlen = md_get_size( md_info );
// first comparison checks for overflow
if( ilen + 2 * hlen + 2 < ilen || olen < ilen + 2 * hlen + 2 )
return( POLARSSL_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( POLARSSL_ERR_RSA_RNG_FAILED + ret );
p += hlen;
// Construct DB
//
md( md_info, label, label_len, p );
p += hlen;
p += olen - 2 * hlen - 2 - ilen;
*p++ = 1;
memcpy( p, input, ilen );
md_init( &md_ctx );
if( ( ret = md_init_ctx( &md_ctx, md_info ) ) != 0 )
{
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 );
md_free( &md_ctx );
return( ( mode == RSA_PUBLIC )
? rsa_public( ctx, output, output )
: rsa_private( ctx, f_rng, p_rng, output, output ) );
}
#endif /* POLARSSL_PKCS1_V21 */
#if defined(POLARSSL_PKCS1_V15)
/*
* Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function
*/
int rsa_rsaes_pkcs1_v15_encrypt( 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 == RSA_PRIVATE && ctx->padding != RSA_PKCS_V15 )
return( POLARSSL_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( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
olen = ctx->len;
// first comparison checks for overflow
if( ilen + 11 < ilen || olen < ilen + 11 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
nb_pad = olen - 3 - ilen;
*p++ = 0;
if( mode == RSA_PUBLIC )
{
*p++ = 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( POLARSSL_ERR_RSA_RNG_FAILED + ret );
p++;
}
}
else
{
*p++ = RSA_SIGN;
while( nb_pad-- > 0 )
*p++ = 0xFF;
}
*p++ = 0;
memcpy( p, input, ilen );
return( ( mode == RSA_PUBLIC )
? rsa_public( ctx, output, output )
: rsa_private( ctx, f_rng, p_rng, output, output ) );
}
#endif /* POLARSSL_PKCS1_V15 */
/*
* Add the message padding, then do an RSA operation
*/
int rsa_pkcs1_encrypt( 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(POLARSSL_PKCS1_V15)
case RSA_PKCS_V15:
return rsa_rsaes_pkcs1_v15_encrypt( ctx, f_rng, p_rng, mode, ilen,
input, output );
#endif
#if defined(POLARSSL_PKCS1_V21)
case RSA_PKCS_V21:
return rsa_rsaes_oaep_encrypt( ctx, f_rng, p_rng, mode, NULL, 0,
ilen, input, output );
#endif
default:
return( POLARSSL_ERR_RSA_INVALID_PADDING );
}
}
#if defined(POLARSSL_PKCS1_V21)
/*
* Implementation of the PKCS#1 v2.1 RSAES-OAEP-DECRYPT function
*/
int rsa_rsaes_oaep_decrypt( 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[POLARSSL_MPI_MAX_SIZE];
unsigned char lhash[POLARSSL_MD_MAX_SIZE];
unsigned int hlen;
const md_info_t *md_info;
md_context_t md_ctx;
/*
* Parameters sanity checks
*/
if( mode == RSA_PRIVATE && ctx->padding != RSA_PKCS_V21 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
ilen = ctx->len;
if( ilen < 16 || ilen > sizeof( buf ) )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
md_info = md_info_from_type( (md_type_t) ctx->hash_id );
if( md_info == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
hlen = md_get_size( md_info );
// checking for integer underflow
if( 2 * hlen + 2 > ilen )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
/*
* RSA operation
*/
ret = ( mode == RSA_PUBLIC )
? rsa_public( ctx, input, buf )
: rsa_private( ctx, f_rng, p_rng, input, buf );
if( ret != 0 )
goto cleanup;
/*
* Unmask data and generate lHash
*/
hlen = md_get_size( md_info );
// checking for integer underflow
if( 2 * hlen + 2 > ilen )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
md_init( &md_ctx );
if( ( ret = md_init_ctx( &md_ctx, md_info ) ) != 0 )
{
md_free( &md_ctx );
return( ret );
}
/* Generate lHash */
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 );
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 = POLARSSL_ERR_RSA_INVALID_PADDING;
goto cleanup;
}
if( ilen - ( p - buf ) > output_max_len )
{
ret = POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE;
goto cleanup;
}
*olen = ilen - (p - buf);
memcpy( output, p, *olen );
ret = 0;
cleanup:
polarssl_zeroize( buf, sizeof( buf ) );
polarssl_zeroize( lhash, sizeof( lhash ) );
return( ret );
}
#endif /* POLARSSL_PKCS1_V21 */
#if defined(POLARSSL_PKCS1_V15)
/*
* Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function
*/
int rsa_rsaes_pkcs1_v15_decrypt( 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, pad_count = 0, i;
unsigned char *p, bad, pad_done = 0;
unsigned char buf[POLARSSL_MPI_MAX_SIZE];
if( mode == RSA_PRIVATE && ctx->padding != RSA_PKCS_V15 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
ilen = ctx->len;
if( ilen < 16 || ilen > sizeof( buf ) )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
ret = ( mode == RSA_PUBLIC )
? rsa_public( ctx, input, buf )
: rsa_private( ctx, f_rng, p_rng, input, buf );
if( ret != 0 )
goto cleanup;
p = buf;
bad = 0;
/*
* 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 == RSA_PRIVATE )
{
bad |= *p++ ^ 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++ ^ 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 */
}
bad |= ( pad_count < 8 );
if( bad )
{
ret = POLARSSL_ERR_RSA_INVALID_PADDING;
goto cleanup;
}
if( ilen - ( p - buf ) > output_max_len )
{
ret = POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE;
goto cleanup;
}
*olen = ilen - (p - buf);
memcpy( output, p, *olen );
ret = 0;
cleanup:
polarssl_zeroize( buf, sizeof( buf ) );
return( ret );
}
#endif /* POLARSSL_PKCS1_V15 */
/*
* Do an RSA operation, then remove the message padding
*/
int rsa_pkcs1_decrypt( 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(POLARSSL_PKCS1_V15)
case RSA_PKCS_V15:
return rsa_rsaes_pkcs1_v15_decrypt( ctx, f_rng, p_rng, mode, olen,
input, output, output_max_len );
#endif
#if defined(POLARSSL_PKCS1_V21)
case RSA_PKCS_V21:
return rsa_rsaes_oaep_decrypt( ctx, f_rng, p_rng, mode, NULL, 0,
olen, input, output,
output_max_len );
#endif
default:
return( POLARSSL_ERR_RSA_INVALID_PADDING );
}
}
#if defined(POLARSSL_PKCS1_V21)
/*
* Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function
*/
int rsa_rsassa_pss_sign( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
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[POLARSSL_MD_MAX_SIZE];
unsigned int slen, hlen, offset = 0;
int ret;
size_t msb;
const md_info_t *md_info;
md_context_t md_ctx;
if( mode == RSA_PRIVATE && ctx->padding != RSA_PKCS_V21 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
if( f_rng == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
olen = ctx->len;
if( md_alg != POLARSSL_MD_NONE )
{
// Gather length of hash to sign
//
md_info = md_info_from_type( md_alg );
if( md_info == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
hashlen = md_get_size( md_info );
}
md_info = md_info_from_type( (md_type_t) ctx->hash_id );
if( md_info == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
hlen = md_get_size( md_info );
slen = hlen;
if( olen < hlen + slen + 2 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
memset( sig, 0, olen );
// Generate salt of length slen
//
if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 )
return( POLARSSL_ERR_RSA_RNG_FAILED + ret );
// Note: EMSA-PSS encoding is over the length of N - 1 bits
//
msb = mpi_msb( &ctx->N ) - 1;
p += olen - hlen * 2 - 2;
*p++ = 0x01;
memcpy( p, salt, slen );
p += slen;
md_init( &md_ctx );
if( ( ret = md_init_ctx( &md_ctx, md_info ) ) != 0 )
{
md_free( &md_ctx );
/* No need to zeroize salt: we didn't use it. */
return( ret );
}
// Generate H = Hash( M' )
//
md_starts( &md_ctx );
md_update( &md_ctx, p, 8 );
md_update( &md_ctx, hash, hashlen );
md_update( &md_ctx, salt, slen );
md_finish( &md_ctx, p );
polarssl_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 );
md_free( &md_ctx );
msb = mpi_msb( &ctx->N ) - 1;
sig[0] &= 0xFF >> ( olen * 8 - msb );
p += hlen;
*p++ = 0xBC;
return( ( mode == RSA_PUBLIC )
? rsa_public( ctx, sig, sig )
: rsa_private( ctx, f_rng, p_rng, sig, sig ) );
}
#endif /* POLARSSL_PKCS1_V21 */
#if defined(POLARSSL_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 rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
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;
unsigned char *sig_try = NULL, *verif = NULL;
size_t i;
unsigned char diff;
volatile unsigned char diff_no_optimize;
int ret;
if( mode == RSA_PRIVATE && ctx->padding != RSA_PKCS_V15 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
olen = ctx->len;
nb_pad = olen - 3;
if( md_alg != POLARSSL_MD_NONE )
{
const md_info_t *md_info = md_info_from_type( md_alg );
if( md_info == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
if( oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
nb_pad -= 10 + oid_size;
hashlen = md_get_size( md_info );
}
nb_pad -= hashlen;
if( ( nb_pad < 8 ) || ( nb_pad > olen ) )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
*p++ = 0;
*p++ = RSA_SIGN;
memset( p, 0xFF, nb_pad );
p += nb_pad;
*p++ = 0;
if( md_alg == POLARSSL_MD_NONE )
{
memcpy( p, hash, hashlen );
}
else
{
/*
* DigestInfo ::= SEQUENCE {
* digestAlgorithm DigestAlgorithmIdentifier,
* digest Digest }
*
* DigestAlgorithmIdentifier ::= AlgorithmIdentifier
*
* Digest ::= OCTET STRING
*/
*p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED;
*p++ = (unsigned char) ( 0x08 + oid_size + hashlen );
*p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED;
*p++ = (unsigned char) ( 0x04 + oid_size );
*p++ = ASN1_OID;
*p++ = oid_size & 0xFF;
memcpy( p, oid, oid_size );
p += oid_size;
*p++ = ASN1_NULL;
*p++ = 0x00;
*p++ = ASN1_OCTET_STRING;
*p++ = hashlen;
memcpy( p, hash, hashlen );
}
if( mode == RSA_PUBLIC )
return( rsa_public( ctx, sig, sig ) );
/*
* In order to prevent Lenstra's attack, make the signature in a
* temporary buffer and check it before returning it.
*/
sig_try = polarssl_malloc( ctx->len );
if( sig_try == NULL )
return( POLARSSL_ERR_MPI_MALLOC_FAILED );
verif = polarssl_malloc( ctx->len );
if( verif == NULL )
{
polarssl_free( sig_try );
return( POLARSSL_ERR_MPI_MALLOC_FAILED );
}
MPI_CHK( rsa_private( ctx, f_rng, p_rng, sig, sig_try ) );
MPI_CHK( rsa_public( ctx, sig_try, verif ) );
/* Compare in constant time just in case */
for( diff = 0, i = 0; i < ctx->len; i++ )
diff |= verif[i] ^ sig[i];
diff_no_optimize = diff;
if( diff_no_optimize != 0 )
{
ret = POLARSSL_ERR_RSA_PRIVATE_FAILED;
goto cleanup;
}
memcpy( sig, sig_try, ctx->len );
cleanup:
polarssl_free( sig_try );
polarssl_free( verif );
return( ret );
}
#endif /* POLARSSL_PKCS1_V15 */
/*
* Do an RSA operation to sign the message digest
*/
int rsa_pkcs1_sign( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
md_type_t md_alg,
unsigned int hashlen,
const unsigned char *hash,
unsigned char *sig )
{
switch( ctx->padding )
{
#if defined(POLARSSL_PKCS1_V15)
case RSA_PKCS_V15:
return rsa_rsassa_pkcs1_v15_sign( ctx, f_rng, p_rng, mode, md_alg,
hashlen, hash, sig );
#endif
#if defined(POLARSSL_PKCS1_V21)
case RSA_PKCS_V21:
return rsa_rsassa_pss_sign( ctx, f_rng, p_rng, mode, md_alg,
hashlen, hash, sig );
#endif
default:
return( POLARSSL_ERR_RSA_INVALID_PADDING );
}
}
#if defined(POLARSSL_PKCS1_V21)
/*
* Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function
*/
int rsa_rsassa_pss_verify_ext( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
md_type_t md_alg,
unsigned int hashlen,
const unsigned char *hash,
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[POLARSSL_MPI_MAX_SIZE];
unsigned char *hash_start;
unsigned char result[POLARSSL_MD_MAX_SIZE];
unsigned char zeros[8];
unsigned int hlen;
size_t observed_salt_len, msb;
const md_info_t *md_info;
md_context_t md_ctx;
if( mode == RSA_PRIVATE && ctx->padding != RSA_PKCS_V21 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
siglen = ctx->len;
if( siglen < 16 || siglen > sizeof( buf ) )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
ret = ( mode == RSA_PUBLIC )
? rsa_public( ctx, sig, buf )
: rsa_private( ctx, f_rng, p_rng, sig, buf );
if( ret != 0 )
return( ret );
p = buf;
if( buf[siglen - 1] != 0xBC )
return( POLARSSL_ERR_RSA_INVALID_PADDING );
if( md_alg != POLARSSL_MD_NONE )
{
// Gather length of hash to sign
//
md_info = md_info_from_type( md_alg );
if( md_info == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
hashlen = md_get_size( md_info );
}
md_info = md_info_from_type( mgf1_hash_id );
if( md_info == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
hlen = md_get_size( md_info );
memset( zeros, 0, 8 );
// Note: EMSA-PSS verification is over the length of N - 1 bits
//
msb = mpi_msb( &ctx->N ) - 1;
if( buf[0] >> ( 8 - siglen * 8 + msb ) )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
// Compensate for boundary condition when applying mask
//
if( msb % 8 == 0 )
{
p++;
siglen -= 1;
}
if( siglen < hlen + 2 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
hash_start = p + siglen - hlen - 1;
md_init( &md_ctx );
if( ( ret = md_init_ctx( &md_ctx, md_info ) ) != 0 )
{
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 )
{
md_free( &md_ctx );
return( POLARSSL_ERR_RSA_INVALID_PADDING );
}
observed_salt_len = hash_start - p;
if( expected_salt_len != RSA_SALT_LEN_ANY &&
observed_salt_len != (size_t) expected_salt_len )
{
md_free( &md_ctx );
return( POLARSSL_ERR_RSA_INVALID_PADDING );
}
// Generate H = Hash( M' )
//
md_starts( &md_ctx );
md_update( &md_ctx, zeros, 8 );
md_update( &md_ctx, hash, hashlen );
md_update( &md_ctx, p, observed_salt_len );
md_finish( &md_ctx, result );
md_free( &md_ctx );
if( memcmp( hash_start, result, hlen ) == 0 )
return( 0 );
else
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
}
/*
* Simplified PKCS#1 v2.1 RSASSA-PSS-VERIFY function
*/
int rsa_rsassa_pss_verify( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
md_type_t md_alg,
unsigned int hashlen,
const unsigned char *hash,
const unsigned char *sig )
{
md_type_t mgf1_hash_id = ( ctx->hash_id != POLARSSL_MD_NONE )
? (md_type_t) ctx->hash_id
: md_alg;
return( rsa_rsassa_pss_verify_ext( ctx, f_rng, p_rng, mode,
md_alg, hashlen, hash,
mgf1_hash_id, RSA_SALT_LEN_ANY,
sig ) );
}
#endif /* POLARSSL_PKCS1_V21 */
#if defined(POLARSSL_PKCS1_V15)
/*
* Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function
*/
int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
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[POLARSSL_MPI_MAX_SIZE];
md_type_t msg_md_alg;
const md_info_t *md_info;
asn1_buf oid;
if( mode == RSA_PRIVATE && ctx->padding != RSA_PKCS_V15 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
siglen = ctx->len;
if( siglen < 16 || siglen > sizeof( buf ) )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
ret = ( mode == RSA_PUBLIC )
? rsa_public( ctx, sig, buf )
: rsa_private( ctx, f_rng, p_rng, sig, buf );
if( ret != 0 )
return( ret );
p = buf;
if( *p++ != 0 || *p++ != RSA_SIGN )
return( POLARSSL_ERR_RSA_INVALID_PADDING );
while( *p != 0 )
{
if( p >= buf + siglen - 1 || *p != 0xFF )
return( POLARSSL_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( POLARSSL_ERR_RSA_INVALID_PADDING );
len = siglen - ( p - buf );
if( len == hashlen && md_alg == POLARSSL_MD_NONE )
{
if( memcmp( p, hash, hashlen ) == 0 )
return( 0 );
else
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
}
md_info = md_info_from_type( md_alg );
if( md_info == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
hashlen = 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 = asn1_get_tag( &p, end, &asn1_len,
ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
if( p != p0 + 2 || asn1_len + 2 != len )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
p0 = p;
if( ( ret = asn1_get_tag( &p, end, &asn1_len,
ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
if( p != p0 + 2 || asn1_len + 6 + hashlen != len )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
p0 = p;
if( ( ret = asn1_get_tag( &p, end, &oid.len, ASN1_OID ) ) != 0 )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
if( p != p0 + 2 )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
oid.p = p;
p += oid.len;
if( oid_get_md_alg( &oid, &msg_md_alg ) != 0 )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
if( md_alg != msg_md_alg )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
/*
* assume the algorithm parameters must be NULL
*/
p0 = p;
if( ( ret = asn1_get_tag( &p, end, &asn1_len, ASN1_NULL ) ) != 0 )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
if( p != p0 + 2 )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
p0 = p;
if( ( ret = asn1_get_tag( &p, end, &asn1_len, ASN1_OCTET_STRING ) ) != 0 )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
if( p != p0 + 2 || asn1_len != hashlen )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
if( memcmp( p, hash, hashlen ) != 0 )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
p += hashlen;
if( p != end )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
return( 0 );
}
#endif /* POLARSSL_PKCS1_V15 */
/*
* Do an RSA operation and check the message digest
*/
int rsa_pkcs1_verify( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
md_type_t md_alg,
unsigned int hashlen,
const unsigned char *hash,
const unsigned char *sig )
{
switch( ctx->padding )
{
#if defined(POLARSSL_PKCS1_V15)
case RSA_PKCS_V15:
return rsa_rsassa_pkcs1_v15_verify( ctx, f_rng, p_rng, mode, md_alg,
hashlen, hash, sig );
#endif
#if defined(POLARSSL_PKCS1_V21)
case RSA_PKCS_V21:
return rsa_rsassa_pss_verify( ctx, f_rng, p_rng, mode, md_alg,
hashlen, hash, sig );
#endif
default:
return( POLARSSL_ERR_RSA_INVALID_PADDING );
}
}
/*
* Copy the components of an RSA key
*/
int rsa_copy( rsa_context *dst, const rsa_context *src )
{
int ret;
dst->ver = src->ver;
dst->len = src->len;
MPI_CHK( mpi_copy( &dst->N, &src->N ) );
MPI_CHK( mpi_copy( &dst->E, &src->E ) );
MPI_CHK( mpi_copy( &dst->D, &src->D ) );
MPI_CHK( mpi_copy( &dst->P, &src->P ) );
MPI_CHK( mpi_copy( &dst->Q, &src->Q ) );
MPI_CHK( mpi_copy( &dst->DP, &src->DP ) );
MPI_CHK( mpi_copy( &dst->DQ, &src->DQ ) );
MPI_CHK( mpi_copy( &dst->QP, &src->QP ) );
MPI_CHK( mpi_copy( &dst->RN, &src->RN ) );
MPI_CHK( mpi_copy( &dst->RP, &src->RP ) );
MPI_CHK( mpi_copy( &dst->RQ, &src->RQ ) );
MPI_CHK( mpi_copy( &dst->Vi, &src->Vi ) );
MPI_CHK( mpi_copy( &dst->Vf, &src->Vf ) );
dst->padding = src->padding;
dst->hash_id = src->hash_id;
cleanup:
if( ret != 0 )
rsa_free( dst );
return( ret );
}
/*
* Free the components of an RSA key
*/
void rsa_free( rsa_context *ctx )
{
mpi_free( &ctx->Vi ); mpi_free( &ctx->Vf );
mpi_free( &ctx->RQ ); mpi_free( &ctx->RP ); mpi_free( &ctx->RN );
mpi_free( &ctx->QP ); mpi_free( &ctx->DQ ); mpi_free( &ctx->DP );
mpi_free( &ctx->Q ); mpi_free( &ctx->P ); mpi_free( &ctx->D );
mpi_free( &ctx->E ); mpi_free( &ctx->N );
#if defined(POLARSSL_THREADING_C)
polarssl_mutex_free( &ctx->mutex );
#endif
}
#if defined(POLARSSL_SELF_TEST)
#include "polarssl/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(POLARSSL_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 /* POLARSSL_PKCS1_V15 */
/*
* Checkup routine
*/
int rsa_self_test( int verbose )
{
int ret = 0;
#if defined(POLARSSL_PKCS1_V15)
size_t len;
rsa_context rsa;
unsigned char rsa_plaintext[PT_LEN];
unsigned char rsa_decrypted[PT_LEN];
unsigned char rsa_ciphertext[KEY_LEN];
#if defined(POLARSSL_SHA1_C)
unsigned char sha1sum[20];
#endif
rsa_init( &rsa, RSA_PKCS_V15, 0 );
rsa.len = KEY_LEN;
MPI_CHK( mpi_read_string( &rsa.N , 16, RSA_N ) );
MPI_CHK( mpi_read_string( &rsa.E , 16, RSA_E ) );
MPI_CHK( mpi_read_string( &rsa.D , 16, RSA_D ) );
MPI_CHK( mpi_read_string( &rsa.P , 16, RSA_P ) );
MPI_CHK( mpi_read_string( &rsa.Q , 16, RSA_Q ) );
MPI_CHK( mpi_read_string( &rsa.DP, 16, RSA_DP ) );
MPI_CHK( mpi_read_string( &rsa.DQ, 16, RSA_DQ ) );
MPI_CHK( mpi_read_string( &rsa.QP, 16, RSA_QP ) );
if( verbose != 0 )
polarssl_printf( " RSA key validation: " );
if( rsa_check_pubkey( &rsa ) != 0 ||
rsa_check_privkey( &rsa ) != 0 )
{
if( verbose != 0 )
polarssl_printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
polarssl_printf( "passed\n PKCS#1 encryption : " );
memcpy( rsa_plaintext, RSA_PT, PT_LEN );
if( rsa_pkcs1_encrypt( &rsa, myrand, NULL, RSA_PUBLIC, PT_LEN,
rsa_plaintext, rsa_ciphertext ) != 0 )
{
if( verbose != 0 )
polarssl_printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
polarssl_printf( "passed\n PKCS#1 decryption : " );
if( rsa_pkcs1_decrypt( &rsa, myrand, NULL, RSA_PRIVATE, &len,
rsa_ciphertext, rsa_decrypted,
sizeof(rsa_decrypted) ) != 0 )
{
if( verbose != 0 )
polarssl_printf( "failed\n" );
return( 1 );
}
if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 )
{
if( verbose != 0 )
polarssl_printf( "failed\n" );
return( 1 );
}
#if defined(POLARSSL_SHA1_C)
if( verbose != 0 )
polarssl_printf( "passed\n PKCS#1 data sign : " );
sha1( rsa_plaintext, PT_LEN, sha1sum );
if( rsa_pkcs1_sign( &rsa, myrand, NULL, RSA_PRIVATE, POLARSSL_MD_SHA1, 0,
sha1sum, rsa_ciphertext ) != 0 )
{
if( verbose != 0 )
polarssl_printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
polarssl_printf( "passed\n PKCS#1 sig. verify: " );
if( rsa_pkcs1_verify( &rsa, NULL, NULL, RSA_PUBLIC, POLARSSL_MD_SHA1, 0,
sha1sum, rsa_ciphertext ) != 0 )
{
if( verbose != 0 )
polarssl_printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
polarssl_printf( "passed\n\n" );
#endif /* POLARSSL_SHA1_C */
cleanup:
rsa_free( &rsa );
#else /* POLARSSL_PKCS1_V15 */
((void) verbose);
#endif /* POLARSSL_PKCS1_V15 */
return( ret );
}
#endif /* POLARSSL_SELF_TEST */
#endif /* POLARSSL_RSA_C */