Files
ipxe/src/crypto/rsa.c
T
Michael Brown 846686325c [crypto] Use private data field for public-key algorithms
Following the example of commit 25072c1 ("[crypto] Use private data
field for key exchange algorithms"), extend the definition of a
public-key algorithm to include an opaque private data field, and use
this to eliminate the wrapper functions for PKCS#1 and RSA-PSS.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-06-19 14:54:03 +01:00

861 lines
22 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 );
FILE_SECBOOT ( PERMITTED );
#include <byteswap.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <strings.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 and updated in RFC 8017.
*/
/* 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" )
/** An RSA context */
struct rsa_context {
/** Allocated memory */
void *dynamic;
/** Modulus */
bigint_element_t *modulus0;
/** Modulus size */
unsigned int size;
/** Modulus length */
size_t max_len;
/** Exponent */
bigint_element_t *exponent0;
/** Exponent size */
unsigned int exponent_size;
/** Input buffer */
bigint_element_t *input0;
/** Output buffer */
bigint_element_t *output0;
/** Temporary working space for modular exponentiation */
void *tmp;
/** Modulus MSB mask */
uint8_t mask;
};
/**
* Encode digest
*
* @v context RSA context
* @v digest Digest algorithm
* @v value Digest value
* @v reference Reference encoded digest (or NULL)
* @v encoded Encoded digest
* @ret rc Return status code
*/
typedef int ( rsa_encode_t ) ( struct rsa_context *context,
struct digest_algorithm *digest,
const void *value, const void *reference,
void *encoded );
/** Generate random data */
int ( * rsa_get_random ) ( void *data, size_t len ) = get_random_nz;
/**
* 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 inline void rsa_free ( struct rsa_context *context ) {
free ( context->dynamic );
}
/**
* 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;
size_t tmp_len = bigint_mod_exp_tmp_len ( modulus );
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;
/* 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 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_cursor cursor;
int is_private;
int rc;
/* Enter subjectPublicKeyInfo/privateKeyInfo/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 );
/* Enter privateKey, if present */
if ( asn1_check_algorithm ( &cursor, &rsa_encryption_algorithm,
NULL ) == 0 ) {
/* Skip privateKeyAlgorithm */
asn1_skip_any ( &cursor );
/* Enter privateKey */
asn1_enter ( &cursor, ASN1_OCTET_STRING );
/* Enter RSAPrivateKey */
asn1_enter ( &cursor, ASN1_SEQUENCE );
/* Skip version */
asn1_skip ( &cursor, ASN1_INTEGER );
}
} else {
/* Public key */
is_private = 0;
/* Skip algorithm */
asn1_skip ( &cursor, ASN1_SEQUENCE );
/* Enter subjectPublicKey */
asn1_enter_bits ( &cursor, NULL );
/* Enter RSAPublicKey */
asn1_enter ( &cursor, ASN1_SEQUENCE );
}
/* Extract modulus */
memcpy ( modulus, &cursor, sizeof ( *modulus ) );
if ( ( rc = asn1_enter_unsigned ( modulus ) ) != 0 )
return rc;
asn1_skip_any ( &cursor );
/* Skip public exponent, if applicable */
if ( is_private )
asn1_skip ( &cursor, ASN1_INTEGER );
/* Extract publicExponent/privateExponent */
memcpy ( exponent, &cursor, sizeof ( *exponent ) );
if ( ( rc = asn1_enter_unsigned ( exponent ) ) != 0 )
return rc;
return 0;
}
/**
* Initialise RSA cipher
*
* @v context RSA context
* @v key Key
* @ret rc Return status code
*/
static int rsa_init ( struct rsa_context *context,
const struct asn1_cursor *key ) {
struct asn1_cursor modulus;
struct asn1_cursor exponent;
uint8_t msb;
int rc;
/* Initialise context */
memset ( context, 0, sizeof ( *context ) );
/* Parse modulus and exponent */
if ( ( rc = rsa_parse_mod_exp ( &modulus, &exponent, key ) ) != 0 ){
DBGC ( context, "RSA %p invalid modulus/exponent:\n", context );
DBGC_HDA ( context, 0, key->data, key->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 );
/* Construct MSB mask */
msb = *( ( const uint8_t * ) modulus.data );
if ( ! msb ) {
DBGC ( context, "RSA %p invalid modulus MSB\n", context );
rc = -EINVAL;
goto err_msb;
}
context->mask = ( ( 1 << ( fls ( msb ) - 1 ) ) - 1 );
/* 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_msb:
err_parse:
return rc;
}
/**
* 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 PKCS#1
*
* @v pubkey Public-key algorithm
* @v key Key
* @v plaintext Plaintext
* @v ciphertext Ciphertext
* @ret ciphertext_len Length of ciphertext, or negative error
*/
static int rsa_pkcs1_encrypt ( struct pubkey_algorithm *pubkey __unused,
const struct asn1_cursor *key,
const struct asn1_cursor *plaintext,
struct asn1_builder *ciphertext ) {
struct rsa_context context;
void *temp;
uint8_t *encoded;
size_t max_len;
size_t random_nz_len;
int rc;
DBGC ( &context, "RSA %p encrypting:\n", &context );
DBGC_HDA ( &context, 0, plaintext->data, plaintext->len );
/* Initialise context */
if ( ( rc = rsa_init ( &context, key ) ) != 0 )
goto err_init;
/* Calculate lengths */
max_len = ( context.max_len - 11 );
random_nz_len = ( max_len - plaintext->len + 8 );
/* Sanity check */
if ( plaintext->len > max_len ) {
DBGC ( &context, "RSA %p plaintext too long (%zd bytes, max "
"%zd)\n", &context, plaintext->len, max_len );
rc = -ERANGE;
goto err_sanity;
}
/* 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 = rsa_get_random ( &encoded[2], random_nz_len ) ) != 0 ) {
DBGC ( &context, "RSA %p could not generate random data: %s\n",
&context, strerror ( rc ) );
goto err_random;
}
encoded[ 2 + random_nz_len ] = 0x00;
memcpy ( &encoded[ context.max_len - plaintext->len ],
plaintext->data, plaintext->len );
DBGC ( &context, "RSA %p encoded:\n", &context );
DBGC_HDA ( &context, 0, encoded, context.max_len );
/* Create space for ciphertext */
if ( ( rc = asn1_grow ( ciphertext, context.max_len ) ) != 0 )
goto err_grow;
/* Encipher the encoded message */
rsa_cipher ( &context, encoded, ciphertext->data );
DBGC ( &context, "RSA %p encrypted:\n", &context );
DBGC_HDA ( &context, 0, ciphertext->data, context.max_len );
/* Free context */
rsa_free ( &context );
return 0;
err_grow:
err_random:
err_sanity:
rsa_free ( &context );
err_init:
return rc;
}
/**
* Decrypt using RSA PKCS#1
*
* @v pubkey Public-key algorithm
* @v key Key
* @v ciphertext Ciphertext
* @v plaintext Plaintext
* @ret rc Return status code
*/
static int rsa_pkcs1_decrypt ( struct pubkey_algorithm *pubkey __unused,
const struct asn1_cursor *key,
const struct asn1_cursor *ciphertext,
struct asn1_builder *plaintext ) {
struct rsa_context context;
void *temp;
uint8_t *encoded;
uint8_t *end;
uint8_t *zero;
uint8_t *start;
size_t len;
int rc;
DBGC ( &context, "RSA %p decrypting:\n", &context );
DBGC_HDA ( &context, 0, ciphertext->data, ciphertext->len );
/* Initialise context */
if ( ( rc = rsa_init ( &context, key ) ) != 0 )
goto err_init;
/* 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 );
rc = -ERANGE;
goto err_sanity;
}
/* Decipher the message (using the big integer input buffer as
* temporary storage)
*/
temp = context.input0;
encoded = temp;
rsa_cipher ( &context, ciphertext->data, encoded );
DBGC ( &context, "RSA %p encoded:\n", &context );
DBGC_HDA ( &context, 0, encoded, context.max_len );
/* Parse the message */
end = ( encoded + context.max_len );
if ( ( encoded[0] != 0x00 ) || ( encoded[1] != 0x02 ) ) {
rc = -EINVAL;
goto err_invalid;
}
zero = memchr ( &encoded[2], 0, ( end - &encoded[2] ) );
if ( ! zero ) {
DBGC ( &context, "RSA %p invalid decrypted message:\n",
&context );
DBGC_HDA ( &context, 0, encoded, context.max_len );
rc = -EINVAL;
goto err_invalid;
}
start = ( zero + 1 );
len = ( end - start );
/* Create space for plaintext */
if ( ( rc = asn1_grow ( plaintext, len ) ) != 0 )
goto err_grow;
/* Copy out message */
memcpy ( plaintext->data, start, len );
DBGC ( &context, "RSA %p decrypted:\n", &context );
DBGC_HDA ( &context, 0, plaintext->data, len );
/* Free context */
rsa_free ( &context );
return 0;
err_grow:
err_invalid:
err_sanity:
rsa_free ( &context );
err_init:
return rc;
}
/**
* Encode digest using RSA PKCS#1
*
* @v context RSA context
* @v digest Digest algorithm
* @v value Digest value
* @v reference Reference encoded digest (or NULL)
* @v encoded Encoded digest
* @ret rc Return status code
*/
static int rsa_pkcs1_encode ( struct rsa_context *context,
struct digest_algorithm *digest,
const void *value,
const void *reference __unused,
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 using PKCS#1:\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 using PKCS#1:\n",
context, digest->name );
DBGC_HDA ( context, 0, encoded, context->max_len );
return 0;
}
/**
* Apply RSA PSS mask generation function
*
* @v digest Digest algorithm
* @v ctx Digest context buffer
* @v out Digest output buffer
* @v seed Mask seed
* @v xor XOR buffer
* @v len Length of XOR buffer
*/
static void rsa_xor_mask ( struct digest_algorithm *digest, void *ctx,
void *out, const void *seed, void *xor,
size_t len ) {
size_t digest_len = digest->digestsize;
const uint8_t *out_byte = out;
uint8_t *xor_byte = xor;
uint32_t counter = 0;
unsigned int i;
while ( len ) {
/* Generate output */
digest_init ( digest, ctx );
digest_update ( digest, ctx, seed, digest_len );
digest_update ( digest, ctx, &counter, sizeof ( counter ) );
digest_final ( digest, ctx, out );
/* XOR output into buffer */
for ( i = 0 ; len && ( i < digest_len ) ; i++, len-- )
*(xor_byte++) ^= out_byte[i];
/* Increment counter */
counter = htonl ( ntohl ( counter ) + 1 );
}
}
/**
* Encode digest using RSA PSS
*
* @v context RSA context
* @v digest Digest algorithm
* @v value Digest value
* @v reference Reference encoded digest (or NULL)
* @v encoded Encoded digest
* @ret rc Return status code
*/
static int rsa_pss_encode ( struct rsa_context *context,
struct digest_algorithm *digest,
const void *value, const void *reference,
void *encoded ) {
static uint8_t zero[8];
uint8_t ctx[ digest->ctxsize ];
uint8_t out[ digest->digestsize ];
size_t digest_len = digest->digestsize;
size_t mask_len;
size_t pad_len;
size_t min_len;
void *hash;
void *salt;
uint8_t *msb;
uint8_t *head;
uint8_t *tail;
int rc;
/* Sanity check */
min_len = ( sizeof ( *head ) + digest_len /* salt */ +
digest_len /* hash */ + sizeof ( *tail ) );
if ( context->max_len < min_len ) {
DBGC ( context, "RSA %p %s formatted digest value too long "
"(%zd bytes, max %zd)\n", context, digest->name,
min_len, context->max_len );
return -ERANGE;
}
DBGC ( context, "RSA %p encoding %s digest using PSS:\n",
context, digest->name );
DBGC_HDA ( context, 0, value, digest_len );
/* Split message into component parts */
pad_len = ( context->max_len - min_len );
msb = encoded;
head = ( msb + pad_len );
salt = ( head + sizeof ( *head ) );
hash = ( salt + digest_len );
tail = ( hash + digest_len );
mask_len = ( pad_len + sizeof ( *head ) + digest_len /* salt */ );
assert ( tail == ( encoded + context->max_len - 1 ) );
/* Generate or construct salt as applicable */
if ( reference ) {
memcpy ( encoded, reference, context->max_len );
rsa_xor_mask ( digest, ctx, out, hash, encoded, mask_len );
} else {
if ( ( rc = rsa_get_random ( salt, digest_len ) ) != 0 ) {
DBGC ( context, "RSA %p could not generate random "
"salt: %s\n", context, strerror ( rc ) );
return rc;
}
}
DBGC ( context, "RSA %p salt:\n", context );
DBGC_HDA ( context, 0, salt, digest_len );
/* Construct intermediate digest */
digest_init ( digest, ctx );
digest_update ( digest, ctx, zero, sizeof ( zero ) );
digest_update ( digest, ctx, value, digest_len );
digest_update ( digest, ctx, salt, digest_len );
digest_final ( digest, ctx, hash );
/* Construct message */
memset ( encoded, 0, pad_len );
*head = 0x01;
rsa_xor_mask ( digest, ctx, out, hash, encoded, mask_len );
*msb &= context->mask;
*tail = 0xbc;
DBGC ( context, "RSA %p encoded %s digest using PSS:\n",
context, digest->name );
DBGC_HDA ( context, 0, encoded, context->max_len );
return 0;
}
/**
* Sign digest value using RSA
*
* @v pubkey Public-key algorithm
* @v key Key
* @v digest Digest algorithm
* @v value Digest value
* @v signature Signature
* @ret rc Return status code
*/
static int rsa_sign ( struct pubkey_algorithm *pubkey,
const struct asn1_cursor *key,
struct digest_algorithm *digest, const void *value,
struct asn1_builder *signature ) {
rsa_encode_t *encode = pubkey->priv;
struct rsa_context context;
int rc;
DBGC ( &context, "RSA %p signing %s digest:\n",
&context, digest->name );
DBGC_HDA ( &context, 0, value, digest->digestsize );
/* Initialise context */
if ( ( rc = rsa_init ( &context, key ) ) != 0 )
goto err_init;
/* Create space for encoded digest and signature */
if ( ( rc = asn1_grow ( signature, context.max_len ) ) != 0 )
goto err_grow;
/* Encode digest */
if ( ( rc = encode ( &context, digest, value, NULL,
signature->data ) ) != 0 )
goto err_encode;
/* Encipher the encoded digest */
rsa_cipher ( &context, signature->data, signature->data );
DBGC ( &context, "RSA %p signed %s digest:\n", &context, digest->name );
DBGC_HDA ( &context, 0, signature->data, signature->len );
/* Free context */
rsa_free ( &context );
return 0;
err_encode:
err_grow:
rsa_free ( &context );
err_init:
return rc;
}
/**
* Verify signed digest value using RSA
*
* @v pubkey Public-key algorithm
* @v key Key
* @v digest Digest algorithm
* @v value Digest value
* @v signature Signature
* @ret rc Return status code
*/
static int rsa_verify ( struct pubkey_algorithm *pubkey,
const struct asn1_cursor *key,
struct digest_algorithm *digest, const void *value,
const struct asn1_cursor *signature ) {
rsa_encode_t *encode = pubkey->priv;
struct rsa_context context;
void *temp;
void *expected;
void *actual;
int rc;
DBGC ( &context, "RSA %p verifying %s digest:\n",
&context, digest->name );
DBGC_HDA ( &context, 0, value, digest->digestsize );
DBGC_HDA ( &context, 0, signature->data, signature->len );
/* Initialise context */
if ( ( rc = rsa_init ( &context, key ) ) != 0 )
goto err_init;
/* 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 );
rc = -ERANGE;
goto err_sanity;
}
/* Decipher the signature (using the big integer input buffer
* as temporary storage)
*/
temp = context.input0;
expected = temp;
rsa_cipher ( &context, signature->data, 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 = encode ( &context, digest, value, expected,
actual ) ) != 0 )
goto err_encode;
/* Verify the signature */
if ( memcmp ( actual, expected, context.max_len ) != 0 ) {
DBGC ( &context, "RSA %p signature verification failed\n",
&context );
rc = -EACCES_VERIFY;
goto err_verify;
}
/* Free context */
rsa_free ( &context );
DBGC ( &context, "RSA %p signature verified successfully\n", &context );
return 0;
err_verify:
err_encode:
err_sanity:
rsa_free ( &context );
err_init:
return rc;
}
/**
* Check for matching RSA public/private key pair
*
* @v pubkey Public-key algorithm
* @v private_key Private key
* @v public_key Public key
* @ret rc Return status code
*/
static int rsa_match ( struct pubkey_algorithm *pubkey __unused,
const struct asn1_cursor *private_key,
const struct asn1_cursor *public_key ) {
struct asn1_cursor private_modulus;
struct asn1_cursor private_exponent;
struct asn1_cursor public_modulus;
struct asn1_cursor public_exponent;
int rc;
/* Parse moduli and exponents */
if ( ( rc = rsa_parse_mod_exp ( &private_modulus, &private_exponent,
private_key ) ) != 0 )
return rc;
if ( ( rc = rsa_parse_mod_exp ( &public_modulus, &public_exponent,
public_key ) ) != 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",
.encrypt = rsa_pkcs1_encrypt,
.decrypt = rsa_pkcs1_decrypt,
.sign = rsa_sign,
.verify = rsa_verify,
.match = rsa_match,
.priv = rsa_pkcs1_encode,
};
/** RSA-PSS public-key algorithm */
struct pubkey_algorithm rsa_pss_algorithm = {
.name = "rsa_pss",
.encrypt = pubkey_null_encrypt,
.decrypt = pubkey_null_decrypt,
.sign = rsa_sign,
.verify = rsa_verify,
.match = rsa_match,
.priv = rsa_pss_encode,
};
/* Drag in objects via rsa_algorithm */
REQUIRING_SYMBOL ( rsa_algorithm );
/* Drag in crypto configuration */
REQUIRE_OBJECT ( config_crypto );