Ensure that the configured RSA digestInfo prefixes are included in any build that includes rsa.o (rather than relying on x509.o or tls.o also being present in the final binary). This allows the RSA self-tests to be run in isolation. Signed-off-by: Michael Brown <mcb30@ipxe.org>
644 lines
17 KiB
C
644 lines
17 KiB
C
/*
|
|
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
|
*
|
|
* 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 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.
|
|
*
|
|
* You can also choose to distribute this program under the terms of
|
|
* the Unmodified Binary Distribution Licence (as given in the file
|
|
* COPYING.UBDL), provided that you have satisfied its requirements.
|
|
*/
|
|
|
|
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <ipxe/asn1.h>
|
|
#include <ipxe/crypto.h>
|
|
#include <ipxe/bigint.h>
|
|
#include <ipxe/random_nz.h>
|
|
#include <ipxe/rsa.h>
|
|
|
|
/** @file
|
|
*
|
|
* RSA public-key cryptography
|
|
*
|
|
* RSA is documented in RFC 3447.
|
|
*/
|
|
|
|
/* Disambiguate the various error causes */
|
|
#define EACCES_VERIFY \
|
|
__einfo_error ( EINFO_EACCES_VERIFY )
|
|
#define EINFO_EACCES_VERIFY \
|
|
__einfo_uniqify ( EINFO_EACCES, 0x01, "RSA signature incorrect" )
|
|
|
|
/** "rsaEncryption" object identifier */
|
|
static uint8_t oid_rsa_encryption[] = { ASN1_OID_RSAENCRYPTION };
|
|
|
|
/** "rsaEncryption" OID-identified algorithm */
|
|
struct asn1_algorithm rsa_encryption_algorithm __asn1_algorithm = {
|
|
.name = "rsaEncryption",
|
|
.pubkey = &rsa_algorithm,
|
|
.digest = NULL,
|
|
.oid = ASN1_OID_CURSOR ( oid_rsa_encryption ),
|
|
};
|
|
|
|
/**
|
|
* Identify RSA prefix
|
|
*
|
|
* @v digest Digest algorithm
|
|
* @ret prefix RSA prefix, or NULL
|
|
*/
|
|
static struct rsa_digestinfo_prefix *
|
|
rsa_find_prefix ( struct digest_algorithm *digest ) {
|
|
struct rsa_digestinfo_prefix *prefix;
|
|
|
|
for_each_table_entry ( prefix, RSA_DIGESTINFO_PREFIXES ) {
|
|
if ( prefix->digest == digest )
|
|
return prefix;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* Free RSA dynamic storage
|
|
*
|
|
* @v context RSA context
|
|
*/
|
|
static void rsa_free ( struct rsa_context *context ) {
|
|
|
|
free ( context->dynamic );
|
|
context->dynamic = NULL;
|
|
}
|
|
|
|
/**
|
|
* Allocate RSA dynamic storage
|
|
*
|
|
* @v context RSA context
|
|
* @v modulus_len Modulus length
|
|
* @v exponent_len Exponent length
|
|
* @ret rc Return status code
|
|
*/
|
|
static int rsa_alloc ( struct rsa_context *context, size_t modulus_len,
|
|
size_t exponent_len ) {
|
|
unsigned int size = bigint_required_size ( modulus_len );
|
|
unsigned int exponent_size = bigint_required_size ( exponent_len );
|
|
bigint_t ( size ) *modulus;
|
|
bigint_t ( exponent_size ) *exponent;
|
|
size_t tmp_len = bigint_mod_exp_tmp_len ( modulus, exponent );
|
|
struct {
|
|
bigint_t ( size ) modulus;
|
|
bigint_t ( exponent_size ) exponent;
|
|
bigint_t ( size ) input;
|
|
bigint_t ( size ) output;
|
|
uint8_t tmp[tmp_len];
|
|
} __attribute__ (( packed )) *dynamic;
|
|
|
|
/* Free any existing dynamic storage */
|
|
rsa_free ( context );
|
|
|
|
/* Allocate dynamic storage */
|
|
dynamic = malloc ( sizeof ( *dynamic ) );
|
|
if ( ! dynamic )
|
|
return -ENOMEM;
|
|
|
|
/* Assign dynamic storage */
|
|
context->dynamic = dynamic;
|
|
context->modulus0 = &dynamic->modulus.element[0];
|
|
context->size = size;
|
|
context->max_len = modulus_len;
|
|
context->exponent0 = &dynamic->exponent.element[0];
|
|
context->exponent_size = exponent_size;
|
|
context->input0 = &dynamic->input.element[0];
|
|
context->output0 = &dynamic->output.element[0];
|
|
context->tmp = &dynamic->tmp;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Parse RSA integer
|
|
*
|
|
* @v integer Integer to fill in
|
|
* @v raw ASN.1 cursor
|
|
* @ret rc Return status code
|
|
*/
|
|
static int rsa_parse_integer ( struct asn1_cursor *integer,
|
|
const struct asn1_cursor *raw ) {
|
|
|
|
/* Enter integer */
|
|
memcpy ( integer, raw, sizeof ( *integer ) );
|
|
asn1_enter ( integer, ASN1_INTEGER );
|
|
|
|
/* Skip initial sign byte if applicable */
|
|
if ( ( integer->len > 1 ) &&
|
|
( *( ( uint8_t * ) integer->data ) == 0x00 ) ) {
|
|
integer->data++;
|
|
integer->len--;
|
|
}
|
|
|
|
/* Fail if cursor or integer are invalid */
|
|
if ( ! integer->len )
|
|
return -EINVAL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Parse RSA modulus and exponent
|
|
*
|
|
* @v modulus Modulus to fill in
|
|
* @v exponent Exponent to fill in
|
|
* @v raw ASN.1 cursor
|
|
* @ret rc Return status code
|
|
*/
|
|
static int rsa_parse_mod_exp ( struct asn1_cursor *modulus,
|
|
struct asn1_cursor *exponent,
|
|
const struct asn1_cursor *raw ) {
|
|
struct asn1_bit_string bits;
|
|
struct asn1_cursor cursor;
|
|
int is_private;
|
|
int rc;
|
|
|
|
/* Enter subjectPublicKeyInfo/RSAPrivateKey */
|
|
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
|
asn1_enter ( &cursor, ASN1_SEQUENCE );
|
|
|
|
/* Determine key format */
|
|
if ( asn1_type ( &cursor ) == ASN1_INTEGER ) {
|
|
|
|
/* Private key */
|
|
is_private = 1;
|
|
|
|
/* Skip version */
|
|
asn1_skip_any ( &cursor );
|
|
|
|
} else {
|
|
|
|
/* Public key */
|
|
is_private = 0;
|
|
|
|
/* Skip algorithm */
|
|
asn1_skip ( &cursor, ASN1_SEQUENCE );
|
|
|
|
/* Enter subjectPublicKey */
|
|
if ( ( rc = asn1_integral_bit_string ( &cursor, &bits ) ) != 0 )
|
|
return rc;
|
|
cursor.data = bits.data;
|
|
cursor.len = bits.len;
|
|
|
|
/* Enter RSAPublicKey */
|
|
asn1_enter ( &cursor, ASN1_SEQUENCE );
|
|
}
|
|
|
|
/* Extract modulus */
|
|
if ( ( rc = rsa_parse_integer ( modulus, &cursor ) ) != 0 )
|
|
return rc;
|
|
asn1_skip_any ( &cursor );
|
|
|
|
/* Skip public exponent, if applicable */
|
|
if ( is_private )
|
|
asn1_skip ( &cursor, ASN1_INTEGER );
|
|
|
|
/* Extract publicExponent/privateExponent */
|
|
if ( ( rc = rsa_parse_integer ( exponent, &cursor ) ) != 0 )
|
|
return rc;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Initialise RSA cipher
|
|
*
|
|
* @v ctx RSA context
|
|
* @v key Key
|
|
* @v key_len Length of key
|
|
* @ret rc Return status code
|
|
*/
|
|
static int rsa_init ( void *ctx, const void *key, size_t key_len ) {
|
|
struct rsa_context *context = ctx;
|
|
struct asn1_cursor modulus;
|
|
struct asn1_cursor exponent;
|
|
struct asn1_cursor cursor;
|
|
int rc;
|
|
|
|
/* Initialise context */
|
|
memset ( context, 0, sizeof ( *context ) );
|
|
|
|
/* Initialise cursor */
|
|
cursor.data = key;
|
|
cursor.len = key_len;
|
|
|
|
/* Parse modulus and exponent */
|
|
if ( ( rc = rsa_parse_mod_exp ( &modulus, &exponent, &cursor ) ) != 0 ){
|
|
DBGC ( context, "RSA %p invalid modulus/exponent:\n", context );
|
|
DBGC_HDA ( context, 0, cursor.data, cursor.len );
|
|
goto err_parse;
|
|
}
|
|
|
|
DBGC ( context, "RSA %p modulus:\n", context );
|
|
DBGC_HDA ( context, 0, modulus.data, modulus.len );
|
|
DBGC ( context, "RSA %p exponent:\n", context );
|
|
DBGC_HDA ( context, 0, exponent.data, exponent.len );
|
|
|
|
/* Allocate dynamic storage */
|
|
if ( ( rc = rsa_alloc ( context, modulus.len, exponent.len ) ) != 0 )
|
|
goto err_alloc;
|
|
|
|
/* Construct big integers */
|
|
bigint_init ( ( ( bigint_t ( context->size ) * ) context->modulus0 ),
|
|
modulus.data, modulus.len );
|
|
bigint_init ( ( ( bigint_t ( context->exponent_size ) * )
|
|
context->exponent0 ), exponent.data, exponent.len );
|
|
|
|
return 0;
|
|
|
|
rsa_free ( context );
|
|
err_alloc:
|
|
err_parse:
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* Calculate RSA maximum output length
|
|
*
|
|
* @v ctx RSA context
|
|
* @ret max_len Maximum output length
|
|
*/
|
|
static size_t rsa_max_len ( void *ctx ) {
|
|
struct rsa_context *context = ctx;
|
|
|
|
return context->max_len;
|
|
}
|
|
|
|
/**
|
|
* Perform RSA cipher operation
|
|
*
|
|
* @v context RSA context
|
|
* @v in Input buffer
|
|
* @v out Output buffer
|
|
*/
|
|
static void rsa_cipher ( struct rsa_context *context,
|
|
const void *in, void *out ) {
|
|
bigint_t ( context->size ) *input = ( ( void * ) context->input0 );
|
|
bigint_t ( context->size ) *output = ( ( void * ) context->output0 );
|
|
bigint_t ( context->size ) *modulus = ( ( void * ) context->modulus0 );
|
|
bigint_t ( context->exponent_size ) *exponent =
|
|
( ( void * ) context->exponent0 );
|
|
|
|
/* Initialise big integer */
|
|
bigint_init ( input, in, context->max_len );
|
|
|
|
/* Perform modular exponentiation */
|
|
bigint_mod_exp ( input, modulus, exponent, output, context->tmp );
|
|
|
|
/* Copy out result */
|
|
bigint_done ( output, out, context->max_len );
|
|
}
|
|
|
|
/**
|
|
* Encrypt using RSA
|
|
*
|
|
* @v ctx RSA context
|
|
* @v plaintext Plaintext
|
|
* @v plaintext_len Length of plaintext
|
|
* @v ciphertext Ciphertext
|
|
* @ret ciphertext_len Length of ciphertext, or negative error
|
|
*/
|
|
static int rsa_encrypt ( void *ctx, const void *plaintext,
|
|
size_t plaintext_len, void *ciphertext ) {
|
|
struct rsa_context *context = ctx;
|
|
void *temp;
|
|
uint8_t *encoded;
|
|
size_t max_len = ( context->max_len - 11 );
|
|
size_t random_nz_len = ( max_len - plaintext_len + 8 );
|
|
int rc;
|
|
|
|
/* Sanity check */
|
|
if ( plaintext_len > max_len ) {
|
|
DBGC ( context, "RSA %p plaintext too long (%zd bytes, max "
|
|
"%zd)\n", context, plaintext_len, max_len );
|
|
return -ERANGE;
|
|
}
|
|
DBGC ( context, "RSA %p encrypting:\n", context );
|
|
DBGC_HDA ( context, 0, plaintext, plaintext_len );
|
|
|
|
/* Construct encoded message (using the big integer output
|
|
* buffer as temporary storage)
|
|
*/
|
|
temp = context->output0;
|
|
encoded = temp;
|
|
encoded[0] = 0x00;
|
|
encoded[1] = 0x02;
|
|
if ( ( rc = get_random_nz ( &encoded[2], random_nz_len ) ) != 0 ) {
|
|
DBGC ( context, "RSA %p could not generate random data: %s\n",
|
|
context, strerror ( rc ) );
|
|
return rc;
|
|
}
|
|
encoded[ 2 + random_nz_len ] = 0x00;
|
|
memcpy ( &encoded[ context->max_len - plaintext_len ],
|
|
plaintext, plaintext_len );
|
|
|
|
/* Encipher the encoded message */
|
|
rsa_cipher ( context, encoded, ciphertext );
|
|
DBGC ( context, "RSA %p encrypted:\n", context );
|
|
DBGC_HDA ( context, 0, ciphertext, context->max_len );
|
|
|
|
return context->max_len;
|
|
}
|
|
|
|
/**
|
|
* Decrypt using RSA
|
|
*
|
|
* @v ctx RSA context
|
|
* @v ciphertext Ciphertext
|
|
* @v ciphertext_len Ciphertext length
|
|
* @v plaintext Plaintext
|
|
* @ret plaintext_len Plaintext length, or negative error
|
|
*/
|
|
static int rsa_decrypt ( void *ctx, const void *ciphertext,
|
|
size_t ciphertext_len, void *plaintext ) {
|
|
struct rsa_context *context = ctx;
|
|
void *temp;
|
|
uint8_t *encoded;
|
|
uint8_t *end;
|
|
uint8_t *zero;
|
|
uint8_t *start;
|
|
size_t plaintext_len;
|
|
|
|
/* Sanity check */
|
|
if ( ciphertext_len != context->max_len ) {
|
|
DBGC ( context, "RSA %p ciphertext incorrect length (%zd "
|
|
"bytes, should be %zd)\n",
|
|
context, ciphertext_len, context->max_len );
|
|
return -ERANGE;
|
|
}
|
|
DBGC ( context, "RSA %p decrypting:\n", context );
|
|
DBGC_HDA ( context, 0, ciphertext, ciphertext_len );
|
|
|
|
/* Decipher the message (using the big integer input buffer as
|
|
* temporary storage)
|
|
*/
|
|
temp = context->input0;
|
|
encoded = temp;
|
|
rsa_cipher ( context, ciphertext, encoded );
|
|
|
|
/* Parse the message */
|
|
end = ( encoded + context->max_len );
|
|
if ( ( encoded[0] != 0x00 ) || ( encoded[1] != 0x02 ) )
|
|
goto invalid;
|
|
zero = memchr ( &encoded[2], 0, ( end - &encoded[2] ) );
|
|
if ( ! zero )
|
|
goto invalid;
|
|
start = ( zero + 1 );
|
|
plaintext_len = ( end - start );
|
|
|
|
/* Copy out message */
|
|
memcpy ( plaintext, start, plaintext_len );
|
|
DBGC ( context, "RSA %p decrypted:\n", context );
|
|
DBGC_HDA ( context, 0, plaintext, plaintext_len );
|
|
|
|
return plaintext_len;
|
|
|
|
invalid:
|
|
DBGC ( context, "RSA %p invalid decrypted message:\n", context );
|
|
DBGC_HDA ( context, 0, encoded, context->max_len );
|
|
return -EINVAL;
|
|
}
|
|
|
|
/**
|
|
* Encode RSA digest
|
|
*
|
|
* @v context RSA context
|
|
* @v digest Digest algorithm
|
|
* @v value Digest value
|
|
* @v encoded Encoded digest
|
|
* @ret rc Return status code
|
|
*/
|
|
static int rsa_encode_digest ( struct rsa_context *context,
|
|
struct digest_algorithm *digest,
|
|
const void *value, void *encoded ) {
|
|
struct rsa_digestinfo_prefix *prefix;
|
|
size_t digest_len = digest->digestsize;
|
|
uint8_t *temp = encoded;
|
|
size_t digestinfo_len;
|
|
size_t max_len;
|
|
size_t pad_len;
|
|
|
|
/* Identify prefix */
|
|
prefix = rsa_find_prefix ( digest );
|
|
if ( ! prefix ) {
|
|
DBGC ( context, "RSA %p has no prefix for %s\n",
|
|
context, digest->name );
|
|
return -ENOTSUP;
|
|
}
|
|
digestinfo_len = ( prefix->len + digest_len );
|
|
|
|
/* Sanity check */
|
|
max_len = ( context->max_len - 11 );
|
|
if ( digestinfo_len > max_len ) {
|
|
DBGC ( context, "RSA %p %s digestInfo too long (%zd bytes, max"
|
|
"%zd)\n",
|
|
context, digest->name, digestinfo_len, max_len );
|
|
return -ERANGE;
|
|
}
|
|
DBGC ( context, "RSA %p encoding %s digest:\n",
|
|
context, digest->name );
|
|
DBGC_HDA ( context, 0, value, digest_len );
|
|
|
|
/* Construct encoded message */
|
|
*(temp++) = 0x00;
|
|
*(temp++) = 0x01;
|
|
pad_len = ( max_len - digestinfo_len + 8 );
|
|
memset ( temp, 0xff, pad_len );
|
|
temp += pad_len;
|
|
*(temp++) = 0x00;
|
|
memcpy ( temp, prefix->data, prefix->len );
|
|
temp += prefix->len;
|
|
memcpy ( temp, value, digest_len );
|
|
temp += digest_len;
|
|
assert ( temp == ( encoded + context->max_len ) );
|
|
DBGC ( context, "RSA %p encoded %s digest:\n", context, digest->name );
|
|
DBGC_HDA ( context, 0, encoded, context->max_len );
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Sign digest value using RSA
|
|
*
|
|
* @v ctx RSA context
|
|
* @v digest Digest algorithm
|
|
* @v value Digest value
|
|
* @v signature Signature
|
|
* @ret signature_len Signature length, or negative error
|
|
*/
|
|
static int rsa_sign ( void *ctx, struct digest_algorithm *digest,
|
|
const void *value, void *signature ) {
|
|
struct rsa_context *context = ctx;
|
|
void *temp;
|
|
int rc;
|
|
|
|
DBGC ( context, "RSA %p signing %s digest:\n", context, digest->name );
|
|
DBGC_HDA ( context, 0, value, digest->digestsize );
|
|
|
|
/* Encode digest (using the big integer output buffer as
|
|
* temporary storage)
|
|
*/
|
|
temp = context->output0;
|
|
if ( ( rc = rsa_encode_digest ( context, digest, value, temp ) ) != 0 )
|
|
return rc;
|
|
|
|
/* Encipher the encoded digest */
|
|
rsa_cipher ( context, temp, signature );
|
|
DBGC ( context, "RSA %p signed %s digest:\n", context, digest->name );
|
|
DBGC_HDA ( context, 0, signature, context->max_len );
|
|
|
|
return context->max_len;
|
|
}
|
|
|
|
/**
|
|
* Verify signed digest value using RSA
|
|
*
|
|
* @v ctx RSA context
|
|
* @v digest Digest algorithm
|
|
* @v value Digest value
|
|
* @v signature Signature
|
|
* @v signature_len Signature length
|
|
* @ret rc Return status code
|
|
*/
|
|
static int rsa_verify ( void *ctx, struct digest_algorithm *digest,
|
|
const void *value, const void *signature,
|
|
size_t signature_len ) {
|
|
struct rsa_context *context = ctx;
|
|
void *temp;
|
|
void *expected;
|
|
void *actual;
|
|
int rc;
|
|
|
|
/* Sanity check */
|
|
if ( signature_len != context->max_len ) {
|
|
DBGC ( context, "RSA %p signature incorrect length (%zd "
|
|
"bytes, should be %zd)\n",
|
|
context, signature_len, context->max_len );
|
|
return -ERANGE;
|
|
}
|
|
DBGC ( context, "RSA %p verifying %s digest:\n",
|
|
context, digest->name );
|
|
DBGC_HDA ( context, 0, value, digest->digestsize );
|
|
DBGC_HDA ( context, 0, signature, signature_len );
|
|
|
|
/* Decipher the signature (using the big integer input buffer
|
|
* as temporary storage)
|
|
*/
|
|
temp = context->input0;
|
|
expected = temp;
|
|
rsa_cipher ( context, signature, expected );
|
|
DBGC ( context, "RSA %p deciphered signature:\n", context );
|
|
DBGC_HDA ( context, 0, expected, context->max_len );
|
|
|
|
/* Encode digest (using the big integer output buffer as
|
|
* temporary storage)
|
|
*/
|
|
temp = context->output0;
|
|
actual = temp;
|
|
if ( ( rc = rsa_encode_digest ( context, digest, value, actual ) ) !=0 )
|
|
return rc;
|
|
|
|
/* Verify the signature */
|
|
if ( memcmp ( actual, expected, context->max_len ) != 0 ) {
|
|
DBGC ( context, "RSA %p signature verification failed\n",
|
|
context );
|
|
return -EACCES_VERIFY;
|
|
}
|
|
|
|
DBGC ( context, "RSA %p signature verified successfully\n", context );
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Finalise RSA cipher
|
|
*
|
|
* @v ctx RSA context
|
|
*/
|
|
static void rsa_final ( void *ctx ) {
|
|
struct rsa_context *context = ctx;
|
|
|
|
rsa_free ( context );
|
|
}
|
|
|
|
/**
|
|
* Check for matching RSA public/private key pair
|
|
*
|
|
* @v private_key Private key
|
|
* @v private_key_len Private key length
|
|
* @v public_key Public key
|
|
* @v public_key_len Public key length
|
|
* @ret rc Return status code
|
|
*/
|
|
static int rsa_match ( const void *private_key, size_t private_key_len,
|
|
const void *public_key, size_t public_key_len ) {
|
|
struct asn1_cursor private_modulus;
|
|
struct asn1_cursor private_exponent;
|
|
struct asn1_cursor private_cursor;
|
|
struct asn1_cursor public_modulus;
|
|
struct asn1_cursor public_exponent;
|
|
struct asn1_cursor public_cursor;
|
|
int rc;
|
|
|
|
/* Initialise cursors */
|
|
private_cursor.data = private_key;
|
|
private_cursor.len = private_key_len;
|
|
public_cursor.data = public_key;
|
|
public_cursor.len = public_key_len;
|
|
|
|
/* Parse moduli and exponents */
|
|
if ( ( rc = rsa_parse_mod_exp ( &private_modulus, &private_exponent,
|
|
&private_cursor ) ) != 0 )
|
|
return rc;
|
|
if ( ( rc = rsa_parse_mod_exp ( &public_modulus, &public_exponent,
|
|
&public_cursor ) ) != 0 )
|
|
return rc;
|
|
|
|
/* Compare moduli */
|
|
if ( asn1_compare ( &private_modulus, &public_modulus ) != 0 )
|
|
return -ENOTTY;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/** RSA public-key algorithm */
|
|
struct pubkey_algorithm rsa_algorithm = {
|
|
.name = "rsa",
|
|
.ctxsize = RSA_CTX_SIZE,
|
|
.init = rsa_init,
|
|
.max_len = rsa_max_len,
|
|
.encrypt = rsa_encrypt,
|
|
.decrypt = rsa_decrypt,
|
|
.sign = rsa_sign,
|
|
.verify = rsa_verify,
|
|
.final = rsa_final,
|
|
.match = rsa_match,
|
|
};
|
|
|
|
/* Drag in objects via rsa_algorithm */
|
|
REQUIRING_SYMBOL ( rsa_algorithm );
|
|
|
|
/* Drag in crypto configuration */
|
|
REQUIRE_OBJECT ( config_crypto );
|