From 299dedcff06770282c5aae5ce9558fe016750e5d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 13 Mar 2012 16:47:29 +0000 Subject: [PATCH] [crypto] Add native RSA algorithm Add an implementation of RSA that uses the iPXE big-integer support. Signed-off-by: Michael Brown --- src/crypto/axtls/{rsa.c => axtls_rsa.c} | 0 src/crypto/rsa.c | 600 ++++++++++++++++++++++++ src/include/ipxe/errfile.h | 1 + src/include/ipxe/rsa.h | 130 ++++- 4 files changed, 728 insertions(+), 3 deletions(-) rename src/crypto/axtls/{rsa.c => axtls_rsa.c} (100%) create mode 100644 src/crypto/rsa.c diff --git a/src/crypto/axtls/rsa.c b/src/crypto/axtls/axtls_rsa.c similarity index 100% rename from src/crypto/axtls/rsa.c rename to src/crypto/axtls/axtls_rsa.c diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c new file mode 100644 index 00000000..4aba5cc3 --- /dev/null +++ b/src/crypto/rsa.c @@ -0,0 +1,600 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * RSA public-key cryptography + * + * RSA is documented in RFC 3447. + */ + +/** An RSA digestInfo prefix */ +struct rsa_digestinfo_prefix { + /** Digest algorithm */ + struct digest_algorithm *digest; + /** Prefix */ + const void *data; + /** Length of prefix */ + size_t len; +}; + +/** "id-md5" object identifier */ +static const uint8_t rsa_md5_prefix[] = + { RSA_DIGESTINFO_PREFIX ( MD5_DIGEST_SIZE, ASN1_OID_MD5 ) }; + +/** "id-sha1" object identifier */ +static const uint8_t rsa_sha1_prefix[] = + { RSA_DIGESTINFO_PREFIX ( SHA1_DIGEST_SIZE, ASN1_OID_SHA1 ) }; + +/** "id-sha256" object identifier */ +static const uint8_t rsa_sha256_prefix[] = + { RSA_DIGESTINFO_PREFIX ( SHA256_DIGEST_SIZE, ASN1_OID_SHA256 ) }; + +/** RSA digestInfo prefixes */ +static struct rsa_digestinfo_prefix rsa_digestinfo_prefixes[] = { + { + .digest = &md5_algorithm, + .data = rsa_md5_prefix, + .len = sizeof ( rsa_md5_prefix ), + }, + { + .digest = &sha1_algorithm, + .data = rsa_sha1_prefix, + .len = sizeof ( rsa_sha1_prefix ), + }, + { + .digest = &sha256_algorithm, + .data = rsa_sha256_prefix, + .len = sizeof ( rsa_sha256_prefix ), + }, +}; + +/** + * 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; + unsigned int i; + + for ( i = 0 ; i < ( sizeof ( rsa_digestinfo_prefixes ) / + sizeof ( rsa_digestinfo_prefixes[0] ) ) ; i++ ) { + prefix = &rsa_digestinfo_prefixes[i]; + 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 ); + struct { + bigint_t ( size ) modulus; + bigint_t ( exponent_size ) exponent; + bigint_t ( size ) input; + bigint_t ( size ) output; + } __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]; + + return 0; +} + +/** + * Parse RSA integer + * + * @v context RSA context + * @v integer Integer to fill in + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int rsa_parse_integer ( struct rsa_context *context, + 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 ) { + DBGC ( context, "RSA %p invalid integer:\n", context ); + DBGC_HDA ( context, 0, raw->data, raw->len ); + return -EINVAL; + } + + 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; + const struct asn1_bit_string *bit_string; + struct asn1_cursor modulus; + struct asn1_cursor exponent; + struct asn1_cursor cursor; + int is_private; + int rc; + + /* Initialise context */ + memset ( context, 0, sizeof ( *context ) ); + + /* Initialise cursor */ + cursor.data = key; + cursor.len = key_len; + + /* Enter subjectPublicKeyInfo/RSAPrivateKey */ + 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 */ + asn1_enter ( &cursor, ASN1_BIT_STRING ); + + /* Check and skip unused-bits byte of bit string */ + bit_string = cursor.data; + if ( cursor.len < 1 ) { + rc = -EINVAL; + goto err_parse; + } + cursor.data++; + cursor.len--; + + /* Enter RSAPublicKey */ + asn1_enter ( &cursor, ASN1_SEQUENCE ); + } + + /* Extract modulus */ + if ( ( rc = rsa_parse_integer ( context, &modulus, &cursor ) ) != 0 ) + goto err_parse; + 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 ( context, &exponent, &cursor ) ) != 0 ) + 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 ); + + /* 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; + } + + 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 ); +} + +/** RSA public-key algorithm */ +struct pubkey_algorithm rsa_algorithm = { + .name = "rsa", + .ctxsize = sizeof ( struct rsa_context ), + .init = rsa_init, + .max_len = rsa_max_len, + .encrypt = rsa_encrypt, + .decrypt = rsa_decrypt, + .sign = rsa_sign, + .verify = rsa_verify, + .final = rsa_final, +}; diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 35a0bb7f..050bf3fe 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -246,6 +246,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_hmac_drbg ( ERRFILE_OTHER | 0x00240000 ) #define ERRFILE_drbg ( ERRFILE_OTHER | 0x00250000 ) #define ERRFILE_entropy ( ERRFILE_OTHER | 0x00260000 ) +#define ERRFILE_rsa ( ERRFILE_OTHER | 0x00270000 ) /** @} */ diff --git a/src/include/ipxe/rsa.h b/src/include/ipxe/rsa.h index a080f9f0..e70362ce 100644 --- a/src/include/ipxe/rsa.h +++ b/src/include/ipxe/rsa.h @@ -1,12 +1,136 @@ #ifndef _IPXE_RSA_H #define _IPXE_RSA_H +/** @file + * + * RSA public-key cryptography + */ + FILE_LICENCE ( GPL2_OR_LATER ); -struct pubkey_algorithm; +#include +#include +#include + +/** ASN.1 OID for iso(1) member-body(2) us(840) */ +#define ASN1_OID_ISO_US ASN1_OID_ISO_MEMBERBODY, ASN1_OID_DOUBLE ( 840 ) + +/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) */ +#define ASN1_OID_RSADSI ASN1_OID_ISO_US, ASN1_OID_TRIPLE ( 113549 ) + +/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) */ +#define ASN1_OID_PKCS ASN1_OID_RSADSI, ASN1_OID_SINGLE ( 1 ) + +/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) + * digestAlgorithm(2) + */ +#define ASN1_OID_DIGESTALGORITHM ASN1_OID_RSADSI, ASN1_OID_SINGLE ( 2 ) + +/** ASN.1 OID for iso(1) identified-organization(3) oiw(14) */ +#define ASN1_OID_OIW ASN1_OID_IDENTIFIED_ORGANIZATION, ASN1_OID_SINGLE ( 14 ) + +/** ASN.1 OID for iso(1) identified-organization(3) oiw(14) secsig(3) */ +#define ASN1_OID_SECSIG ASN1_OID_OIW, ASN1_OID_SINGLE ( 3 ) + +/** ASN1. OID for iso(1) identified-organization(3) oiw(14) secsig(3) + * algorithms(2) + */ +#define ASN1_OID_SECSIG_ALGORITHMS ASN1_OID_SECSIG, ASN1_OID_SINGLE ( 2 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) */ +#define ASN1_OID_COUNTRY_US ASN1_OID_COUNTRY, ASN1_OID_DOUBLE ( 840 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) organization(1) */ +#define ASN1_OID_US_ORGANIZATION ASN1_OID_COUNTRY_US, ASN1_OID_SINGLE ( 1 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) + */ +#define ASN1_OID_US_GOV ASN1_OID_US_ORGANIZATION, ASN1_OID_SINGLE ( 101 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) csor(3) + */ +#define ASN1_OID_CSOR ASN1_OID_US_GOV, ASN1_OID_SINGLE ( 3 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) csor(3) nistalgorithm(4) + */ +#define ASN1_OID_NISTALGORITHM ASN1_OID_CSOR, ASN1_OID_SINGLE ( 4 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) + */ +#define ASN1_OID_HASHALGS ASN1_OID_NISTALGORITHM, ASN1_OID_SINGLE ( 2 ) + +/** ASN.1 OID for pkcs-1 */ +#define ASN1_OID_PKCS_1 ASN1_OID_PKCS, ASN1_OID_SINGLE ( 1 ) + +/** ASN.1 OID for rsaEncryption */ +#define ASN1_OID_RSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 1 ) + +/** ASN.1 OID for md5WithRSAEncryption */ +#define ASN1_OID_MD5WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 4 ) + +/** ASN.1 OID for sha1WithRSAEncryption */ +#define ASN1_OID_SHA1WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 5 ) + +/** ASN.1 OID for sha256WithRSAEncryption */ +#define ASN1_OID_SHA256WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 11 ) + +/** ASN.1 OID for id-md5 */ +#define ASN1_OID_MD5 ASN1_OID_DIGESTALGORITHM, ASN1_OID_SINGLE ( 5 ) + +/** ASN.1 OID for id-sha1 */ +#define ASN1_OID_SHA1 ASN1_OID_SECSIG_ALGORITHMS, ASN1_OID_SINGLE ( 26 ) + +/** ASN.1 OID for id-sha256 */ +#define ASN1_OID_SHA256 ASN1_OID_HASHALGS, ASN1_OID_SINGLE ( 1 ) + +/** RSA digestAlgorithm sequence contents */ +#define RSA_DIGESTALGORITHM_CONTENTS( ... ) \ + ASN1_OID, VA_ARG_COUNT ( __VA_ARGS__ ), __VA_ARGS__, \ + ASN1_NULL, 0x00 + +/** RSA digestAlgorithm sequence */ +#define RSA_DIGESTALGORITHM( ... ) \ + ASN1_SEQUENCE, \ + VA_ARG_COUNT ( RSA_DIGESTALGORITHM_CONTENTS ( __VA_ARGS__ ) ), \ + RSA_DIGESTALGORITHM_CONTENTS ( __VA_ARGS__ ) + +/** RSA digest prefix */ +#define RSA_DIGEST_PREFIX( digest_size ) \ + ASN1_OCTET_STRING, digest_size + +/** RSA digestInfo prefix */ +#define RSA_DIGESTINFO_PREFIX( digest_size, ... ) \ + ASN1_SEQUENCE, \ + ( VA_ARG_COUNT ( RSA_DIGESTALGORITHM ( __VA_ARGS__ ) ) + \ + VA_ARG_COUNT ( RSA_DIGEST_PREFIX ( digest_size ) ) + \ + digest_size ), \ + RSA_DIGESTALGORITHM ( __VA_ARGS__ ), \ + RSA_DIGEST_PREFIX ( digest_size ) + +/** 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; +}; extern struct pubkey_algorithm rsa_algorithm; -#include "crypto/axtls/crypto.h" - #endif /* _IPXE_RSA_H */