]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[crypto] Add native RSA algorithm
authorMichael Brown <mcb30@ipxe.org>
Tue, 13 Mar 2012 16:47:29 +0000 (16:47 +0000)
committerMichael Brown <mcb30@ipxe.org>
Sun, 18 Mar 2012 13:36:07 +0000 (13:36 +0000)
Add an implementation of RSA that uses the iPXE big-integer support.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/crypto/axtls/axtls_rsa.c [moved from src/crypto/axtls/rsa.c with 100% similarity]
src/crypto/rsa.c [new file with mode: 0644]
src/include/ipxe/errfile.h
src/include/ipxe/rsa.h

diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c
new file mode 100644 (file)
index 0000000..4aba5cc
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#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/md5.h>
+#include <ipxe/sha1.h>
+#include <ipxe/sha256.h>
+#include <ipxe/rsa.h>
+
+/** @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,
+};
index 35a0bb7f01b16e994674bbb2fc517daad05d3b33..050bf3fecaf1565dbf385111dd450a2cd10eb75f 100644 (file)
@@ -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 )
 
 /** @} */
 
index a080f9f08afe4bcb1537b6789f2fa917914c705c..e70362ce7cfa6090534fcda227406d4a050feea1 100644 (file)
 #ifndef _IPXE_RSA_H
 #define _IPXE_RSA_H
 
+/** @file
+ *
+ * RSA public-key cryptography
+ */
+
 FILE_LICENCE ( GPL2_OR_LATER );
 
-struct pubkey_algorithm;
+#include <ipxe/crypto.h>
+#include <ipxe/bigint.h>
+#include <ipxe/asn1.h>
 
-extern struct pubkey_algorithm rsa_algorithm;
+/** 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 )
 
-#include "crypto/axtls/crypto.h"
+/** 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;
 
 #endif /* _IPXE_RSA_H */