mbedtls/library/rsa.c
Paul Bakker c70b982056 OID functionality moved to a separate module.
A new OID module has been created that contains the main OID searching
functionality based on type-dependent arrays. A base type is used to
contain the basic values (oid_descriptor_t) and that type is extended to
contain type specific information (like a pk_alg_t).

As a result the rsa sign and verify function prototypes have changed. They
now expect a md_type_t identifier instead of the removed RSA_SIG_XXX
defines.

All OID definitions have been moved to oid.h
All OID matching code is in the OID module.

The RSA PKCS#1 functions cleaned up as a result and adapted to use the
MD layer.

The SSL layer cleanup up as a result and adapted to use the MD layer.

The X509 parser cleaned up and matches OIDs in certificates with new
module and adapted to use the MD layer.

The X509 writer cleaned up and adapted to use the MD layer.

Apps and tests modified accordingly
2013-04-07 22:00:46 +02:00

1393 lines
36 KiB
C

/*
* The RSA public-key cryptosystem
*
* Copyright (C) 2006-2011, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* 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
*/
#include "polarssl/config.h"
#if defined(POLARSSL_RSA_C)
#include "polarssl/rsa.h"
#include "polarssl/oid.h"
#if defined(POLARSSL_PKCS1_V21)
#include "polarssl/md.h"
#endif
#include <stdlib.h>
#include <stdio.h>
/*
* Initialize an RSA context
*/
void rsa_init( rsa_context *ctx,
int padding,
int hash_id )
{
memset( ctx, 0, sizeof( rsa_context ) );
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 );
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 ) >> 1, 0,
f_rng, p_rng ) );
MPI_CHK( mpi_gen_prime( &ctx->Q, ( nbits + 1 ) >> 1, 0,
f_rng, p_rng ) );
if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 )
mpi_swap( &ctx->P, &ctx->Q );
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;
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
/*
* 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_msb( &ctx->E ) > 64 )
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 );
}
/*
* 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 );
MPI_CHK( mpi_read_binary( &T, input, ctx->len ) );
if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
{
mpi_free( &T );
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
}
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:
mpi_free( &T );
if( ret != 0 )
return( POLARSSL_ERR_RSA_PUBLIC_FAILED + ret );
return( 0 );
}
/*
* Do an RSA private key operation
*/
int rsa_private( rsa_context *ctx,
const unsigned char *input,
unsigned char *output )
{
int ret;
size_t olen;
mpi T, T1, T2;
mpi_init( &T ); mpi_init( &T1 ); mpi_init( &T2 );
MPI_CHK( mpi_read_binary( &T, input, ctx->len ) );
if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
{
mpi_free( &T );
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
}
#if defined(POLARSSL_RSA_NO_CRT)
MPI_CHK( mpi_exp_mod( &T, &T, &ctx->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, &ctx->DP, &ctx->P, &ctx->RP ) );
MPI_CHK( mpi_exp_mod( &T2, &T, &ctx->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 ) );
/*
* output = T2 + T * Q
*/
MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) );
MPI_CHK( mpi_add_mpi( &T, &T2, &T1 ) );
#endif
olen = ctx->len;
MPI_CHK( mpi_write_binary( &T, output, olen ) );
cleanup:
mpi_free( &T ); mpi_free( &T1 ); mpi_free( &T2 );
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;
}
}
#endif
#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( ctx->padding != RSA_PKCS_V21 || f_rng == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
md_info = md_info_from_type( ctx->hash_id );
if( md_info == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
olen = ctx->len;
hlen = md_get_size( md_info );
if( olen < ilen + 2 * hlen + 2 || f_rng == NULL )
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_ctx( &md_ctx, md_info );
// 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_ctx( &md_ctx );
return( ( mode == RSA_PUBLIC )
? rsa_public( ctx, output, output )
: rsa_private( ctx, output, output ) );
}
#endif /* POLARSSL_PKCS1_V21 */
/*
* 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( ctx->padding != RSA_PKCS_V15 || f_rng == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
olen = ctx->len;
if( 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, output, output ) );
}
/*
* 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 )
{
case RSA_PKCS_V15:
return rsa_rsaes_pkcs1_v15_encrypt( ctx, f_rng, p_rng, mode, ilen,
input, output );
#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 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;
unsigned char *p;
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;
if( 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 );
ret = ( mode == RSA_PUBLIC )
? rsa_public( ctx, input, buf )
: rsa_private( ctx, input, buf );
if( ret != 0 )
return( ret );
p = buf;
if( *p++ != 0 )
return( POLARSSL_ERR_RSA_INVALID_PADDING );
md_info = md_info_from_type( ctx->hash_id );
if( md_info == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
hlen = md_get_size( md_info );
md_init_ctx( &md_ctx, md_info );
// 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 );
p += hlen;
md_free_ctx( &md_ctx );
// Check validity
//
if( memcmp( lhash, p, hlen ) != 0 )
return( POLARSSL_ERR_RSA_INVALID_PADDING );
p += hlen;
while( *p == 0 && p < buf + ilen )
p++;
if( p == buf + ilen )
return( POLARSSL_ERR_RSA_INVALID_PADDING );
if( *p++ != 0x01 )
return( POLARSSL_ERR_RSA_INVALID_PADDING );
if (ilen - (p - buf) > output_max_len)
return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE );
*olen = ilen - (p - buf);
memcpy( output, p, *olen );
return( 0 );
}
#endif /* POLARSSL_PKCS1_V21 */
/*
* Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function
*/
int rsa_rsaes_pkcs1_v15_decrypt( rsa_context *ctx,
int mode, size_t *olen,
const unsigned char *input,
unsigned char *output,
size_t output_max_len)
{
int ret, correct = 1;
size_t ilen, pad_count = 0;
unsigned char *p, *q;
unsigned char bt;
unsigned char buf[POLARSSL_MPI_MAX_SIZE];
if( 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, input, buf );
if( ret != 0 )
return( ret );
p = buf;
if( *p++ != 0 )
correct = 0;
bt = *p++;
if( ( bt != RSA_CRYPT && mode == RSA_PRIVATE ) ||
( bt != RSA_SIGN && mode == RSA_PUBLIC ) )
{
correct = 0;
}
if( bt == RSA_CRYPT )
{
while( *p != 0 && p < buf + ilen - 1 )
pad_count += ( *p++ != 0 );
correct &= ( *p == 0 && p < buf + ilen - 1 );
q = p;
// Also pass over all other bytes to reduce timing differences
//
while ( q < buf + ilen - 1 )
pad_count += ( *q++ != 0 );
// Prevent compiler optimization of pad_count
//
correct |= pad_count & 0x100000; /* Always 0 unless 1M bit keys */
p++;
}
else
{
while( *p == 0xFF && p < buf + ilen - 1 )
pad_count += ( *p++ == 0xFF );
correct &= ( *p == 0 && p < buf + ilen - 1 );
q = p;
// Also pass over all other bytes to reduce timing differences
//
while ( q < buf + ilen - 1 )
pad_count += ( *q++ != 0 );
// Prevent compiler optimization of pad_count
//
correct |= pad_count & 0x100000; /* Always 0 unless 1M bit keys */
p++;
}
if( correct == 0 )
return( POLARSSL_ERR_RSA_INVALID_PADDING );
if (ilen - (p - buf) > output_max_len)
return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE );
*olen = ilen - (p - buf);
memcpy( output, p, *olen );
return( 0 );
}
/*
* Do an RSA operation, then remove the message padding
*/
int rsa_pkcs1_decrypt( rsa_context *ctx,
int mode, size_t *olen,
const unsigned char *input,
unsigned char *output,
size_t output_max_len)
{
switch( ctx->padding )
{
case RSA_PKCS_V15:
return rsa_rsaes_pkcs1_v15_decrypt( ctx, mode, olen, input, output,
output_max_len );
#if defined(POLARSSL_PKCS1_V21)
case RSA_PKCS_V21:
return rsa_rsaes_oaep_decrypt( ctx, 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( ctx->padding != RSA_PKCS_V21 || 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( 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 );
msb = mpi_msb( &ctx->N ) - 1;
// 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_ctx( &md_ctx, md_info );
// 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 );
// 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_ctx( &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, sig, sig ) );
}
#endif /* POLARSSL_PKCS1_V21 */
/*
* 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 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;
if( 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 ) != 0 )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
oid_size = strlen( oid );
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++ = 0x08 + oid_size + hashlen;
*p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED;
*p++ = 0x04 + oid_size;
*p++ = ASN1_OID;
*p++ = oid_size;
memcpy( p, oid, oid_size );
p += oid_size;
*p++ = ASN1_NULL;
*p++ = 0x00;
*p++ = ASN1_OCTET_STRING;
*p++ = hashlen;
memcpy( p, hash, hashlen );
}
return( ( mode == RSA_PUBLIC )
? rsa_public( ctx, sig, sig )
: rsa_private( ctx, sig, sig ) );
}
/*
* 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 )
{
case RSA_PKCS_V15:
return rsa_rsassa_pkcs1_v15_sign( ctx, mode, md_alg,
hashlen, hash, sig );
#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( rsa_context *ctx,
int mode,
md_type_t md_alg,
unsigned int hashlen,
const unsigned char *hash,
unsigned char *sig )
{
int ret;
size_t siglen;
unsigned char *p;
unsigned char buf[POLARSSL_MPI_MAX_SIZE];
unsigned char result[POLARSSL_MD_MAX_SIZE];
unsigned char zeros[8];
unsigned int hlen;
size_t slen, msb;
const md_info_t *md_info;
md_context_t md_ctx;
if( 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, 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( ctx->hash_id );
if( md_info == NULL )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
hlen = md_get_size( md_info );
slen = siglen - hlen - 1;
memset( zeros, 0, 8 );
// Note: EMSA-PSS verification is over the length of N - 1 bits
//
msb = mpi_msb( &ctx->N ) - 1;
// Compensate for boundary condition when applying mask
//
if( msb % 8 == 0 )
{
p++;
siglen -= 1;
}
if( buf[0] >> ( 8 - siglen * 8 + msb ) )
return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
md_init_ctx( &md_ctx, md_info );
mgf_mask( p, siglen - hlen - 1, p + siglen - hlen - 1, hlen, &md_ctx );
buf[0] &= 0xFF >> ( siglen * 8 - msb );
while( *p == 0 && p < buf + siglen )
p++;
if( p == buf + siglen ||
*p++ != 0x01 )
{
md_free_ctx( &md_ctx );
return( POLARSSL_ERR_RSA_INVALID_PADDING );
}
slen -= p - buf;
// 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, slen );
md_finish( &md_ctx, result );
md_free_ctx( &md_ctx );
if( memcmp( p + slen, result, hlen ) == 0 )
return( 0 );
else
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
}
#endif /* POLARSSL_PKCS1_V21 */
/*
* Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function
*/
int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx,
int mode,
md_type_t md_alg,
unsigned int hashlen,
const unsigned char *hash,
unsigned char *sig )
{
int ret;
size_t len, siglen, asn1_len;
unsigned char *p, *end;
unsigned char buf[POLARSSL_MPI_MAX_SIZE];
md_type_t msg_md_alg;
const md_info_t *md_info;
asn1_buf oid;
if( 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, 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++;
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
//
if( ( ret = asn1_get_tag( &p, end, &asn1_len,
ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
if( asn1_len + 2 != len )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
if( ( ret = asn1_get_tag( &p, end, &asn1_len,
ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
if( asn1_len + 6 + hashlen != len )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
if( ( ret = asn1_get_tag( &p, end, &oid.len, ASN1_OID ) ) != 0 )
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
*/
if( ( ret = asn1_get_tag( &p, end, &asn1_len, ASN1_NULL ) ) != 0 )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
if( ( ret = asn1_get_tag( &p, end, &asn1_len, ASN1_OCTET_STRING ) ) != 0 )
return( POLARSSL_ERR_RSA_VERIFY_FAILED );
if( 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 );
}
/*
* Do an RSA operation and check the message digest
*/
int rsa_pkcs1_verify( rsa_context *ctx,
int mode,
md_type_t md_alg,
unsigned int hashlen,
const unsigned char *hash,
unsigned char *sig )
{
switch( ctx->padding )
{
case RSA_PKCS_V15:
return rsa_rsassa_pkcs1_v15_verify( ctx, mode, md_alg,
hashlen, hash, sig );
#if defined(POLARSSL_PKCS1_V21)
case RSA_PKCS_V21:
return rsa_rsassa_pss_verify( ctx, mode, md_alg,
hashlen, hash, sig );
#endif
default:
return( POLARSSL_ERR_RSA_INVALID_PADDING );
}
}
/*
* Free the components of an RSA key
*/
void rsa_free( rsa_context *ctx )
{
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_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"
static int myrand( void *rng_state, unsigned char *output, size_t len )
{
size_t i;
if( rng_state != NULL )
rng_state = NULL;
for( i = 0; i < len; ++i )
output[i] = rand();
return( 0 );
}
/*
* Checkup routine
*/
int rsa_self_test( int verbose )
{
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_read_string( &rsa.N , 16, RSA_N );
mpi_read_string( &rsa.E , 16, RSA_E );
mpi_read_string( &rsa.D , 16, RSA_D );
mpi_read_string( &rsa.P , 16, RSA_P );
mpi_read_string( &rsa.Q , 16, RSA_Q );
mpi_read_string( &rsa.DP, 16, RSA_DP );
mpi_read_string( &rsa.DQ, 16, RSA_DQ );
mpi_read_string( &rsa.QP, 16, RSA_QP );
if( verbose != 0 )
printf( " RSA key validation: " );
if( rsa_check_pubkey( &rsa ) != 0 ||
rsa_check_privkey( &rsa ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
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 )
printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
printf( "passed\n PKCS#1 decryption : " );
if( rsa_pkcs1_decrypt( &rsa, RSA_PRIVATE, &len,
rsa_ciphertext, rsa_decrypted,
sizeof(rsa_decrypted) ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
#if defined(POLARSSL_SHA1_C)
if( verbose != 0 )
printf( "passed\n PKCS#1 data sign : " );
sha1( rsa_plaintext, PT_LEN, sha1sum );
if( rsa_pkcs1_sign( &rsa, NULL, NULL, RSA_PRIVATE, POLARSSL_MD_SHA1, 0,
sha1sum, rsa_ciphertext ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
printf( "passed\n PKCS#1 sig. verify: " );
if( rsa_pkcs1_verify( &rsa, RSA_PUBLIC, POLARSSL_MD_SHA1, 0,
sha1sum, rsa_ciphertext ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
printf( "passed\n\n" );
#endif /* POLARSSL_SHA1_C */
rsa_free( &rsa );
return( 0 );
}
#endif
#endif