summaryrefslogtreecommitdiff
path: root/gpxe/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/crypto')
-rw-r--r--gpxe/src/crypto/asn1.c159
-rw-r--r--gpxe/src/crypto/axtls/aes.c478
-rw-r--r--gpxe/src/crypto/axtls/axtls_asn1.c867
-rw-r--r--gpxe/src/crypto/axtls/bigint.c1496
-rw-r--r--gpxe/src/crypto/axtls/bigint.h93
-rw-r--r--gpxe/src/crypto/axtls/bigint_impl.h105
-rw-r--r--gpxe/src/crypto/axtls/crypto.h298
-rw-r--r--gpxe/src/crypto/axtls/os_port.h61
-rw-r--r--gpxe/src/crypto/axtls/rsa.c332
-rw-r--r--gpxe/src/crypto/axtls/sha1.c240
-rw-r--r--gpxe/src/crypto/axtls_aes.c54
-rw-r--r--gpxe/src/crypto/axtls_sha1.c26
-rw-r--r--gpxe/src/crypto/chap.c122
-rw-r--r--gpxe/src/crypto/cipher.c24
-rw-r--r--gpxe/src/crypto/cryptoLayer.h120
-rw-r--r--gpxe/src/crypto/crypto_null.c69
-rw-r--r--gpxe/src/crypto/framework.c86
-rw-r--r--gpxe/src/crypto/hmac.c120
-rw-r--r--gpxe/src/crypto/matrixssl/mpi.h487
-rw-r--r--gpxe/src/crypto/matrixssl/pscrypto.h661
-rw-r--r--gpxe/src/crypto/md5.c235
-rw-r--r--gpxe/src/crypto/ssl.c136
-rw-r--r--gpxe/src/crypto/ssl.h19
-rw-r--r--gpxe/src/crypto/ssl_constructs.h342
24 files changed, 6630 insertions, 0 deletions
diff --git a/gpxe/src/crypto/asn1.c b/gpxe/src/crypto/asn1.c
new file mode 100644
index 00000000..0a69162a
--- /dev/null
+++ b/gpxe/src/crypto/asn1.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <errno.h>
+#include <gpxe/asn1.h>
+
+/** @file
+ *
+ * ASN.1 encoding
+ *
+ */
+
+/**
+ * Start parsing ASN.1 object
+ *
+ * @v cursor ASN.1 object cursor
+ * @v type Expected type
+ * @ret len Length of object body, or -1 on error
+ *
+ * The object cursor will be updated to point to the start of the
+ * object body (i.e. the first byte following the length byte(s)), and
+ * the length of the object body (i.e. the number of bytes until the
+ * following object tag, if any) is returned.
+ *
+ * If any error occurs (i.e. if the object is not of the expected
+ * type, or if we overflow beyond the end of the ASN.1 object), then
+ * the cursor will be invalidated and a negative value will be
+ * returned.
+ */
+static int asn1_start_object ( struct asn1_cursor *cursor,
+ unsigned int type ) {
+ unsigned int len_len;
+ unsigned int len;
+
+ /* Sanity check */
+ if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
+ if ( cursor->len )
+ DBGC ( cursor, "ASN1 %p too short\n", cursor );
+ goto notfound;
+ }
+
+ /* Check the tag byte */
+ if ( cursor->data[0] != type ) {
+ DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
+ cursor, type, cursor->data[0] );
+ goto notfound;
+ }
+ cursor->data++;
+ cursor->len--;
+
+ /* Extract length of the length field and sanity check */
+ len_len = cursor->data[0];
+ if ( len_len & 0x80 ) {
+ len_len = ( len_len & 0x7f );
+ cursor->data++;
+ cursor->len--;
+ } else {
+ len_len = 1;
+ }
+ if ( cursor->len < len_len ) {
+ DBGC ( cursor, "ASN1 %p bad length field length %d (max "
+ "%zd)\n", cursor, len_len, cursor->len );
+ goto notfound;
+ }
+
+ /* Extract the length and sanity check */
+ for ( len = 0 ; len_len ; len_len-- ) {
+ len <<= 8;
+ len |= cursor->data[0];
+ cursor->data++;
+ cursor->len--;
+ }
+ if ( cursor->len < len ) {
+ DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
+ cursor, len, cursor->len );
+ goto notfound;
+ }
+
+ return len;
+
+ notfound:
+ cursor->data = NULL;
+ cursor->len = 0;
+ return -1;
+}
+
+/**
+ * Enter ASN.1 object
+ *
+ * @v cursor ASN.1 object cursor
+ * @v type Expected type
+ * @ret rc Return status code
+ *
+ * The object cursor will be updated to point to the body of the
+ * current ASN.1 object. If any error occurs, the object cursor will
+ * be invalidated.
+ */
+int asn1_enter_object ( struct asn1_cursor *cursor, unsigned int type ) {
+ int len;
+
+ len = asn1_start_object ( cursor, type );
+ if ( len < 0 )
+ return -ENOENT;
+
+ cursor->len = len;
+ DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
+ cursor, type, len );
+
+ return 0;
+}
+
+/**
+ * Skip ASN.1 object
+ *
+ * @v cursor ASN.1 object cursor
+ * @v type Expected type
+ * @ret rc Return status code
+ *
+ * The object cursor will be updated to point to the next ASN.1
+ * object. If any error occurs, the object cursor will be
+ * invalidated.
+ */
+int asn1_skip_object ( struct asn1_cursor *cursor, unsigned int type ) {
+ int len;
+
+ len = asn1_start_object ( cursor, type );
+ if ( len < 0 )
+ return -ENOENT;
+
+ cursor->data += len;
+ cursor->len -= len;
+ DBGC ( cursor, "ASN1 %p skipped object type %02x (len %x)\n",
+ cursor, type, len );
+
+ if ( ! cursor->len ) {
+ DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
+ cursor->data = NULL;
+ return -ENOENT;
+ }
+
+ return 0;
+}
diff --git a/gpxe/src/crypto/axtls/aes.c b/gpxe/src/crypto/axtls/aes.c
new file mode 100644
index 00000000..9154a515
--- /dev/null
+++ b/gpxe/src/crypto/axtls/aes.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright(C) 2006 Cameron Rich
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/**
+ * AES implementation - this is a small code version. There are much faster
+ * versions around but they are much larger in size (i.e. they use large
+ * submix tables).
+ */
+
+#include <string.h>
+#include "crypto.h"
+
+/* all commented out in skeleton mode */
+#ifndef CONFIG_SSL_SKELETON_MODE
+
+#define rot1(x) (((x) << 24) | ((x) >> 8))
+#define rot2(x) (((x) << 16) | ((x) >> 16))
+#define rot3(x) (((x) << 8) | ((x) >> 24))
+
+/*
+ * This cute trick does 4 'mul by two' at once. Stolen from
+ * Dr B. R. Gladman <brg@gladman.uk.net> but I'm sure the u-(u>>7) is
+ * a standard graphics trick
+ * The key to this is that we need to xor with 0x1b if the top bit is set.
+ * a 1xxx xxxx 0xxx 0xxx First we mask the 7bit,
+ * b 1000 0000 0000 0000 then we shift right by 7 putting the 7bit in 0bit,
+ * c 0000 0001 0000 0000 we then subtract (c) from (b)
+ * d 0111 1111 0000 0000 and now we and with our mask
+ * e 0001 1011 0000 0000
+ */
+#define mt 0x80808080
+#define ml 0x7f7f7f7f
+#define mh 0xfefefefe
+#define mm 0x1b1b1b1b
+#define mul2(x,t) ((t)=((x)&mt), \
+ ((((x)+(x))&mh)^(((t)-((t)>>7))&mm)))
+
+#define inv_mix_col(x,f2,f4,f8,f9) (\
+ (f2)=mul2(x,f2), \
+ (f4)=mul2(f2,f4), \
+ (f8)=mul2(f4,f8), \
+ (f9)=(x)^(f8), \
+ (f8)=((f2)^(f4)^(f8)), \
+ (f2)^=(f9), \
+ (f4)^=(f9), \
+ (f8)^=rot3(f2), \
+ (f8)^=rot2(f4), \
+ (f8)^rot1(f9))
+
+/* some macros to do endian independent byte extraction */
+#define n2l(c,l) l=ntohl(*c); c++
+#define l2n(l,c) *c++=htonl(l)
+
+/*
+ * AES S-box
+ */
+static const uint8_t aes_sbox[256] =
+{
+ 0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,
+ 0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76,
+ 0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,
+ 0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0,
+ 0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,
+ 0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15,
+ 0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,
+ 0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75,
+ 0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,
+ 0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84,
+ 0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,
+ 0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF,
+ 0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,
+ 0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8,
+ 0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,
+ 0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2,
+ 0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,
+ 0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73,
+ 0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,
+ 0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB,
+ 0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,
+ 0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79,
+ 0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,
+ 0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08,
+ 0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,
+ 0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A,
+ 0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,
+ 0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E,
+ 0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,
+ 0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF,
+ 0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,
+ 0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16,
+};
+
+/*
+ * AES is-box
+ */
+static const uint8_t aes_isbox[256] =
+{
+ 0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,
+ 0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
+ 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,
+ 0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
+ 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,
+ 0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,
+ 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,
+ 0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
+ 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,
+ 0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
+ 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,
+ 0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
+ 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,
+ 0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
+ 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,
+ 0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
+ 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,
+ 0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
+ 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,
+ 0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
+ 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,
+ 0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
+ 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,
+ 0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
+ 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,
+ 0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
+ 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,
+ 0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
+ 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,
+ 0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
+ 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,
+ 0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d
+};
+
+static const unsigned char Rcon[30]=
+{
+ 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
+ 0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,
+ 0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,
+ 0xb3,0x7d,0xfa,0xef,0xc5,0x91,
+};
+
+/* ----- static functions ----- */
+static void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
+static void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
+
+/* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial
+ x^8+x^4+x^3+x+1 */
+static unsigned char AES_xtime(uint32_t x)
+{
+ return x = (x&0x80) ? (x<<1)^0x1b : x<<1;
+}
+
+/**
+ * Set up AES with the key/iv and cipher size.
+ */
+void AES_set_key(AES_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, AES_MODE mode)
+{
+ int i, ii;
+ uint32_t *W, tmp, tmp2;
+ const unsigned char *ip;
+ int words;
+
+ switch (mode)
+ {
+ case AES_MODE_128:
+ i = 10;
+ words = 4;
+ break;
+
+ case AES_MODE_256:
+ i = 14;
+ words = 8;
+ break;
+
+ default: /* fail silently */
+ return;
+ }
+
+ ctx->rounds = i;
+ ctx->key_size = words;
+ W = ctx->ks;
+ for (i = 0; i < words; i+=2)
+ {
+ W[i+0]= ((uint32_t)key[ 0]<<24)|
+ ((uint32_t)key[ 1]<<16)|
+ ((uint32_t)key[ 2]<< 8)|
+ ((uint32_t)key[ 3] );
+ W[i+1]= ((uint32_t)key[ 4]<<24)|
+ ((uint32_t)key[ 5]<<16)|
+ ((uint32_t)key[ 6]<< 8)|
+ ((uint32_t)key[ 7] );
+ key += 8;
+ }
+
+ ip = Rcon;
+ ii = 4 * (ctx->rounds+1);
+ for (i = words; i<ii; i++)
+ {
+ tmp = W[i-1];
+
+ if ((i % words) == 0)
+ {
+ tmp2 =(uint32_t)aes_sbox[(tmp )&0xff]<< 8;
+ tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<<16;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<24;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>24) ];
+ tmp=tmp2^(((unsigned int)*ip)<<24);
+ ip++;
+ }
+
+ if ((words == 8) && ((i % words) == 4))
+ {
+ tmp2 =(uint32_t)aes_sbox[(tmp )&0xff] ;
+ tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<< 8;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<16;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>24) ]<<24;
+ tmp=tmp2;
+ }
+
+ W[i]=W[i-words]^tmp;
+ }
+
+ /* copy the iv across */
+ memcpy(ctx->iv, iv, 16);
+}
+
+/**
+ * Change a key for decryption.
+ */
+void AES_convert_key(AES_CTX *ctx)
+{
+ int i;
+ uint32_t *k,w,t1,t2,t3,t4;
+
+ k = ctx->ks;
+ k += 4;
+
+ for (i=ctx->rounds*4; i>4; i--)
+ {
+ w= *k;
+ w = inv_mix_col(w,t1,t2,t3,t4);
+ *k++ =w;
+ }
+}
+
+/**
+ * Encrypt a byte sequence (with a block size 16) using the AES cipher.
+ */
+void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{
+ uint32_t tin0, tin1, tin2, tin3;
+ uint32_t tout0, tout1, tout2, tout3;
+ uint32_t tin[4];
+ uint32_t *iv = (uint32_t *)ctx->iv;
+ uint32_t *msg_32 = (uint32_t *)msg;
+ uint32_t *out_32 = (uint32_t *)out;
+
+ n2l(iv, tout0);
+ n2l(iv, tout1);
+ n2l(iv, tout2);
+ n2l(iv, tout3);
+ iv -= 4;
+
+ for (length -= 16; length >= 0; length -= 16)
+ {
+ n2l(msg_32, tin0);
+ n2l(msg_32, tin1);
+ n2l(msg_32, tin2);
+ n2l(msg_32, tin3);
+ tin[0] = tin0^tout0;
+ tin[1] = tin1^tout1;
+ tin[2] = tin2^tout2;
+ tin[3] = tin3^tout3;
+
+ AES_encrypt(ctx, tin);
+
+ tout0 = tin[0];
+ l2n(tout0, out_32);
+ tout1 = tin[1];
+ l2n(tout1, out_32);
+ tout2 = tin[2];
+ l2n(tout2, out_32);
+ tout3 = tin[3];
+ l2n(tout3, out_32);
+ }
+
+ l2n(tout0, iv);
+ l2n(tout1, iv);
+ l2n(tout2, iv);
+ l2n(tout3, iv);
+}
+
+/**
+ * Decrypt a byte sequence (with a block size 16) using the AES cipher.
+ */
+void AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{
+ uint32_t tin0, tin1, tin2, tin3;
+ uint32_t xor0,xor1,xor2,xor3;
+ uint32_t tout0,tout1,tout2,tout3;
+ uint32_t data[4];
+ uint32_t *iv = (uint32_t *)ctx->iv;
+ uint32_t *msg_32 = (uint32_t *)msg;
+ uint32_t *out_32 = (uint32_t *)out;
+
+ n2l(iv ,xor0);
+ n2l(iv, xor1);
+ n2l(iv, xor2);
+ n2l(iv, xor3);
+ iv -= 4;
+
+ for (length-=16; length >= 0; length -= 16)
+ {
+ n2l(msg_32, tin0);
+ n2l(msg_32, tin1);
+ n2l(msg_32, tin2);
+ n2l(msg_32, tin3);
+
+ data[0] = tin0;
+ data[1] = tin1;
+ data[2] = tin2;
+ data[3] = tin3;
+
+ AES_decrypt(ctx, data);
+
+ tout0 = data[0]^xor0;
+ tout1 = data[1]^xor1;
+ tout2 = data[2]^xor2;
+ tout3 = data[3]^xor3;
+
+ xor0 = tin0;
+ xor1 = tin1;
+ xor2 = tin2;
+ xor3 = tin3;
+
+ l2n(tout0, out_32);
+ l2n(tout1, out_32);
+ l2n(tout2, out_32);
+ l2n(tout3, out_32);
+ }
+
+ l2n(xor0, iv);
+ l2n(xor1, iv);
+ l2n(xor2, iv);
+ l2n(xor3, iv);
+}
+
+/**
+ * Encrypt a single block (16 bytes) of data
+ */
+static void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
+{
+ /* To make this code smaller, generate the sbox entries on the fly.
+ * This will have a really heavy effect upon performance.
+ */
+ uint32_t tmp[4];
+ uint32_t tmp1, old_a0, a0, a1, a2, a3, row;
+ int curr_rnd;
+ int rounds = ctx->rounds;
+ const uint32_t *k = ctx->ks;
+
+ /* Pre-round key addition */
+ for (row = 0; row < 4; row++)
+ {
+ data[row] ^= *(k++);
+ }
+
+ /* Encrypt one block. */
+ for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
+ {
+ /* Perform ByteSub and ShiftRow operations together */
+ for (row = 0; row < 4; row++)
+ {
+ a0 = (uint32_t)aes_sbox[(data[row%4]>>24)&0xFF];
+ a1 = (uint32_t)aes_sbox[(data[(row+1)%4]>>16)&0xFF];
+ a2 = (uint32_t)aes_sbox[(data[(row+2)%4]>>8)&0xFF];
+ a3 = (uint32_t)aes_sbox[(data[(row+3)%4])&0xFF];
+
+ /* Perform MixColumn iff not last round */
+ if (curr_rnd < (rounds - 1))
+ {
+ tmp1 = a0 ^ a1 ^ a2 ^ a3;
+ old_a0 = a0;
+
+ a0 ^= tmp1 ^ AES_xtime(a0 ^ a1);
+ a1 ^= tmp1 ^ AES_xtime(a1 ^ a2);
+ a2 ^= tmp1 ^ AES_xtime(a2 ^ a3);
+ a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0);
+
+ }
+
+ tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3);
+ }
+
+ /* KeyAddition - note that it is vital that this loop is separate from
+ the MixColumn operation, which must be atomic...*/
+ for (row = 0; row < 4; row++)
+ {
+ data[row] = tmp[row] ^ *(k++);
+ }
+ }
+}
+
+/**
+ * Decrypt a single block (16 bytes) of data
+ */
+static void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
+{
+ uint32_t tmp[4];
+ uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6;
+ uint32_t a0, a1, a2, a3, row;
+ int curr_rnd;
+ int rounds = ctx->rounds;
+ uint32_t *k = (uint32_t*)ctx->ks + ((rounds+1)*4);
+
+ /* pre-round key addition */
+ for (row=4; row > 0;row--)
+ {
+ data[row-1] ^= *(--k);
+ }
+
+ /* Decrypt one block */
+ for (curr_rnd=0; curr_rnd < rounds; curr_rnd++)
+ {
+ /* Perform ByteSub and ShiftRow operations together */
+ for (row = 4; row > 0; row--)
+ {
+ a0 = aes_isbox[(data[(row+3)%4]>>24)&0xFF];
+ a1 = aes_isbox[(data[(row+2)%4]>>16)&0xFF];
+ a2 = aes_isbox[(data[(row+1)%4]>>8)&0xFF];
+ a3 = aes_isbox[(data[row%4])&0xFF];
+
+ /* Perform MixColumn iff not last round */
+ if (curr_rnd<(rounds-1))
+ {
+ /* The MDS cofefficients (0x09, 0x0B, 0x0D, 0x0E)
+ are quite large compared to encryption; this
+ operation slows decryption down noticeably. */
+ xt0 = AES_xtime(a0^a1);
+ xt1 = AES_xtime(a1^a2);
+ xt2 = AES_xtime(a2^a3);
+ xt3 = AES_xtime(a3^a0);
+ xt4 = AES_xtime(xt0^xt1);
+ xt5 = AES_xtime(xt1^xt2);
+ xt6 = AES_xtime(xt4^xt5);
+
+ xt0 ^= a1^a2^a3^xt4^xt6;
+ xt1 ^= a0^a2^a3^xt5^xt6;
+ xt2 ^= a0^a1^a3^xt4^xt6;
+ xt3 ^= a0^a1^a2^xt5^xt6;
+ tmp[row-1] = ((xt0<<24)|(xt1<<16)|(xt2<<8)|xt3);
+ }
+ else
+ tmp[row-1] = ((a0<<24)|(a1<<16)|(a2<<8)|a3);
+ }
+
+ for (row = 4; row > 0; row--)
+ {
+ data[row-1] = tmp[row-1] ^ *(--k);
+ }
+ }
+}
+
+#endif
diff --git a/gpxe/src/crypto/axtls/axtls_asn1.c b/gpxe/src/crypto/axtls/axtls_asn1.c
new file mode 100644
index 00000000..74411c70
--- /dev/null
+++ b/gpxe/src/crypto/axtls/axtls_asn1.c
@@ -0,0 +1,867 @@
+/*
+ * Copyright(C) 2006 Cameron Rich
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/**
+ * @file asn1.c
+ *
+ * Some primitive asn methods for extraction rsa modulus information. It also
+ * is used for retrieving information from X.509 certificates.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "crypto.h"
+
+#define SIG_OID_PREFIX_SIZE 8
+
+#define SIG_TYPE_MD2 0x02
+#define SIG_TYPE_MD5 0x04
+#define SIG_TYPE_SHA1 0x05
+
+/* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */
+static const uint8_t sig_oid_prefix[SIG_OID_PREFIX_SIZE] =
+{
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01
+};
+
+/* CN, O, OU */
+static const uint8_t g_dn_types[] = { 3, 10, 11 };
+
+static int get_asn1_length(const uint8_t *buf, int *offset)
+{
+ int len, i;
+
+ if (!(buf[*offset] & 0x80)) /* short form */
+ {
+ len = buf[(*offset)++];
+ }
+ else /* long form */
+ {
+ int length_bytes = buf[(*offset)++]&0x7f;
+ len = 0;
+ for (i = 0; i < length_bytes; i++)
+ {
+ len <<= 8;
+ len += buf[(*offset)++];
+ }
+ }
+
+ return len;
+}
+
+/**
+ * Skip the ASN1.1 object type and its length. Get ready to read the object's
+ * data.
+ */
+int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type)
+{
+ if (buf[*offset] != obj_type)
+ return X509_NOT_OK;
+ (*offset)++;
+ return get_asn1_length(buf, offset);
+}
+
+/**
+ * Skip over an ASN.1 object type completely. Get ready to read the next
+ * object.
+ */
+int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type)
+{
+ int len;
+
+ if (buf[*offset] != obj_type)
+ return X509_NOT_OK;
+ (*offset)++;
+ len = get_asn1_length(buf, offset);
+ *offset += len;
+ return 0;
+}
+
+/**
+ * Read an integer value for ASN.1 data
+ * Note: This function allocates memory which must be freed by the user.
+ */
+int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object)
+{
+ int len;
+
+ if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0)
+ goto end_int_array;
+
+ *object = (uint8_t *)malloc(len);
+ memcpy(*object, &buf[*offset], len);
+ *offset += len;
+
+end_int_array:
+ return len;
+}
+
+#if 0
+
+/**
+ * Get all the RSA private key specifics from an ASN.1 encoded file
+ */
+int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx)
+{
+ int offset = 7;
+ uint8_t *modulus, *priv_exp, *pub_exp;
+ int mod_len, priv_len, pub_len;
+#ifdef CONFIG_BIGINT_CRT
+ uint8_t *p, *q, *dP, *dQ, *qInv;
+ int p_len, q_len, dP_len, dQ_len, qInv_len;
+#endif
+
+ /* not in der format */
+ if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("Error: This is not a valid ASN.1 file\n");
+#endif
+ return X509_INVALID_PRIV_KEY;
+ }
+
+ /* initialise the RNG */
+ RNG_initialize(buf, len);
+
+ mod_len = asn1_get_int(buf, &offset, &modulus);
+ pub_len = asn1_get_int(buf, &offset, &pub_exp);
+ priv_len = asn1_get_int(buf, &offset, &priv_exp);
+
+ if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0)
+ return X509_INVALID_PRIV_KEY;
+
+#ifdef CONFIG_BIGINT_CRT
+ p_len = asn1_get_int(buf, &offset, &p);
+ q_len = asn1_get_int(buf, &offset, &q);
+ dP_len = asn1_get_int(buf, &offset, &dP);
+ dQ_len = asn1_get_int(buf, &offset, &dQ);
+ qInv_len = asn1_get_int(buf, &offset, &qInv);
+
+ if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0)
+ return X509_INVALID_PRIV_KEY;
+
+ RSA_priv_key_new(rsa_ctx,
+ modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len,
+ p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len);
+
+ free(p);
+ free(q);
+ free(dP);
+ free(dQ);
+ free(qInv);
+#else
+ RSA_priv_key_new(rsa_ctx,
+ modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len);
+#endif
+
+ free(modulus);
+ free(priv_exp);
+ free(pub_exp);
+ return X509_OK;
+}
+
+/**
+ * Get the time of a certificate. Ignore hours/minutes/seconds.
+ */
+static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t)
+{
+ int ret = X509_NOT_OK, len, t_offset;
+ struct tm tm;
+
+ if (buf[(*offset)++] != ASN1_UTC_TIME)
+ goto end_utc_time;
+ len = get_asn1_length(buf, offset);
+ t_offset = *offset;
+
+ memset(&tm, 0, sizeof(struct tm));
+ tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0');
+
+ if (tm.tm_year <= 50) /* 1951-2050 thing */
+ {
+ tm.tm_year += 100;
+ }
+
+ tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1;
+ tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0');
+ *t = mktime(&tm);
+ *offset += len;
+ ret = X509_OK;
+
+end_utc_time:
+ return ret;
+}
+
+/**
+ * Get the version type of a certificate (which we don't actually care about)
+ */
+static int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+ int ret = X509_NOT_OK;
+
+ (*offset) += 2; /* get past explicit tag */
+ if (asn1_skip_obj(cert, offset, ASN1_INTEGER))
+ goto end_version;
+
+ ret = X509_OK;
+end_version:
+ return ret;
+}
+
+/**
+ * Retrieve the notbefore and notafter certificate times.
+ */
+static int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+ return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
+ asn1_get_utc_time(cert, offset, &x509_ctx->not_before) ||
+ asn1_get_utc_time(cert, offset, &x509_ctx->not_after));
+}
+
+/**
+ * Get the components of a distinguished name
+ */
+static int asn1_get_oid_x520(const uint8_t *buf, int *offset)
+{
+ int dn_type = 0;
+ int len;
+
+ if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)
+ goto end_oid;
+
+ /* expect a sequence of 2.5.4.[x] where x is a one of distinguished name
+ components we are interested in. */
+ if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04)
+ dn_type = buf[(*offset)++];
+ else
+ {
+ *offset += len; /* skip over it */
+ }
+
+end_oid:
+ return dn_type;
+}
+
+/**
+ * Obtain an ASN.1 printable string type.
+ */
+static int asn1_get_printable_str(const uint8_t *buf, int *offset, char **str)
+{
+ int len = X509_NOT_OK;
+
+ /* some certs have this awful crud in them for some reason */
+ if (buf[*offset] != ASN1_PRINTABLE_STR &&
+ buf[*offset] != ASN1_TELETEX_STR && buf[*offset] != ASN1_IA5_STR)
+ goto end_pnt_str;
+
+ (*offset)++;
+ len = get_asn1_length(buf, offset);
+ *str = (char *)malloc(len+1); /* allow for null */
+ memcpy(*str, &buf[*offset], len);
+ (*str)[len] = 0; /* null terminate */
+ *offset += len;
+end_pnt_str:
+ return len;
+}
+
+/**
+ * Get the subject name (or the issuer) of a certificate.
+ */
+static int asn1_name(const uint8_t *cert, int *offset, char *dn[])
+{
+ int ret = X509_NOT_OK;
+ int dn_type;
+ char *tmp = NULL;
+
+ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
+ goto end_name;
+
+ while (asn1_next_obj(cert, offset, ASN1_SET) >= 0)
+ {
+ int i, found = 0;
+
+ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
+ (dn_type = asn1_get_oid_x520(cert, offset)) < 0)
+ goto end_name;
+
+ if (asn1_get_printable_str(cert, offset, &tmp) < 0)
+ {
+ free(tmp);
+ goto end_name;
+ }
+
+ /* find the distinguished named type */
+ for (i = 0; i < X509_NUM_DN_TYPES; i++)
+ {
+ if (dn_type == g_dn_types[i])
+ {
+ if (dn[i] == NULL)
+ {
+ dn[i] = tmp;
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ if (found == 0) /* not found so get rid of it */
+ {
+ free(tmp);
+ }
+ }
+
+ ret = X509_OK;
+end_name:
+ return ret;
+}
+
+/**
+ * Read the modulus and public exponent of a certificate.
+ */
+static int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+ int ret = X509_NOT_OK, mod_len, pub_len;
+ uint8_t *modulus, *pub_exp;
+
+ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(cert, offset, ASN1_SEQUENCE) ||
+ asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0)
+ goto end_pub_key;
+
+ (*offset)++;
+
+ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
+ goto end_pub_key;
+
+ mod_len = asn1_get_int(cert, offset, &modulus);
+ pub_len = asn1_get_int(cert, offset, &pub_exp);
+
+ RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len);
+
+ free(modulus);
+ free(pub_exp);
+ ret = X509_OK;
+
+end_pub_key:
+ return ret;
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Read the signature of the certificate.
+ */
+static int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
+{
+ int ret = X509_NOT_OK;
+
+ if (cert[(*offset)++] != ASN1_BIT_STRING)
+ goto end_sig;
+
+ x509_ctx->sig_len = get_asn1_length(cert, offset);
+ x509_ctx->signature = (uint8_t *)malloc(x509_ctx->sig_len);
+ memcpy(x509_ctx->signature, &cert[*offset], x509_ctx->sig_len);
+ *offset += x509_ctx->sig_len;
+ ret = X509_OK;
+
+end_sig:
+ return ret;
+}
+
+/*
+ * Compare 2 distinguished name components for equality
+ * @return 0 if a match
+ */
+static int asn1_compare_dn_comp(const char *dn1, const char *dn2)
+{
+ int ret = 1;
+
+ if ((dn1 && dn2 == NULL) || (dn1 == NULL && dn2)) goto err_no_match;
+
+ ret = (dn1 && dn2) ? strcmp(dn1, dn2) : 0;
+
+err_no_match:
+ return ret;
+}
+
+/**
+ * Clean up all of the CA certificates.
+ */
+void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx)
+{
+ int i = 0;
+
+ while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
+ {
+ x509_free(ca_cert_ctx->cert[i]);
+ ca_cert_ctx->cert[i++] = NULL;
+ }
+
+ free(ca_cert_ctx);
+}
+
+/*
+ * Compare 2 distinguished names for equality
+ * @return 0 if a match
+ */
+static int asn1_compare_dn(char * const dn1[], char * const dn2[])
+{
+ int i;
+
+ for (i = 0; i < X509_NUM_DN_TYPES; i++)
+ {
+ if (asn1_compare_dn_comp(dn1[i], dn2[i]))
+ {
+ return 1;
+ }
+ }
+
+ return 0; /* all good */
+}
+
+/**
+ * Retrieve the signature from a certificate.
+ */
+const uint8_t *x509_get_signature(const uint8_t *asn1_sig, int *len)
+{
+ int offset = 0;
+ const uint8_t *ptr = NULL;
+
+ if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 ||
+ asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
+ goto end_get_sig;
+
+ if (asn1_sig[offset++] != ASN1_OCTET_STRING)
+ goto end_get_sig;
+ *len = get_asn1_length(asn1_sig, &offset);
+ ptr = &asn1_sig[offset]; /* all ok */
+
+end_get_sig:
+ return ptr;
+}
+
+#endif
+
+/**
+ * Read the signature type of the certificate. We only support RSA-MD5 and
+ * RSA-SHA1 signature types.
+ */
+static int asn1_signature_type(const uint8_t *cert,
+ int *offset, X509_CTX *x509_ctx)
+{
+ int ret = X509_NOT_OK, len;
+
+ if (cert[(*offset)++] != ASN1_OID)
+ goto end_check_sig;
+
+ len = get_asn1_length(cert, offset);
+
+ if (memcmp(sig_oid_prefix, &cert[*offset], SIG_OID_PREFIX_SIZE))
+ goto end_check_sig; /* unrecognised cert type */
+
+ x509_ctx->sig_type = cert[*offset + SIG_OID_PREFIX_SIZE];
+
+ *offset += len;
+ if (asn1_skip_obj(cert, offset, ASN1_NULL))
+ goto end_check_sig;
+ ret = X509_OK;
+
+end_check_sig:
+ return ret;
+}
+
+/**
+ * Construct a new x509 object.
+ * @return 0 if ok. < 0 if there was a problem.
+ */
+int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
+{
+ int begin_tbs, end_tbs;
+ int ret = X509_NOT_OK, offset = 0, cert_size = 0;
+ X509_CTX *x509_ctx;
+ BI_CTX *bi_ctx;
+
+ *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX));
+ x509_ctx = *ctx;
+
+ /* get the certificate size */
+ asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE);
+
+ if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
+ goto end_cert;
+
+ begin_tbs = offset; /* start of the tbs */
+ end_tbs = begin_tbs; /* work out the end of the tbs */
+ asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE);
+
+ if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
+ goto end_cert;
+
+ if (cert[offset] == ASN1_EXPLICIT_TAG) /* optional version */
+ {
+ if (asn1_version(cert, &offset, x509_ctx))
+ goto end_cert;
+ }
+
+ if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */
+ asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
+ goto end_cert;
+
+ /* make sure the signature is ok */
+ if (asn1_signature_type(cert, &offset, x509_ctx))
+ {
+ ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST;
+ goto end_cert;
+ }
+
+ if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) ||
+ asn1_validity(cert, &offset, x509_ctx) ||
+ asn1_name(cert, &offset, x509_ctx->cert_dn) ||
+ asn1_public_key(cert, &offset, x509_ctx))
+ goto end_cert;
+
+ bi_ctx = x509_ctx->rsa_ctx->bi_ctx;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
+ /* use the appropriate signature algorithm (either SHA1 or MD5) */
+ if (x509_ctx->sig_type == SIG_TYPE_MD5)
+ {
+ MD5_CTX md5_ctx;
+ uint8_t md5_dgst[MD5_SIZE];
+ MD5Init(&md5_ctx);
+ MD5Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
+ MD5Final(&md5_ctx, md5_dgst);
+ x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE);
+ }
+ else if (x509_ctx->sig_type == SIG_TYPE_SHA1)
+ {
+ SHA1_CTX sha_ctx;
+ uint8_t sha_dgst[SHA1_SIZE];
+ SHA1Init(&sha_ctx);
+ SHA1Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
+ SHA1Final(&sha_ctx, sha_dgst);
+ x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE);
+ }
+
+ offset = end_tbs; /* skip the v3 data */
+ if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
+ asn1_signature(cert, &offset, x509_ctx))
+ goto end_cert;
+#endif
+
+ if (len)
+ {
+ *len = cert_size;
+ }
+
+ ret = X509_OK;
+end_cert:
+
+#ifdef CONFIG_SSL_FULL_MODE
+ if (ret)
+ {
+ printf("Error: Invalid X509 ASN.1 file\n");
+ }
+#endif
+
+ return ret;
+}
+
+/**
+ * Free an X.509 object's resources.
+ */
+void x509_free(X509_CTX *x509_ctx)
+{
+ X509_CTX *next;
+ int i;
+
+ if (x509_ctx == NULL) /* if already null, then don't bother */
+ return;
+
+ for (i = 0; i < X509_NUM_DN_TYPES; i++)
+ {
+ free(x509_ctx->ca_cert_dn[i]);
+ free(x509_ctx->cert_dn[i]);
+ }
+
+ free(x509_ctx->signature);
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ if (x509_ctx->digest)
+ {
+ bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);
+ }
+#endif
+
+ RSA_free(x509_ctx->rsa_ctx);
+
+ next = x509_ctx->next;
+ free(x509_ctx);
+ x509_free(next); /* clear the chain */
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Do some basic checks on the certificate chain.
+ *
+ * Certificate verification consists of a number of checks:
+ * - A root certificate exists in the certificate store.
+ * - The date of the certificate is after the start date.
+ * - The date of the certificate is before the finish date.
+ * - The certificate chain is valid.
+ * - That the certificate(s) are not self-signed.
+ * - The signature of the certificate is valid.
+ */
+int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
+{
+ int ret = X509_OK, i = 0;
+ bigint *cert_sig;
+ X509_CTX *next_cert = NULL;
+ BI_CTX *ctx;
+ bigint *mod, *expn;
+ struct timeval tv;
+ int match_ca_cert = 0;
+
+ if (cert == NULL || ca_cert_ctx == NULL)
+ {
+ ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
+ goto end_verify;
+ }
+
+ /* last cert in the chain - look for a trusted cert */
+ if (cert->next == NULL)
+ {
+ while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
+ {
+ if (asn1_compare_dn(cert->ca_cert_dn,
+ ca_cert_ctx->cert[i]->cert_dn) == 0)
+ {
+ match_ca_cert = 1;
+ break;
+ }
+
+ i++;
+ }
+
+ if (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
+ {
+ next_cert = ca_cert_ctx->cert[i];
+ }
+ else /* trusted cert not found */
+ {
+ ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
+ goto end_verify;
+ }
+ }
+ else
+ {
+ next_cert = cert->next;
+ }
+
+ gettimeofday(&tv, NULL);
+
+ /* check the not before date */
+ if (tv.tv_sec < cert->not_before)
+ {
+ ret = X509_VFY_ERROR_NOT_YET_VALID;
+ goto end_verify;
+ }
+
+ /* check the not after date */
+ if (tv.tv_sec > cert->not_after)
+ {
+ ret = X509_VFY_ERROR_EXPIRED;
+ goto end_verify;
+ }
+
+ /* check the chain integrity */
+ if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn))
+ {
+ ret = X509_VFY_ERROR_INVALID_CHAIN;
+ goto end_verify;
+ }
+
+ /* check for self-signing */
+ if (!match_ca_cert && asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0)
+ {
+ ret = X509_VFY_ERROR_SELF_SIGNED;
+ goto end_verify;
+ }
+
+ /* check the signature */
+ ctx = cert->rsa_ctx->bi_ctx;
+ mod = next_cert->rsa_ctx->m;
+ expn = next_cert->rsa_ctx->e;
+ cert_sig = RSA_sign_verify(ctx, cert->signature, cert->sig_len,
+ bi_clone(ctx, mod), bi_clone(ctx, expn));
+
+ if (cert_sig)
+ {
+ ret = cert->digest ? /* check the signature */
+ bi_compare(cert_sig, cert->digest) :
+ X509_VFY_ERROR_UNSUPPORTED_DIGEST;
+ bi_free(ctx, cert_sig);
+
+ if (ret)
+ goto end_verify;
+ }
+ else
+ {
+ ret = X509_VFY_ERROR_BAD_SIGNATURE;
+ goto end_verify;
+ }
+
+ /* go down the certificate chain using recursion. */
+ if (ret == 0 && cert->next)
+ {
+ ret = x509_verify(ca_cert_ctx, next_cert);
+ }
+
+end_verify:
+ return ret;
+}
+#endif
+
+#if defined (CONFIG_SSL_FULL_MODE)
+/**
+ * Used for diagnostics.
+ */
+void x509_print(CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
+{
+ if (cert == NULL)
+ return;
+
+ printf("---------------- CERT DEBUG ----------------\n");
+ printf("* CA Cert Distinguished Name\n");
+ if (cert->ca_cert_dn[X509_COMMON_NAME])
+ {
+ printf("Common Name (CN):\t%s\n", cert->ca_cert_dn[X509_COMMON_NAME]);
+ }
+
+ if (cert->ca_cert_dn[X509_ORGANIZATION])
+ {
+ printf("Organization (O):\t%s\n", cert->ca_cert_dn[X509_ORGANIZATION]);
+ }
+
+ if (cert->ca_cert_dn[X509_ORGANIZATIONAL_TYPE])
+ {
+ printf("Organizational Unit (OU): %s\n",
+ cert->ca_cert_dn[X509_ORGANIZATIONAL_TYPE]);
+ }
+
+ printf("* Cert Distinguished Name\n");
+ if (cert->cert_dn[X509_COMMON_NAME])
+ {
+ printf("Common Name (CN):\t%s\n", cert->cert_dn[X509_COMMON_NAME]);
+ }
+
+ if (cert->cert_dn[X509_ORGANIZATION])
+ {
+ printf("Organization (O):\t%s\n", cert->cert_dn[X509_ORGANIZATION]);
+ }
+
+ if (cert->cert_dn[X509_ORGANIZATIONAL_TYPE])
+ {
+ printf("Organizational Unit (OU): %s\n",
+ cert->cert_dn[X509_ORGANIZATIONAL_TYPE]);
+ }
+
+ printf("Not Before:\t\t%s", ctime(&cert->not_before));
+ printf("Not After:\t\t%s", ctime(&cert->not_after));
+ printf("RSA bitsize:\t\t%d\n", cert->rsa_ctx->num_octets*8);
+ printf("Sig Type:\t\t");
+ switch (cert->sig_type)
+ {
+ case SIG_TYPE_MD5:
+ printf("MD5\n");
+ break;
+ case SIG_TYPE_SHA1:
+ printf("SHA1\n");
+ break;
+ case SIG_TYPE_MD2:
+ printf("MD2\n");
+ break;
+ default:
+ printf("Unrecognized: %d\n", cert->sig_type);
+ break;
+ }
+
+ printf("Verify:\t\t\t");
+
+ if (ca_cert_ctx)
+ {
+ x509_display_error(x509_verify(ca_cert_ctx, cert));
+ }
+
+ printf("\n");
+#if 0
+ print_blob("Signature", cert->signature, cert->sig_len);
+ bi_print("Modulus", cert->rsa_ctx->m);
+ bi_print("Pub Exp", cert->rsa_ctx->e);
+#endif
+
+ if (ca_cert_ctx)
+ {
+ x509_print(ca_cert_ctx, cert->next);
+ }
+}
+
+void x509_display_error(int error)
+{
+ switch (error)
+ {
+ case X509_NOT_OK:
+ printf("X509 not ok");
+ break;
+
+ case X509_VFY_ERROR_NO_TRUSTED_CERT:
+ printf("No trusted cert is available");
+ break;
+
+ case X509_VFY_ERROR_BAD_SIGNATURE:
+ printf("Bad signature");
+ break;
+
+ case X509_VFY_ERROR_NOT_YET_VALID:
+ printf("Cert is not yet valid");
+ break;
+
+ case X509_VFY_ERROR_EXPIRED:
+ printf("Cert has expired");
+ break;
+
+ case X509_VFY_ERROR_SELF_SIGNED:
+ printf("Cert is self-signed");
+ break;
+
+ case X509_VFY_ERROR_INVALID_CHAIN:
+ printf("Chain is invalid (check order of certs)");
+ break;
+
+ case X509_VFY_ERROR_UNSUPPORTED_DIGEST:
+ printf("Unsupported digest");
+ break;
+
+ case X509_INVALID_PRIV_KEY:
+ printf("Invalid private key");
+ break;
+ }
+}
+#endif /* CONFIG_SSL_FULL_MODE */
+
+#endif
diff --git a/gpxe/src/crypto/axtls/bigint.c b/gpxe/src/crypto/axtls/bigint.c
new file mode 100644
index 00000000..49cad971
--- /dev/null
+++ b/gpxe/src/crypto/axtls/bigint.c
@@ -0,0 +1,1496 @@
+/*
+ * Copyright(C) 2006 Cameron Rich
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/**
+ * @defgroup bigint_api Big Integer API
+ * @brief The bigint implementation as used by the axTLS project.
+ *
+ * The bigint library is for RSA encryption/decryption as well as signing.
+ * This code tries to minimise use of malloc/free by maintaining a small
+ * cache. A bigint context may maintain state by being made "permanent".
+ * It be be later released with a bi_depermanent() and bi_free() call.
+ *
+ * It supports the following reduction techniques:
+ * - Classical
+ * - Barrett
+ * - Montgomery
+ *
+ * It also implements the following:
+ * - Karatsuba multiplication
+ * - Squaring
+ * - Sliding window exponentiation
+ * - Chinese Remainder Theorem (implemented in rsa.c).
+ *
+ * All the algorithms used are pretty standard, and designed for different
+ * data bus sizes. Negative numbers are not dealt with at all, so a subtraction
+ * may need to be tested for negativity.
+ *
+ * This library steals some ideas from Jef Poskanzer
+ * <http://cs.marlboro.edu/term/cs-fall02/algorithms/crypto/RSA/bigint>
+ * and GMP <http://www.swox.com/gmp>. It gets most of its implementation
+ * detail from "The Handbook of Applied Cryptography"
+ * <http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf>
+ * @{
+ */
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include "bigint.h"
+#include "crypto.h"
+
+static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i);
+static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom);
+static bigint __malloc *alloc(BI_CTX *ctx, int size);
+static bigint *trim(bigint *bi);
+static void more_comps(bigint *bi, int n);
+#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
+ defined(CONFIG_BIGINT_MONTGOMERY)
+static bigint *comp_right_shift(bigint *biR, int num_shifts);
+static bigint *comp_left_shift(bigint *biR, int num_shifts);
+#endif
+
+#ifdef CONFIG_BIGINT_CHECK_ON
+static void check(const bigint *bi);
+#endif
+
+/**
+ * @brief Start a new bigint context.
+ * @return A bigint context.
+ */
+BI_CTX *bi_initialize(void)
+{
+ /* calloc() sets everything to zero */
+ BI_CTX *ctx = (BI_CTX *)calloc(1, sizeof(BI_CTX));
+
+ /* the radix */
+ ctx->bi_radix = alloc(ctx, 2);
+ ctx->bi_radix->comps[0] = 0;
+ ctx->bi_radix->comps[1] = 1;
+ bi_permanent(ctx->bi_radix);
+ return ctx;
+}
+
+/**
+ * @brief Close the bigint context and free any resources.
+ *
+ * Free up any used memory - a check is done if all objects were not
+ * properly freed.
+ * @param ctx [in] The bigint session context.
+ */
+void bi_terminate(BI_CTX *ctx)
+{
+ bigint *p, *pn;
+
+ bi_depermanent(ctx->bi_radix);
+ bi_free(ctx, ctx->bi_radix);
+
+ if (ctx->active_count != 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("bi_terminate: there were %d un-freed bigints\n",
+ ctx->active_count);
+#endif
+ abort();
+ }
+
+ for (p = ctx->free_list; p != NULL; p = pn)
+ {
+ pn = p->next;
+ free(p->comps);
+ free(p);
+ }
+
+ free(ctx);
+}
+
+/**
+ * @brief Increment the number of references to this object.
+ * It does not do a full copy.
+ * @param bi [in] The bigint to copy.
+ * @return A reference to the same bigint.
+ */
+bigint *bi_copy(bigint *bi)
+{
+ check(bi);
+ if (bi->refs != PERMANENT)
+ bi->refs++;
+ return bi;
+}
+
+/**
+ * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it.
+ *
+ * For this object to be freed, bi_depermanent() must be called.
+ * @param bi [in] The bigint to be made permanent.
+ */
+void bi_permanent(bigint *bi)
+{
+ check(bi);
+ if (bi->refs != 1)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("bi_permanent: refs was not 1\n");
+#endif
+ abort();
+ }
+
+ bi->refs = PERMANENT;
+}
+
+/**
+ * @brief Take a permanent object and make it eligible for freedom.
+ * @param bi [in] The bigint to be made back to temporary.
+ */
+void bi_depermanent(bigint *bi)
+{
+ check(bi);
+ if (bi->refs != PERMANENT)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("bi_depermanent: bigint was not permanent\n");
+#endif
+ abort();
+ }
+
+ bi->refs = 1;
+}
+
+/**
+ * @brief Free a bigint object so it can be used again.
+ *
+ * The memory itself it not actually freed, just tagged as being available
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] The bigint to be freed.
+ */
+void bi_free(BI_CTX *ctx, bigint *bi)
+{
+ check(bi);
+ if (bi->refs == PERMANENT)
+ {
+ return;
+ }
+
+ if (--bi->refs > 0)
+ {
+ return;
+ }
+
+ bi->next = ctx->free_list;
+ ctx->free_list = bi;
+ ctx->free_count++;
+
+ if (--ctx->active_count < 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("bi_free: active_count went negative "
+ "- double-freed bigint?\n");
+#endif
+ abort();
+ }
+}
+
+/**
+ * @brief Convert an (unsigned) integer into a bigint.
+ * @param ctx [in] The bigint session context.
+ * @param i [in] The (unsigned) integer to be converted.
+ *
+ */
+bigint *int_to_bi(BI_CTX *ctx, comp i)
+{
+ bigint *biR = alloc(ctx, 1);
+ biR->comps[0] = i;
+ return biR;
+}
+
+/**
+ * @brief Do a full copy of the bigint object.
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] The bigint object to be copied.
+ */
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi)
+{
+ bigint *biR = alloc(ctx, bi->size);
+ check(bi);
+ memcpy(biR->comps, bi->comps, bi->size*COMP_BYTE_SIZE);
+ return biR;
+}
+
+/**
+ * @brief Perform an addition operation between two bigints.
+ * @param ctx [in] The bigint session context.
+ * @param bia [in] A bigint.
+ * @param bib [in] Another bigint.
+ * @return The result of the addition.
+ */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+ int n;
+ comp carry = 0;
+ comp *pa, *pb;
+
+ check(bia);
+ check(bib);
+
+ n = max(bia->size, bib->size);
+ more_comps(bia, n+1);
+ more_comps(bib, n);
+ pa = bia->comps;
+ pb = bib->comps;
+
+ do
+ {
+ comp sl, rl, cy1;
+ sl = *pa + *pb++;
+ rl = sl + carry;
+ cy1 = sl < *pa;
+ carry = cy1 | (rl < sl);
+ *pa++ = rl;
+ } while (--n != 0);
+
+ *pa = carry; /* do overflow */
+ bi_free(ctx, bib);
+ return trim(bia);
+}
+
+/**
+ * @brief Perform a subtraction operation between two bigints.
+ * @param ctx [in] The bigint session context.
+ * @param bia [in] A bigint.
+ * @param bib [in] Another bigint.
+ * @param is_negative [out] If defined, indicates that the result was negative.
+ * is_negative may be null.
+ * @return The result of the subtraction. The result is always positive.
+ */
+bigint *bi_subtract(BI_CTX *ctx,
+ bigint *bia, bigint *bib, int *is_negative)
+{
+ int n = bia->size;
+ comp *pa, *pb, carry = 0;
+
+ check(bia);
+ check(bib);
+
+ more_comps(bib, n);
+ pa = bia->comps;
+ pb = bib->comps;
+
+ do
+ {
+ comp sl, rl, cy1;
+ sl = *pa - *pb++;
+ rl = sl - carry;
+ cy1 = sl > *pa;
+ carry = cy1 | (rl > sl);
+ *pa++ = rl;
+ } while (--n != 0);
+
+ if (is_negative) /* indicate a negative result */
+ {
+ *is_negative = carry;
+ }
+
+ bi_free(ctx, trim(bib)); /* put bib back to the way it was */
+ return trim(bia);
+}
+
+/**
+ * Perform a multiply between a bigint an an (unsigned) integer
+ */
+static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b)
+{
+ int j = 0, n = bia->size;
+ bigint *biR = alloc(ctx, n + 1);
+ comp carry = 0;
+ comp *r = biR->comps;
+ comp *a = bia->comps;
+
+ check(bia);
+
+ /* clear things to start with */
+ memset(r, 0, ((n+1)*COMP_BYTE_SIZE));
+
+ do
+ {
+ long_comp tmp = *r + (long_comp)a[j]*b + carry;
+ *r++ = (comp)tmp; /* downsize */
+ carry = (comp)(tmp >> COMP_BIT_SIZE);
+ } while (++j < n);
+
+ *r = carry;
+ bi_free(ctx, bia);
+ return trim(biR);
+}
+
+/**
+ * @brief Does both division and modulo calculations.
+ *
+ * Used extensively when doing classical reduction.
+ * @param ctx [in] The bigint session context.
+ * @param u [in] A bigint which is the numerator.
+ * @param v [in] Either the denominator or the modulus depending on the mode.
+ * @param is_mod [n] Determines if this is a normal division (0) or a reduction
+ * (1).
+ * @return The result of the division/reduction.
+ */
+bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod)
+{
+ int n = v->size, m = u->size-n;
+ int j = 0, orig_u_size = u->size;
+ uint8_t mod_offset = ctx->mod_offset;
+ comp d;
+ bigint *quotient, *tmp_u;
+ comp q_dash;
+
+ check(u);
+ check(v);
+
+ /* if doing reduction and we are < mod, then return mod */
+ if (is_mod && bi_compare(v, u) > 0)
+ {
+ bi_free(ctx, v);
+ return u;
+ }
+
+ quotient = alloc(ctx, m+1);
+ tmp_u = alloc(ctx, n+1);
+ v = trim(v); /* make sure we have no leading 0's */
+ d = (comp)((long_comp)COMP_RADIX/(V1+1));
+
+ /* clear things to start with */
+ memset(quotient->comps, 0, ((quotient->size)*COMP_BYTE_SIZE));
+
+ /* normalise */
+ if (d > 1)
+ {
+ u = bi_int_multiply(ctx, u, d);
+
+ if (is_mod)
+ {
+ v = ctx->bi_normalised_mod[mod_offset];
+ }
+ else
+ {
+ v = bi_int_multiply(ctx, v, d);
+ }
+ }
+
+ if (orig_u_size == u->size) /* new digit position u0 */
+ {
+ more_comps(u, orig_u_size + 1);
+ }
+
+ do
+ {
+ /* get a temporary short version of u */
+ memcpy(tmp_u->comps, &u->comps[u->size-n-1-j], (n+1)*COMP_BYTE_SIZE);
+
+ /* calculate q' */
+ if (U(0) == V1)
+ {
+ q_dash = COMP_RADIX-1;
+ }
+ else
+ {
+ q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1);
+ }
+
+ if (v->size > 1 && V2)
+ {
+ /* we are implementing the following:
+ if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) -
+ q_dash*V1)*COMP_RADIX) + U(2))) ... */
+ comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) -
+ (long_comp)q_dash*V1);
+ if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2))
+ {
+ q_dash--;
+ }
+ }
+
+ /* multiply and subtract */
+ if (q_dash)
+ {
+ int is_negative;
+ tmp_u = bi_subtract(ctx, tmp_u,
+ bi_int_multiply(ctx, bi_copy(v), q_dash), &is_negative);
+ more_comps(tmp_u, n+1);
+
+ Q(j) = q_dash;
+
+ /* add back */
+ if (is_negative)
+ {
+ Q(j)--;
+ tmp_u = bi_add(ctx, tmp_u, bi_copy(v));
+
+ /* lop off the carry */
+ tmp_u->size--;
+ v->size--;
+ }
+ }
+ else
+ {
+ Q(j) = 0;
+ }
+
+ /* copy back to u */
+ memcpy(&u->comps[u->size-n-1-j], tmp_u->comps, (n+1)*COMP_BYTE_SIZE);
+ } while (++j <= m);
+
+ bi_free(ctx, tmp_u);
+ bi_free(ctx, v);
+
+ if (is_mod) /* get the remainder */
+ {
+ bi_free(ctx, quotient);
+ return bi_int_divide(ctx, trim(u), d);
+ }
+ else /* get the quotient */
+ {
+ bi_free(ctx, u);
+ return trim(quotient);
+ }
+}
+
+/*
+ * Perform an integer divide on a bigint.
+ */
+static bigint *bi_int_divide(BI_CTX *ctx __unused, bigint *biR, comp denom)
+{
+ int i = biR->size - 1;
+ long_comp r = 0;
+
+ check(biR);
+
+ do
+ {
+ r = (r<<COMP_BIT_SIZE) + biR->comps[i];
+ biR->comps[i] = (comp)(r / denom);
+ r %= denom;
+ } while (--i != 0);
+
+ return trim(biR);
+}
+
+#ifdef CONFIG_BIGINT_MONTGOMERY
+/**
+ * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1,
+ * where B^-1(B-1) mod N=1. Actually, only the least significant part of
+ * N' is needed, hence the definition N0'=N' mod b. We reproduce below the
+ * simple algorithm from an article by Dusse and Kaliski to efficiently
+ * find N0' from N0 and b */
+static comp modular_inverse(bigint *bim)
+{
+ int i;
+ comp t = 1;
+ comp two_2_i_minus_1 = 2; /* 2^(i-1) */
+ long_comp two_2_i = 4; /* 2^i */
+ comp N = bim->comps[0];
+
+ for (i = 2; i <= COMP_BIT_SIZE; i++)
+ {
+ if ((long_comp)N*t%two_2_i >= two_2_i_minus_1)
+ {
+ t += two_2_i_minus_1;
+ }
+
+ two_2_i_minus_1 <<= 1;
+ two_2_i <<= 1;
+ }
+
+ return (comp)(COMP_RADIX-t);
+}
+#endif
+
+#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
+ defined(CONFIG_BIGINT_MONTGOMERY)
+/**
+ * Take each component and shift down (in terms of components)
+ */
+static bigint *comp_right_shift(bigint *biR, int num_shifts)
+{
+ int i = biR->size-num_shifts;
+ comp *x = biR->comps;
+ comp *y = &biR->comps[num_shifts];
+
+ check(biR);
+
+ if (i <= 0) /* have we completely right shifted? */
+ {
+ biR->comps[0] = 0; /* return 0 */
+ biR->size = 1;
+ return biR;
+ }
+
+ do
+ {
+ *x++ = *y++;
+ } while (--i > 0);
+
+ biR->size -= num_shifts;
+ return biR;
+}
+
+/**
+ * Take each component and shift it up (in terms of components)
+ */
+static bigint *comp_left_shift(bigint *biR, int num_shifts)
+{
+ int i = biR->size-1;
+ comp *x, *y;
+
+ check(biR);
+
+ if (num_shifts <= 0)
+ {
+ return biR;
+ }
+
+ more_comps(biR, biR->size + num_shifts);
+
+ x = &biR->comps[i+num_shifts];
+ y = &biR->comps[i];
+
+ do
+ {
+ *x-- = *y--;
+ } while (i--);
+
+ memset(biR->comps, 0, num_shifts*COMP_BYTE_SIZE); /* zero LS comps */
+ return biR;
+}
+#endif
+
+/**
+ * @brief Allow a binary sequence to be imported as a bigint.
+ * @param ctx [in] The bigint session context.
+ * @param data [in] The data to be converted.
+ * @param size [in] The number of bytes of data.
+ * @return A bigint representing this data.
+ */
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size)
+{
+ bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE);
+ int i, j = 0, offset = 0;
+
+ memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
+
+ for (i = size-1; i >= 0; i--)
+ {
+ biR->comps[offset] += data[i] << (j*8);
+
+ if (++j == COMP_BYTE_SIZE)
+ {
+ j = 0;
+ offset ++;
+ }
+ }
+
+ return trim(biR);
+}
+
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * @brief The testharness uses this code to import text hex-streams and
+ * convert them into bigints.
+ * @param ctx [in] The bigint session context.
+ * @param data [in] A string consisting of hex characters. The characters must
+ * be in upper case.
+ * @return A bigint representing this data.
+ */
+bigint *bi_str_import(BI_CTX *ctx, const char *data)
+{
+ int size = strlen(data);
+ bigint *biR = alloc(ctx, (size+COMP_NUM_NIBBLES-1)/COMP_NUM_NIBBLES);
+ int i, j = 0, offset = 0;
+ memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
+
+ for (i = size-1; i >= 0; i--)
+ {
+ int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10);
+ biR->comps[offset] += num << (j*4);
+
+ if (++j == COMP_NUM_NIBBLES)
+ {
+ j = 0;
+ offset ++;
+ }
+ }
+
+ return biR;
+}
+
+void bi_print(const char *label, bigint *x)
+{
+ int i, j;
+
+ if (x == NULL)
+ {
+ printf("%s: (null)\n", label);
+ return;
+ }
+
+ printf("%s: (size %d)\n", label, x->size);
+ for (i = x->size-1; i >= 0; i--)
+ {
+ for (j = COMP_NUM_NIBBLES-1; j >= 0; j--)
+ {
+ comp mask = 0x0f << (j*4);
+ comp num = (x->comps[i] & mask) >> (j*4);
+ putc((num <= 9) ? (num + '0') : (num + 'A' - 10), stdout);
+ }
+ }
+
+ printf("\n");
+}
+#endif
+
+/**
+ * @brief Take a bigint and convert it into a byte sequence.
+ *
+ * This is useful after a decrypt operation.
+ * @param ctx [in] The bigint session context.
+ * @param x [in] The bigint to be converted.
+ * @param data [out] The converted data as a byte stream.
+ * @param size [in] The maximum size of the byte stream. Unused bytes will be
+ * zeroed.
+ */
+void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size)
+{
+ int i, j, k = size-1;
+
+ check(x);
+ memset(data, 0, size); /* ensure all leading 0's are cleared */
+
+ for (i = 0; i < x->size; i++)
+ {
+ for (j = 0; j < COMP_BYTE_SIZE; j++)
+ {
+ comp mask = 0xff << (j*8);
+ int num = (x->comps[i] & mask) >> (j*8);
+ data[k--] = num;
+
+ if (k < 0)
+ {
+ break;
+ }
+ }
+ }
+
+ bi_free(ctx, x);
+}
+
+/**
+ * @brief Pre-calculate some of the expensive steps in reduction.
+ *
+ * This function should only be called once (normally when a session starts).
+ * When the session is over, bi_free_mod() should be called. bi_mod_power()
+ * relies on this function being called.
+ * @param ctx [in] The bigint session context.
+ * @param bim [in] The bigint modulus that will be used.
+ * @param mod_offset [in] There are three moduluii that can be stored - the
+ * standard modulus, and its two primes p and q. This offset refers to which
+ * modulus we are referring to.
+ * @see bi_free_mod(), bi_mod_power().
+ */
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset)
+{
+ int k = bim->size;
+ comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1));
+#ifdef CONFIG_BIGINT_MONTGOMERY
+ bigint *R, *R2;
+#endif
+
+ ctx->bi_mod[mod_offset] = bim;
+ bi_permanent(ctx->bi_mod[mod_offset]);
+ ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d);
+ bi_permanent(ctx->bi_normalised_mod[mod_offset]);
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ /* set montgomery variables */
+ R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k-1); /* R */
+ R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k*2-1); /* R^2 */
+ ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2); /* R^2 mod m */
+ ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R); /* R mod m */
+
+ bi_permanent(ctx->bi_RR_mod_m[mod_offset]);
+ bi_permanent(ctx->bi_R_mod_m[mod_offset]);
+
+ ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]);
+
+#elif defined (CONFIG_BIGINT_BARRETT)
+ ctx->bi_mu[mod_offset] =
+ bi_divide(ctx, comp_left_shift(
+ bi_clone(ctx, ctx->bi_radix), k*2-1), ctx->bi_mod[mod_offset], 0);
+ bi_permanent(ctx->bi_mu[mod_offset]);
+#endif
+}
+
+/**
+ * @brief Used when cleaning various bigints at the end of a session.
+ * @param ctx [in] The bigint session context.
+ * @param mod_offset [in] The offset to use.
+ * @see bi_set_mod().
+ */
+void bi_free_mod(BI_CTX *ctx, int mod_offset)
+{
+ bi_depermanent(ctx->bi_mod[mod_offset]);
+ bi_free(ctx, ctx->bi_mod[mod_offset]);
+#if defined (CONFIG_BIGINT_MONTGOMERY)
+ bi_depermanent(ctx->bi_RR_mod_m[mod_offset]);
+ bi_depermanent(ctx->bi_R_mod_m[mod_offset]);
+ bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]);
+ bi_free(ctx, ctx->bi_R_mod_m[mod_offset]);
+#elif defined(CONFIG_BIGINT_BARRETT)
+ bi_depermanent(ctx->bi_mu[mod_offset]);
+ bi_free(ctx, ctx->bi_mu[mod_offset]);
+#endif
+ bi_depermanent(ctx->bi_normalised_mod[mod_offset]);
+ bi_free(ctx, ctx->bi_normalised_mod[mod_offset]);
+}
+
+/**
+ * Perform a standard multiplication between two bigints.
+ */
+static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+ int i, j, i_plus_j;
+ int n = bia->size;
+ int t = bib->size;
+ bigint *biR = alloc(ctx, n + t);
+ comp *sr = biR->comps;
+ comp *sa = bia->comps;
+ comp *sb = bib->comps;
+
+ check(bia);
+ check(bib);
+
+ /* clear things to start with */
+ memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE));
+ i = 0;
+
+ do
+ {
+ comp carry = 0;
+ comp b = *sb++;
+ i_plus_j = i;
+ j = 0;
+
+ do
+ {
+ long_comp tmp = sr[i_plus_j] + (long_comp)sa[j]*b + carry;
+ sr[i_plus_j++] = (comp)tmp; /* downsize */
+ carry = (comp)(tmp >> COMP_BIT_SIZE);
+ } while (++j < n);
+
+ sr[i_plus_j] = carry;
+ } while (++i < t);
+
+ bi_free(ctx, bia);
+ bi_free(ctx, bib);
+ return trim(biR);
+}
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+/*
+ * Karatsuba improves on regular multiplication due to only 3 multiplications
+ * being done instead of 4. The additional additions/subtractions are O(N)
+ * rather than O(N^2) and so for big numbers it saves on a few operations
+ */
+static bigint *karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square)
+{
+ bigint *x0, *x1;
+ bigint *p0, *p1, *p2;
+ int m;
+
+ if (is_square)
+ {
+ m = (bia->size + 1)/2;
+ }
+ else
+ {
+ m = (max(bia->size, bib->size) + 1)/2;
+ }
+
+ x0 = bi_clone(ctx, bia);
+ x0->size = m;
+ x1 = bi_clone(ctx, bia);
+ comp_right_shift(x1, m);
+ bi_free(ctx, bia);
+
+ /* work out the 3 partial products */
+ if (is_square)
+ {
+ p0 = bi_square(ctx, bi_copy(x0));
+ p2 = bi_square(ctx, bi_copy(x1));
+ p1 = bi_square(ctx, bi_add(ctx, x0, x1));
+ }
+ else /* normal multiply */
+ {
+ bigint *y0, *y1;
+ y0 = bi_clone(ctx, bib);
+ y0->size = m;
+ y1 = bi_clone(ctx, bib);
+ comp_right_shift(y1, m);
+ bi_free(ctx, bib);
+
+ p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0));
+ p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1));
+ p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1));
+ }
+
+ p1 = bi_subtract(ctx,
+ bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), NULL);
+
+ comp_left_shift(p1, m);
+ comp_left_shift(p2, 2*m);
+ return bi_add(ctx, p1, bi_add(ctx, p0, p2));
+}
+#endif
+
+/**
+ * @brief Perform a multiplication operation between two bigints.
+ * @param ctx [in] The bigint session context.
+ * @param bia [in] A bigint.
+ * @param bib [in] Another bigint.
+ * @return The result of the multiplication.
+ */
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+ check(bia);
+ check(bib);
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+ if (min(bia->size, bib->size) < MUL_KARATSUBA_THRESH)
+ {
+ return regular_multiply(ctx, bia, bib);
+ }
+
+ return karatsuba(ctx, bia, bib, 0);
+#else
+ return regular_multiply(ctx, bia, bib);
+#endif
+}
+
+#ifdef CONFIG_BIGINT_SQUARE
+/*
+ * Perform the actual square operion. It takes into account overflow.
+ */
+static bigint *regular_square(BI_CTX *ctx, bigint *bi)
+{
+ int t = bi->size;
+ int i = 0, j;
+ bigint *biR = alloc(ctx, t*2);
+ comp *w = biR->comps;
+ comp *x = bi->comps;
+ comp carry;
+
+ memset(w, 0, biR->size*COMP_BYTE_SIZE);
+
+ do
+ {
+ long_comp tmp = w[2*i] + (long_comp)x[i]*x[i];
+ comp u = 0;
+ w[2*i] = (comp)tmp;
+ carry = (comp)(tmp >> COMP_BIT_SIZE);
+
+ for (j = i+1; j < t; j++)
+ {
+ long_comp xx = (long_comp)x[i]*x[j];
+ long_comp blob = (long_comp)w[i+j]+carry;
+
+ if (u) /* previous overflow */
+ {
+ blob += COMP_RADIX;
+ }
+
+ u = 0;
+ if (xx & COMP_BIG_MSB) /* check for overflow */
+ {
+ u = 1;
+ }
+
+ tmp = 2*xx + blob;
+ w[i+j] = (comp)tmp;
+ carry = (comp)(tmp >> COMP_BIT_SIZE);
+ }
+
+ w[i+t] += carry;
+
+ if (u)
+ {
+ w[i+t+1] = 1; /* add carry */
+ }
+ } while (++i < t);
+
+ bi_free(ctx, bi);
+ return trim(biR);
+}
+
+/**
+ * @brief Perform a square operation on a bigint.
+ * @param ctx [in] The bigint session context.
+ * @param bia [in] A bigint.
+ * @return The result of the multiplication.
+ */
+bigint *bi_square(BI_CTX *ctx, bigint *bia)
+{
+ check(bia);
+
+#ifdef CONFIG_BIGINT_KARATSUBA
+ if (bia->size < SQU_KARATSUBA_THRESH)
+ {
+ return regular_square(ctx, bia);
+ }
+
+ return karatsuba(ctx, bia, NULL, 1);
+#else
+ return regular_square(ctx, bia);
+#endif
+}
+#endif
+
+/**
+ * @brief Compare two bigints.
+ * @param bia [in] A bigint.
+ * @param bib [in] Another bigint.
+ * @return -1 if smaller, 1 if larger and 0 if equal.
+ */
+int bi_compare(bigint *bia, bigint *bib)
+{
+ int r, i;
+
+ check(bia);
+ check(bib);
+
+ if (bia->size > bib->size)
+ r = 1;
+ else if (bia->size < bib->size)
+ r = -1;
+ else
+ {
+ comp *a = bia->comps;
+ comp *b = bib->comps;
+
+ /* Same number of components. Compare starting from the high end
+ * and working down. */
+ r = 0;
+ i = bia->size - 1;
+
+ do
+ {
+ if (a[i] > b[i])
+ {
+ r = 1;
+ break;
+ }
+ else if (a[i] < b[i])
+ {
+ r = -1;
+ break;
+ }
+ } while (--i >= 0);
+ }
+
+ return r;
+}
+
+/*
+ * Allocate and zero more components. Does not consume bi.
+ */
+static void more_comps(bigint *bi, int n)
+{
+ if (n > bi->max_comps)
+ {
+ bi->max_comps = max(bi->max_comps * 2, n);
+ bi->comps = (comp*)realloc(bi->comps, bi->max_comps * COMP_BYTE_SIZE);
+ }
+
+ if (n > bi->size)
+ {
+ memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE);
+ }
+
+ bi->size = n;
+}
+
+/*
+ * Make a new empty bigint. It may just use an old one if one is available.
+ * Otherwise get one off the heap.
+ */
+static bigint *alloc(BI_CTX *ctx, int size)
+{
+ bigint *biR;
+
+ /* Can we recycle an old bigint? */
+ if (ctx->free_list != NULL)
+ {
+ biR = ctx->free_list;
+ ctx->free_list = biR->next;
+ ctx->free_count--;
+
+ if (biR->refs != 0)
+ {
+#ifdef CONFIG_SSL_FULL_MODE
+ printf("alloc: refs was not 0\n");
+#endif
+ abort(); /* create a stack trace from a core dump */
+ }
+
+ more_comps(biR, size);
+ }
+ else
+ {
+ /* No free bigints available - create a new one. */
+ biR = (bigint *)malloc(sizeof(bigint));
+ biR->comps = (comp*)malloc(size * COMP_BYTE_SIZE);
+ biR->max_comps = size; /* give some space to spare */
+ }
+
+ biR->size = size;
+ biR->refs = 1;
+ biR->next = NULL;
+ ctx->active_count++;
+ return biR;
+}
+
+/*
+ * Work out the highest '1' bit in an exponent. Used when doing sliding-window
+ * exponentiation.
+ */
+static int find_max_exp_index(bigint *biexp)
+{
+ int i = COMP_BIT_SIZE-1;
+ comp shift = COMP_RADIX/2;
+ comp test = biexp->comps[biexp->size-1]; /* assume no leading zeroes */
+
+ check(biexp);
+
+ do
+ {
+ if (test & shift)
+ {
+ return i+(biexp->size-1)*COMP_BIT_SIZE;
+ }
+
+ shift >>= 1;
+ } while (--i != 0);
+
+ return -1; /* error - must have been a leading 0 */
+}
+
+/*
+ * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window
+ * exponentiation.
+ */
+static int exp_bit_is_one(bigint *biexp, int offset)
+{
+ comp test = biexp->comps[offset / COMP_BIT_SIZE];
+ int num_shifts = offset % COMP_BIT_SIZE;
+ comp shift = 1;
+ int i;
+
+ check(biexp);
+
+ for (i = 0; i < num_shifts; i++)
+ {
+ shift <<= 1;
+ }
+
+ return test & shift;
+}
+
+#ifdef CONFIG_BIGINT_CHECK_ON
+/*
+ * Perform a sanity check on bi.
+ */
+static void check(const bigint *bi)
+{
+ if (bi->refs <= 0)
+ {
+ printf("check: zero or negative refs in bigint\n");
+ abort();
+ }
+
+ if (bi->next != NULL)
+ {
+ printf("check: attempt to use a bigint from "
+ "the free list\n");
+ abort();
+ }
+}
+#endif
+
+/*
+ * Delete any leading 0's (and allow for 0).
+ */
+static bigint *trim(bigint *bi)
+{
+ check(bi);
+
+ while (bi->comps[bi->size-1] == 0 && bi->size > 1)
+ {
+ bi->size--;
+ }
+
+ return bi;
+}
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+/**
+ * @brief Perform a single montgomery reduction.
+ * @param ctx [in] The bigint session context.
+ * @param bixy [in] A bigint.
+ * @return The result of the montgomery reduction.
+ */
+bigint *bi_mont(BI_CTX *ctx, bigint *bixy)
+{
+ int i = 0, n;
+ uint8_t mod_offset = ctx->mod_offset;
+ bigint *bim = ctx->bi_mod[mod_offset];
+ comp mod_inv = ctx->N0_dash[mod_offset];
+
+ check(bixy);
+
+ if (ctx->use_classical) /* just use classical instead */
+ {
+ return bi_mod(ctx, bixy);
+ }
+
+ n = bim->size;
+
+ do
+ {
+ bixy = bi_add(ctx, bixy, comp_left_shift(
+ bi_int_multiply(ctx, bim, bixy->comps[i]*mod_inv), i));
+ } while (++i < n);
+
+ comp_right_shift(bixy, n);
+
+ if (bi_compare(bixy, bim) >= 0)
+ {
+ bixy = bi_subtract(ctx, bixy, bim, NULL);
+ }
+
+ return bixy;
+}
+
+#elif defined(CONFIG_BIGINT_BARRETT)
+/*
+ * Stomp on the most significant components to give the illusion of a "mod base
+ * radix" operation
+ */
+static bigint *comp_mod(bigint *bi, int mod)
+{
+ check(bi);
+
+ if (bi->size > mod)
+ {
+ bi->size = mod;
+ }
+
+ return bi;
+}
+
+/*
+ * Barrett reduction has no need for some parts of the product, so ignore bits
+ * of the multiply. This routine gives Barrett its big performance
+ * improvements over Classical/Montgomery reduction methods.
+ */
+static bigint *partial_multiply(BI_CTX *ctx, bigint *bia, bigint *bib,
+ int inner_partial, int outer_partial)
+{
+ int i = 0, j, n = bia->size, t = bib->size;
+ bigint *biR;
+ comp carry;
+ comp *sr, *sa, *sb;
+
+ check(bia);
+ check(bib);
+
+ biR = alloc(ctx, n + t);
+ sa = bia->comps;
+ sb = bib->comps;
+ sr = biR->comps;
+
+ if (inner_partial)
+ {
+ memset(sr, 0, inner_partial*COMP_BYTE_SIZE);
+ }
+ else /* outer partial */
+ {
+ if (n < outer_partial || t < outer_partial) /* should we bother? */
+ {
+ bi_free(ctx, bia);
+ bi_free(ctx, bib);
+ biR->comps[0] = 0; /* return 0 */
+ biR->size = 1;
+ return biR;
+ }
+
+ memset(&sr[outer_partial], 0, (n+t-outer_partial)*COMP_BYTE_SIZE);
+ }
+
+ do
+ {
+ comp *a = sa;
+ comp b = *sb++;
+ long_comp tmp;
+ int i_plus_j = i;
+ carry = 0;
+ j = n;
+
+ if (outer_partial && i_plus_j < outer_partial)
+ {
+ i_plus_j = outer_partial;
+ a = &sa[outer_partial-i];
+ j = n-(outer_partial-i);
+ }
+
+ do
+ {
+ if (inner_partial && i_plus_j >= inner_partial)
+ {
+ break;
+ }
+
+ tmp = sr[i_plus_j] + ((long_comp)*a++)*b + carry;
+ sr[i_plus_j++] = (comp)tmp; /* downsize */
+ carry = (comp)(tmp >> COMP_BIT_SIZE);
+ } while (--j != 0);
+
+ sr[i_plus_j] = carry;
+ } while (++i < t);
+
+ bi_free(ctx, bia);
+ bi_free(ctx, bib);
+ return trim(biR);
+}
+
+/**
+ * @brief Perform a single Barrett reduction.
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] A bigint.
+ * @return The result of the Barrett reduction.
+ */
+bigint *bi_barrett(BI_CTX *ctx, bigint *bi)
+{
+ bigint *q1, *q2, *q3, *r1, *r2, *r;
+ uint8_t mod_offset = ctx->mod_offset;
+ bigint *bim = ctx->bi_mod[mod_offset];
+ int k = bim->size;
+
+ check(bi);
+ check(bim);
+
+ /* use Classical method instead - Barrett cannot help here */
+ if (bi->size > k*2)
+ {
+ return bi_mod(ctx, bi);
+ }
+
+ q1 = comp_right_shift(bi_clone(ctx, bi), k-1);
+
+ /* do outer partial multiply */
+ q2 = partial_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k-1);
+ q3 = comp_right_shift(q2, k+1);
+ r1 = comp_mod(bi, k+1);
+
+ /* do inner partial multiply */
+ r2 = comp_mod(partial_multiply(ctx, q3, bim, k+1, 0), k+1);
+ r = bi_subtract(ctx, r1, r2, NULL);
+
+ /* if (r >= m) r = r - m; */
+ if (bi_compare(r, bim) >= 0)
+ {
+ r = bi_subtract(ctx, r, bim, NULL);
+ }
+
+ return r;
+}
+#endif /* CONFIG_BIGINT_BARRETT */
+
+#ifdef CONFIG_BIGINT_SLIDING_WINDOW
+/*
+ * Work out g1, g3, g5, g7... etc for the sliding-window algorithm
+ */
+static void precompute_slide_window(BI_CTX *ctx, int window, bigint *g1)
+{
+ int k = 1, i;
+ bigint *g2;
+
+ for (i = 0; i < window-1; i++) /* compute 2^(window-1) */
+ {
+ k <<= 1;
+ }
+
+ ctx->g = (bigint **)malloc(k*sizeof(bigint *));
+ ctx->g[0] = bi_clone(ctx, g1);
+ bi_permanent(ctx->g[0]);
+ g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0])); /* g^2 */
+
+ for (i = 1; i < k; i++)
+ {
+ ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i-1], bi_copy(g2)));
+ bi_permanent(ctx->g[i]);
+ }
+
+ bi_free(ctx, g2);
+ ctx->window = k;
+}
+#endif
+
+/**
+ * @brief Perform a modular exponentiation.
+ *
+ * This function requires bi_set_mod() to have been called previously. This is
+ * one of the optimisations used for performance.
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] The bigint on which to perform the mod power operation.
+ * @param biexp [in] The bigint exponent.
+ * @see bi_set_mod().
+ */
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp)
+{
+ int i = find_max_exp_index(biexp), j, window_size = 1;
+ bigint *biR = int_to_bi(ctx, 1);
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ uint8_t mod_offset = ctx->mod_offset;
+ if (!ctx->use_classical)
+ {
+ /* preconvert */
+ bi = bi_mont(ctx,
+ bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset])); /* x' */
+ bi_free(ctx, biR);
+ biR = ctx->bi_R_mod_m[mod_offset]; /* A */
+ }
+#endif
+
+ check(bi);
+ check(biexp);
+
+#ifdef CONFIG_BIGINT_SLIDING_WINDOW
+ for (j = i; j > 32; j /= 5) /* work out an optimum size */
+ window_size++;
+
+ /* work out the slide constants */
+ precompute_slide_window(ctx, window_size, bi);
+#else /* just one constant */
+ ctx->g = (bigint **)malloc(sizeof(bigint *));
+ ctx->g[0] = bi_clone(ctx, bi);
+ ctx->window = 1;
+ bi_permanent(ctx->g[0]);
+#endif
+
+ /* if sliding-window is off, then only one bit will be done at a time and
+ * will reduce to standard left-to-right exponentiation */
+ do
+ {
+ if (exp_bit_is_one(biexp, i))
+ {
+ int l = i-window_size+1;
+ int part_exp = 0;
+
+ if (l < 0) /* LSB of exponent will always be 1 */
+ l = 0;
+ else
+ {
+ while (exp_bit_is_one(biexp, l) == 0)
+ l++; /* go back up */
+ }
+
+ /* build up the section of the exponent */
+ for (j = i; j >= l; j--)
+ {
+ biR = bi_residue(ctx, bi_square(ctx, biR));
+ if (exp_bit_is_one(biexp, j))
+ part_exp++;
+
+ if (j != l)
+ part_exp <<= 1;
+ }
+
+ part_exp = (part_exp-1)/2; /* adjust for array */
+ biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp]));
+ i = l-1;
+ }
+ else /* square it */
+ {
+ biR = bi_residue(ctx, bi_square(ctx, biR));
+ i--;
+ }
+ } while (i >= 0);
+
+ /* cleanup */
+ for (i = 0; i < ctx->window; i++)
+ {
+ bi_depermanent(ctx->g[i]);
+ bi_free(ctx, ctx->g[i]);
+ }
+
+ free(ctx->g);
+ bi_free(ctx, bi);
+ bi_free(ctx, biexp);
+#if defined CONFIG_BIGINT_MONTGOMERY
+ return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */
+#else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */
+ return biR;
+#endif
+}
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * @brief Perform a modular exponentiation using a temporary modulus.
+ *
+ * We need this function to check the signatures of certificates. The modulus
+ * of this function is temporary as it's just used for authentication.
+ * @param ctx [in] The bigint session context.
+ * @param bi [in] The bigint to perform the exp/mod.
+ * @param bim [in] The temporary modulus.
+ * @param biexp [in] The bigint exponent.
+ * @see bi_set_mod().
+ */
+bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp)
+{
+ bigint *biR, *tmp_biR;
+
+ /* Set up a temporary bigint context and transfer what we need between
+ * them. We need to do this since we want to keep the original modulus
+ * which is already in this context. This operation is only called when
+ * doing peer verification, and so is not expensive :-) */
+ BI_CTX *tmp_ctx = bi_initialize();
+ bi_set_mod(tmp_ctx, bi_clone(tmp_ctx, bim), BIGINT_M_OFFSET);
+ tmp_biR = bi_mod_power(tmp_ctx,
+ bi_clone(tmp_ctx, bi),
+ bi_clone(tmp_ctx, biexp));
+ biR = bi_clone(ctx, tmp_biR);
+ bi_free(tmp_ctx, tmp_biR);
+ bi_free_mod(tmp_ctx, BIGINT_M_OFFSET);
+ bi_terminate(tmp_ctx);
+
+ bi_free(ctx, bi);
+ bi_free(ctx, bim);
+ bi_free(ctx, biexp);
+ return biR;
+}
+#endif
+/** @} */
diff --git a/gpxe/src/crypto/axtls/bigint.h b/gpxe/src/crypto/axtls/bigint.h
new file mode 100644
index 00000000..5a13c5ae
--- /dev/null
+++ b/gpxe/src/crypto/axtls/bigint.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright(C) 2006 Cameron Rich
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef BIGINT_HEADER
+#define BIGINT_HEADER
+
+#include "config.h"
+
+/* enable features based on a 'super-set' capbaility. */
+#if defined(CONFIG_SSL_FULL_MODE)
+#define CONFIG_SSL_ENABLE_CLIENT
+#define CONFIG_SSL_CERT_VERIFICATION
+#elif defined(CONFIG_SSL_ENABLE_CLIENT)
+#define CONFIG_SSL_CERT_VERIFICATION
+#endif
+
+#include "os_port.h"
+#include "bigint_impl.h"
+
+#ifndef CONFIG_BIGINT_CHECK_ON
+#define check(A) /**< disappears in normal production mode */
+#endif
+BI_CTX *bi_initialize(void);
+void bi_terminate(BI_CTX *ctx);
+void bi_permanent(bigint *bi);
+void bi_depermanent(bigint *bi);
+void bi_free(BI_CTX *ctx, bigint *bi);
+bigint *bi_copy(bigint *bi);
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi);
+void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size);
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len);
+bigint *int_to_bi(BI_CTX *ctx, comp i);
+
+/* the functions that actually do something interesting */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_subtract(BI_CTX *ctx, bigint *bia,
+ bigint *bib, int *is_negative);
+bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, int is_mod);
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp);
+bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp);
+int bi_compare(bigint *bia, bigint *bib);
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset);
+void bi_free_mod(BI_CTX *ctx, int mod_offset);
+
+#ifdef CONFIG_SSL_FULL_MODE
+void bi_print(const char *label, bigint *bi);
+bigint *bi_str_import(BI_CTX *ctx, const char *data);
+#endif
+
+/**
+ * @def bi_mod
+ * Find the residue of B. bi_set_mod() must be called before hand.
+ */
+#define bi_mod(A, B) bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1)
+
+/**
+ * bi_residue() is technically the same as bi_mod(), but it uses the
+ * appropriate reduction technique (which is bi_mod() when doing classical
+ * reduction).
+ */
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+#define bi_residue(A, B) bi_mont(A, B)
+bigint *bi_mont(BI_CTX *ctx, bigint *bixy);
+#elif defined(CONFIG_BIGINT_BARRETT)
+#define bi_residue(A, B) bi_barrett(A, B)
+bigint *bi_barrett(BI_CTX *ctx, bigint *bi);
+#else /* if defined(CONFIG_BIGINT_CLASSICAL) */
+#define bi_residue(A, B) bi_mod(A, B)
+#endif
+
+#ifdef CONFIG_BIGINT_SQUARE
+bigint *bi_square(BI_CTX *ctx, bigint *bi);
+#else
+#define bi_square(A, B) bi_multiply(A, bi_copy(B), B)
+#endif
+
+#endif
diff --git a/gpxe/src/crypto/axtls/bigint_impl.h b/gpxe/src/crypto/axtls/bigint_impl.h
new file mode 100644
index 00000000..762a7ccb
--- /dev/null
+++ b/gpxe/src/crypto/axtls/bigint_impl.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright(C) 2006 Cameron Rich
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef BIGINT_IMPL_HEADER
+#define BIGINT_IMPL_HEADER
+
+/* Maintain a number of precomputed variables when doing reduction */
+#define BIGINT_M_OFFSET 0 /**< Normal modulo offset. */
+#ifdef CONFIG_BIGINT_CRT
+#define BIGINT_P_OFFSET 1 /**< p modulo offset. */
+#define BIGINT_Q_OFFSET 2 /**< q module offset. */
+#define BIGINT_NUM_MODS 3 /**< The number of modulus constants used. */
+#else
+#define BIGINT_NUM_MODS 1
+#endif
+
+/* Architecture specific functions for big ints */
+#ifdef WIN32
+#define COMP_RADIX 4294967296i64
+#define COMP_BIG_MSB 0x8000000000000000i64
+#else
+#define COMP_RADIX 4294967296ULL /**< Max component + 1 */
+#define COMP_BIG_MSB 0x8000000000000000ULL /**< (Max dbl comp + 1)/ 2 */
+#endif
+#define COMP_BIT_SIZE 32 /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */
+
+typedef uint32_t comp; /**< A single precision component. */
+typedef uint64_t long_comp; /**< A double precision component. */
+typedef int64_t slong_comp; /**< A signed double precision component. */
+
+/**
+ * @struct _bigint
+ * @brief A big integer basic object
+ */
+struct _bigint
+{
+ struct _bigint* next; /**< The next bigint in the cache. */
+ short size; /**< The number of components in this bigint. */
+ short max_comps; /**< The heapsize allocated for this bigint */
+ int refs; /**< An internal reference count. */
+ comp* comps; /**< A ptr to the actual component data */
+};
+
+typedef struct _bigint bigint; /**< An alias for _bigint */
+
+/**
+ * Maintains the state of the cache, and a number of variables used in
+ * reduction.
+ */
+typedef struct /**< A big integer "session" context. */
+{
+ bigint *active_list; /**< Bigints currently used. */
+ bigint *free_list; /**< Bigints not used. */
+ bigint *bi_radix; /**< The radix used. */
+ bigint *bi_mod[BIGINT_NUM_MODS]; /**< modulus */
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ bigint *bi_RR_mod_m[BIGINT_NUM_MODS]; /**< R^2 mod m */
+ bigint *bi_R_mod_m[BIGINT_NUM_MODS]; /**< R mod m */
+ comp N0_dash[BIGINT_NUM_MODS];
+#elif defined(CONFIG_BIGINT_BARRETT)
+ bigint *bi_mu[BIGINT_NUM_MODS]; /**< Storage for mu */
+#endif
+ bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */
+ bigint **g; /**< Used by sliding-window. */
+ int window; /**< The size of the sliding window */
+ int active_count; /**< Number of active bigints. */
+ int free_count; /**< Number of free bigints. */
+
+#ifdef CONFIG_BIGINT_MONTGOMERY
+ uint8_t use_classical; /**< Use classical reduction. */
+#endif
+ uint8_t mod_offset; /**< The mod offset we are using */
+} BI_CTX;
+
+#ifndef WIN32
+#define max(a,b) ((a)>(b)?(a):(b)) /**< Find the maximum of 2 numbers. */
+#define min(a,b) ((a)<(b)?(a):(b)) /**< Find the minimum of 2 numbers. */
+#endif
+
+#define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */
+
+#define V1 v->comps[v->size-1] /**< v1 for division */
+#define V2 v->comps[v->size-2] /**< v2 for division */
+#define U(j) tmp_u->comps[tmp_u->size-j-1] /**< uj for division */
+#define Q(j) quotient->comps[quotient->size-j-1] /**< qj for division */
+
+#endif
diff --git a/gpxe/src/crypto/axtls/crypto.h b/gpxe/src/crypto/axtls/crypto.h
new file mode 100644
index 00000000..de1dbeb4
--- /dev/null
+++ b/gpxe/src/crypto/axtls/crypto.h
@@ -0,0 +1,298 @@
+/*
+ * Copyright(C) 2006 Cameron Rich
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/**
+ * @file crypto.h
+ */
+
+#ifndef HEADER_CRYPTO_H
+#define HEADER_CRYPTO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "bigint.h"
+
+/**************************************************************************
+ * AES declarations
+ **************************************************************************/
+
+#define AES_MAXROUNDS 14
+
+typedef struct aes_key_st
+{
+ uint16_t rounds;
+ uint16_t key_size;
+ uint32_t ks[(AES_MAXROUNDS+1)*8];
+ uint8_t iv[16];
+} AES_CTX;
+
+typedef enum
+{
+ AES_MODE_128,
+ AES_MODE_256
+} AES_MODE;
+
+void AES_set_key(AES_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, AES_MODE mode);
+void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg,
+ uint8_t *out, int length);
+void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length);
+void AES_convert_key(AES_CTX *ctx);
+
+/**************************************************************************
+ * RC4 declarations
+ **************************************************************************/
+
+typedef struct
+{
+ int x, y, m[256];
+} RC4_CTX;
+
+void RC4_setup(RC4_CTX *s, const uint8_t *key, int length);
+void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length);
+
+/**************************************************************************
+ * SHA1 declarations
+ **************************************************************************/
+
+#define SHA1_SIZE 20
+
+/*
+ * This structure will hold context information for the SHA-1
+ * hashing operation
+ */
+typedef struct
+{
+ uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */
+ uint32_t Length_Low; /* Message length in bits */
+ uint32_t Length_High; /* Message length in bits */
+ uint16_t Message_Block_Index; /* Index into message block array */
+ uint8_t Message_Block[64]; /* 512-bit message blocks */
+} SHA1_CTX;
+
+void SHA1Init(SHA1_CTX *);
+void SHA1Update(SHA1_CTX *, const uint8_t * msg, int len);
+void SHA1Final(SHA1_CTX *, uint8_t *digest);
+
+/**************************************************************************
+ * MD5 declarations
+ **************************************************************************/
+
+/* MD5 context. */
+
+#define MD5_SIZE 16
+
+typedef struct
+{
+ uint32_t state[4]; /* state (ABCD) */
+ uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ uint8_t buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init(MD5_CTX *);
+void MD5Update(MD5_CTX *, const uint8_t *msg, int len);
+void MD5Final(MD5_CTX *, uint8_t *digest);
+
+/**************************************************************************
+ * HMAC declarations
+ **************************************************************************/
+void hmac_md5(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest);
+void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest);
+
+/**************************************************************************
+ * RNG declarations
+ **************************************************************************/
+void RNG_initialize(const uint8_t *seed_buf, int size);
+void RNG_terminate(void);
+void get_random(int num_rand_bytes, uint8_t *rand_data);
+//void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
+
+#include <string.h>
+static inline void get_random_NZ(int num_rand_bytes, uint8_t *rand_data) {
+ memset ( rand_data, 0x01, num_rand_bytes );
+}
+
+/**************************************************************************
+ * RSA declarations
+ **************************************************************************/
+
+typedef struct
+{
+ bigint *m; /* modulus */
+ bigint *e; /* public exponent */
+ bigint *d; /* private exponent */
+#ifdef CONFIG_BIGINT_CRT
+ bigint *p; /* p as in m = pq */
+ bigint *q; /* q as in m = pq */
+ bigint *dP; /* d mod (p-1) */
+ bigint *dQ; /* d mod (q-1) */
+ bigint *qInv; /* q^-1 mod p */
+#endif
+ int num_octets;
+ bigint *sig_m; /* signature modulus */
+ BI_CTX *bi_ctx;
+} RSA_CTX;
+
+void RSA_priv_key_new(RSA_CTX **rsa_ctx,
+ const uint8_t *modulus, int mod_len,
+ const uint8_t *pub_exp, int pub_len,
+ const uint8_t *priv_exp, int priv_len
+#ifdef CONFIG_BIGINT_CRT
+ , const uint8_t *p, int p_len,
+ const uint8_t *q, int q_len,
+ const uint8_t *dP, int dP_len,
+ const uint8_t *dQ, int dQ_len,
+ const uint8_t *qInv, int qInv_len
+#endif
+ );
+void RSA_pub_key_new(RSA_CTX **rsa_ctx,
+ const uint8_t *modulus, int mod_len,
+ const uint8_t *pub_exp, int pub_len);
+void RSA_free(RSA_CTX *ctx);
+int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
+ int is_decryption);
+bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+bigint *RSA_raw_sign_verify(RSA_CTX *c, bigint *bi_msg);
+bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
+ bigint *modulus, bigint *pub_exp);
+bigint *RSA_public(const RSA_CTX *c, bigint *bi_msg);
+int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
+ uint8_t *out_data, int is_signing);
+void RSA_print(const RSA_CTX *ctx);
+#endif
+
+/**************************************************************************
+ * ASN1 declarations
+ **************************************************************************/
+#define X509_OK 0
+#define X509_NOT_OK -1
+#define X509_VFY_ERROR_NO_TRUSTED_CERT -2
+#define X509_VFY_ERROR_BAD_SIGNATURE -3
+#define X509_VFY_ERROR_NOT_YET_VALID -4
+#define X509_VFY_ERROR_EXPIRED -5
+#define X509_VFY_ERROR_SELF_SIGNED -6
+#define X509_VFY_ERROR_INVALID_CHAIN -7
+#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8
+#define X509_INVALID_PRIV_KEY -9
+
+/*
+ * The Distinguished Name
+ */
+#define X509_NUM_DN_TYPES 3
+#define X509_COMMON_NAME 0
+#define X509_ORGANIZATION 1
+#define X509_ORGANIZATIONAL_TYPE 2
+
+#define ASN1_INTEGER 0x02
+#define ASN1_BIT_STRING 0x03
+#define ASN1_OCTET_STRING 0x04
+#define ASN1_NULL 0x05
+#define ASN1_OID 0x06
+#define ASN1_PRINTABLE_STR 0x13
+#define ASN1_TELETEX_STR 0x14
+#define ASN1_IA5_STR 0x16
+#define ASN1_UTC_TIME 0x17
+#define ASN1_SEQUENCE 0x30
+#define ASN1_SET 0x31
+#define ASN1_IMPLICIT_TAG 0x80
+#define ASN1_EXPLICIT_TAG 0xa0
+
+#define SALT_SIZE 8
+
+struct _x509_ctx
+{
+ char *ca_cert_dn[X509_NUM_DN_TYPES];
+ char *cert_dn[X509_NUM_DN_TYPES];
+#if defined(_WIN32_WCE)
+ long not_before;
+ long not_after;
+#else
+ time_t not_before;
+ time_t not_after;
+#endif
+ uint8_t *signature;
+ uint16_t sig_len;
+ uint8_t sig_type;
+ RSA_CTX *rsa_ctx;
+ bigint *digest;
+ struct _x509_ctx *next;
+};
+
+typedef struct _x509_ctx X509_CTX;
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+typedef struct
+{
+ X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS];
+} CA_CERT_CTX;
+#endif
+
+int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx);
+int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type);
+int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type);
+int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object);
+int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx);
+void x509_free(X509_CTX *x509_ctx);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
+const uint8_t *x509_get_signature(const uint8_t *asn1_signature, int *len);
+#endif
+#ifdef CONFIG_SSL_FULL_MODE
+void x509_print(CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
+void x509_display_error(int error);
+#endif
+
+/**************************************************************************
+ * MISC declarations
+ **************************************************************************/
+
+extern const char * const unsupported_str;
+
+typedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int);
+typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest);
+
+typedef struct
+{
+ uint8_t *pre_data; /* include the ssl record bytes */
+ uint8_t *data; /* the regular ssl data */
+ int max_len;
+ int index;
+} BUF_MEM;
+
+BUF_MEM buf_new(void);
+void buf_grow(BUF_MEM *bm, int len);
+void buf_free(BUF_MEM *bm);
+int get_file(const char *filename, uint8_t **buf);
+
+#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG)
+void print_blob(const char *format, const uint8_t *data, int size, ...);
+#else
+ #define print_blob(...)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/gpxe/src/crypto/axtls/os_port.h b/gpxe/src/crypto/axtls/os_port.h
new file mode 100644
index 00000000..babdbfad
--- /dev/null
+++ b/gpxe/src/crypto/axtls/os_port.h
@@ -0,0 +1,61 @@
+/**
+ * @file os_port.h
+ *
+ * Trick the axtls code into building within our build environment.
+ */
+
+#ifndef HEADER_OS_PORT_H
+#define HEADER_OS_PORT_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include <byteswap.h>
+
+#define STDCALL
+#define EXP_FUNC
+#define TTY_FLUSH()
+
+/** We can't actually abort, since we are effectively a kernel... */
+#define abort() assert ( 0 )
+
+/** crypto_misc.c has a bad #ifdef */
+static inline void close ( int fd __unused ) {
+ /* Do nothing */
+}
+
+typedef void FILE;
+
+static inline FILE * fopen ( const char *filename __unused,
+ const char *mode __unused ) {
+ return NULL;
+}
+
+static inline int fseek ( FILE *stream __unused, long offset __unused,
+ int whence __unused ) {
+ return -1;
+}
+
+static inline long ftell ( FILE *stream __unused ) {
+ return -1;
+}
+
+static inline size_t fread ( void *ptr __unused, size_t size __unused,
+ size_t nmemb __unused, FILE *stream __unused ) {
+ return -1;
+}
+
+static inline int fclose ( FILE *stream __unused ) {
+ return -1;
+}
+
+#define CONFIG_SSL_CERT_VERIFICATION 1
+#define CONFIG_SSL_MAX_CERTS 1
+#define CONFIG_X509_MAX_CA_CERTS 1
+#define CONFIG_SSL_EXPIRY_TIME 24
+#define CONFIG_SSL_ENABLE_CLIENT 1
+#define CONFIG_BIGINT_CLASSICAL 1
+
+#endif
diff --git a/gpxe/src/crypto/axtls/rsa.c b/gpxe/src/crypto/axtls/rsa.c
new file mode 100644
index 00000000..389eda57
--- /dev/null
+++ b/gpxe/src/crypto/axtls/rsa.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright(C) 2006 Cameron Rich
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/**
+ * Implements the RSA public encryption algorithm. Uses the bigint library to
+ * perform its calculations.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include "crypto.h"
+
+#ifdef CONFIG_BIGINT_CRT
+static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi);
+#endif
+
+void RSA_priv_key_new(RSA_CTX **ctx,
+ const uint8_t *modulus, int mod_len,
+ const uint8_t *pub_exp, int pub_len,
+ const uint8_t *priv_exp, int priv_len
+#if CONFIG_BIGINT_CRT
+ , const uint8_t *p, int p_len,
+ const uint8_t *q, int q_len,
+ const uint8_t *dP, int dP_len,
+ const uint8_t *dQ, int dQ_len,
+ const uint8_t *qInv, int qInv_len
+#endif
+ )
+{
+ RSA_CTX *rsa_ctx;
+ BI_CTX *bi_ctx;
+ RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len);
+ rsa_ctx = *ctx;
+ bi_ctx = rsa_ctx->bi_ctx;
+ rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len);
+ bi_permanent(rsa_ctx->d);
+
+#ifdef CONFIG_BIGINT_CRT
+ rsa_ctx->p = bi_import(bi_ctx, p, p_len);
+ rsa_ctx->q = bi_import(bi_ctx, q, q_len);
+ rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len);
+ rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len);
+ rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len);
+ bi_permanent(rsa_ctx->dP);
+ bi_permanent(rsa_ctx->dQ);
+ bi_permanent(rsa_ctx->qInv);
+ bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET);
+ bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET);
+#endif
+}
+
+void RSA_pub_key_new(RSA_CTX **ctx,
+ const uint8_t *modulus, int mod_len,
+ const uint8_t *pub_exp, int pub_len)
+{
+ RSA_CTX *rsa_ctx;
+ BI_CTX *bi_ctx = bi_initialize();
+ *ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX));
+ rsa_ctx = *ctx;
+ rsa_ctx->bi_ctx = bi_ctx;
+ rsa_ctx->num_octets = (mod_len & 0xFFF0);
+ rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len);
+ bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET);
+ rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len);
+ bi_permanent(rsa_ctx->e);
+}
+
+/**
+ * Free up any RSA context resources.
+ */
+void RSA_free(RSA_CTX *rsa_ctx)
+{
+ BI_CTX *bi_ctx;
+ if (rsa_ctx == NULL) /* deal with ptrs that are null */
+ return;
+
+ bi_ctx = rsa_ctx->bi_ctx;
+
+ bi_depermanent(rsa_ctx->e);
+ bi_free(bi_ctx, rsa_ctx->e);
+ bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET);
+
+ if (rsa_ctx->d)
+ {
+ bi_depermanent(rsa_ctx->d);
+ bi_free(bi_ctx, rsa_ctx->d);
+#ifdef CONFIG_BIGINT_CRT
+ bi_depermanent(rsa_ctx->dP);
+ bi_depermanent(rsa_ctx->dQ);
+ bi_depermanent(rsa_ctx->qInv);
+ bi_free(bi_ctx, rsa_ctx->dP);
+ bi_free(bi_ctx, rsa_ctx->dQ);
+ bi_free(bi_ctx, rsa_ctx->qInv);
+ bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET);
+ bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET);
+#endif
+ }
+
+ bi_terminate(bi_ctx);
+ free(rsa_ctx);
+}
+
+/**
+ * @brief Use PKCS1.5 for decryption/verification.
+ * @param ctx [in] The context
+ * @param in_data [in] The data to encrypt (must be < modulus size-11)
+ * @param out_data [out] The encrypted data.
+ * @param is_decryption [in] Decryption or verify operation.
+ * @return The number of bytes that were originally encrypted. -1 on error.
+ * @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
+ */
+int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data,
+ uint8_t *out_data, int is_decryption)
+{
+ int byte_size = ctx->num_octets;
+ uint8_t *block;
+ int i, size;
+ bigint *decrypted_bi, *dat_bi;
+
+ memset(out_data, 0, byte_size); /* initialise */
+
+ /* decrypt */
+ dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size);
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ decrypted_bi = is_decryption ? /* decrypt or verify? */
+ RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi);
+#else /* always a decryption */
+ decrypted_bi = RSA_private(ctx, dat_bi);
+#endif
+
+ /* convert to a normal block */
+ block = (uint8_t *)malloc(byte_size);
+ bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size);
+
+ i = 10; /* start at the first possible non-padded byte */
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+ if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */
+ {
+ while (block[i++] == 0xff && i < byte_size);
+
+ if (block[i-2] != 0xff)
+ i = byte_size; /*ensure size is 0 */
+ }
+ else /* PKCS1.5 encryption padding is random */
+#endif
+ {
+ while (block[i++] && i < byte_size);
+ }
+ size = byte_size - i;
+
+ /* get only the bit we want */
+ if (size > 0)
+ memcpy(out_data, &block[i], size);
+
+ free(block);
+ return size ? size : -1;
+}
+
+/**
+ * Performs m = c^d mod n
+ */
+bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg)
+{
+#ifdef CONFIG_BIGINT_CRT
+ return bi_crt(c, bi_msg);
+#else
+ BI_CTX *ctx = c->bi_ctx;
+ ctx->mod_offset = BIGINT_M_OFFSET;
+ return bi_mod_power(ctx, bi_msg, c->d);
+#endif
+}
+
+#ifdef CONFIG_BIGINT_CRT
+/**
+ * Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
+ * This should really be in bigint.c (and was at one stage), but needs
+ * access to the RSA_CTX context...
+ */
+static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi)
+{
+ BI_CTX *ctx = rsa->bi_ctx;
+ bigint *m1, *m2, *h;
+
+ /* Montgomery has a condition the 0 < x, y < m and these products violate
+ * that condition. So disable Montgomery when using CRT */
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ ctx->use_classical = 1;
+#endif
+ ctx->mod_offset = BIGINT_P_OFFSET;
+ m1 = bi_mod_power(ctx, bi_copy(bi), rsa->dP);
+
+ ctx->mod_offset = BIGINT_Q_OFFSET;
+ m2 = bi_mod_power(ctx, bi, rsa->dQ);
+
+ h = bi_subtract(ctx, bi_add(ctx, m1, rsa->p), bi_copy(m2), NULL);
+ h = bi_multiply(ctx, h, rsa->qInv);
+ ctx->mod_offset = BIGINT_P_OFFSET;
+ h = bi_residue(ctx, h);
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ ctx->use_classical = 0; /* reset for any further operation */
+#endif
+ return bi_add(ctx, m2, bi_multiply(ctx, rsa->q, h));
+}
+#endif
+
+#ifdef CONFIG_SSL_FULL_MODE
+/**
+ * Used for diagnostics.
+ */
+void RSA_print(const RSA_CTX *rsa_ctx)
+{
+ if (rsa_ctx == NULL)
+ return;
+
+ printf("----------------- RSA DEBUG ----------------\n");
+ printf("Size:\t%d\n", rsa_ctx->num_octets);
+ bi_print("Modulus", rsa_ctx->m);
+ bi_print("Public Key", rsa_ctx->e);
+ bi_print("Private Key", rsa_ctx->d);
+}
+#endif
+
+#ifdef CONFIG_SSL_CERT_VERIFICATION
+/**
+ * Performs c = m^e mod n
+ */
+bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg)
+{
+ c->bi_ctx->mod_offset = BIGINT_M_OFFSET;
+ return bi_mod_power(c->bi_ctx, bi_msg, c->e);
+}
+
+/**
+ * Use PKCS1.5 for encryption/signing.
+ * see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
+ */
+int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
+ uint8_t *out_data, int is_signing)
+{
+ int byte_size = ctx->num_octets;
+ int num_pads_needed = byte_size-in_len-3;
+ bigint *dat_bi, *encrypt_bi;
+
+ /* note: in_len+11 must be > byte_size */
+ out_data[0] = 0; /* ensure encryption block is < modulus */
+
+ if (is_signing)
+ {
+ out_data[1] = 1; /* PKCS1.5 signing pads with "0xff"'s */
+ memset(&out_data[2], 0xff, num_pads_needed);
+ }
+ else /* randomize the encryption padding with non-zero bytes */
+ {
+ out_data[1] = 2;
+ get_random_NZ(num_pads_needed, &out_data[2]);
+ }
+
+ out_data[2+num_pads_needed] = 0;
+ memcpy(&out_data[3+num_pads_needed], in_data, in_len);
+
+ /* now encrypt it */
+ dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size);
+ encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) :
+ RSA_public(ctx, dat_bi);
+ bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size);
+ return byte_size;
+}
+
+#if 0
+/**
+ * Take a signature and decrypt it.
+ */
+bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
+ bigint *modulus, bigint *pub_exp)
+{
+ uint8_t *block;
+ int i, size;
+ bigint *decrypted_bi, *dat_bi;
+ bigint *bir = NULL;
+
+ block = (uint8_t *)malloc(sig_len);
+
+ /* decrypt */
+ dat_bi = bi_import(ctx, sig, sig_len);
+ ctx->mod_offset = BIGINT_M_OFFSET;
+
+ /* convert to a normal block */
+ decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);
+
+ bi_export(ctx, decrypted_bi, block, sig_len);
+ ctx->mod_offset = BIGINT_M_OFFSET;
+
+ i = 10; /* start at the first possible non-padded byte */
+ while (block[i++] && i < sig_len);
+ size = sig_len - i;
+
+ /* get only the bit we want */
+ if (size > 0)
+ {
+ int len;
+ const uint8_t *sig_ptr = x509_get_signature(&block[i], &len);
+
+ if (sig_ptr)
+ {
+ bir = bi_import(ctx, sig_ptr, len);
+ }
+ }
+
+ free(block);
+ return bir;
+}
+#endif
+
+#endif /* CONFIG_SSL_CERT_VERIFICATION */
diff --git a/gpxe/src/crypto/axtls/sha1.c b/gpxe/src/crypto/axtls/sha1.c
new file mode 100644
index 00000000..9a42801f
--- /dev/null
+++ b/gpxe/src/crypto/axtls/sha1.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright(C) 2006 Cameron Rich
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/**
+ * SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995.
+ * This code was originally taken from RFC3174
+ */
+
+#include <string.h>
+#include "crypto.h"
+
+/*
+ * Define the SHA1 circular left shift macro
+ */
+#define SHA1CircularShift(bits,word) \
+ (((word) << (bits)) | ((word) >> (32-(bits))))
+
+/* ----- static functions ----- */
+static void SHA1PadMessage(SHA1_CTX *ctx);
+static void SHA1ProcessMessageBlock(SHA1_CTX *ctx);
+
+/**
+ * Initialize the SHA1 context
+ */
+void SHA1Init(SHA1_CTX *ctx)
+{
+ ctx->Length_Low = 0;
+ ctx->Length_High = 0;
+ ctx->Message_Block_Index = 0;
+ ctx->Intermediate_Hash[0] = 0x67452301;
+ ctx->Intermediate_Hash[1] = 0xEFCDAB89;
+ ctx->Intermediate_Hash[2] = 0x98BADCFE;
+ ctx->Intermediate_Hash[3] = 0x10325476;
+ ctx->Intermediate_Hash[4] = 0xC3D2E1F0;
+}
+
+/**
+ * Accepts an array of octets as the next portion of the message.
+ */
+void SHA1Update(SHA1_CTX *ctx, const uint8_t *msg, int len)
+{
+ while (len--)
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF);
+
+ ctx->Length_Low += 8;
+ if (ctx->Length_Low == 0)
+ {
+ ctx->Length_High++;
+ }
+
+ if (ctx->Message_Block_Index == 64)
+ {
+ SHA1ProcessMessageBlock(ctx);
+ }
+
+ msg++;
+ }
+}
+
+/**
+ * Return the 160-bit message digest into the user's array
+ */
+void SHA1Final(SHA1_CTX *ctx, uint8_t *digest)
+{
+ int i;
+
+ SHA1PadMessage(ctx);
+ memset(ctx->Message_Block, 0, 64);
+ ctx->Length_Low = 0; /* and clear length */
+ ctx->Length_High = 0;
+
+ for (i = 0; i < SHA1_SIZE; i++)
+ {
+ digest[i] = ctx->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) );
+ }
+}
+
+/**
+ * Process the next 512 bits of the message stored in the array.
+ */
+static void SHA1ProcessMessageBlock(SHA1_CTX *ctx)
+{
+ const uint32_t K[] = { /* Constants defined in SHA-1 */
+ 0x5A827999,
+ 0x6ED9EBA1,
+ 0x8F1BBCDC,
+ 0xCA62C1D6
+ };
+ int t; /* Loop counter */
+ uint32_t temp; /* Temporary word value */
+ uint32_t W[80]; /* Word sequence */
+ uint32_t A, B, C, D, E; /* Word buffers */
+
+ /*
+ * Initialize the first 16 words in the array W
+ */
+ for (t = 0; t < 16; t++)
+ {
+ W[t] = ctx->Message_Block[t * 4] << 24;
+ W[t] |= ctx->Message_Block[t * 4 + 1] << 16;
+ W[t] |= ctx->Message_Block[t * 4 + 2] << 8;
+ W[t] |= ctx->Message_Block[t * 4 + 3];
+ }
+
+ for (t = 16; t < 80; t++)
+ {
+ W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+ }
+
+ A = ctx->Intermediate_Hash[0];
+ B = ctx->Intermediate_Hash[1];
+ C = ctx->Intermediate_Hash[2];
+ D = ctx->Intermediate_Hash[3];
+ E = ctx->Intermediate_Hash[4];
+
+ for (t = 0; t < 20; t++)
+ {
+ temp = SHA1CircularShift(5,A) +
+ ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+
+ B = A;
+ A = temp;
+ }
+
+ for (t = 20; t < 40; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 40; t < 60; t++)
+ {
+ temp = SHA1CircularShift(5,A) +
+ ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 60; t < 80; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ ctx->Intermediate_Hash[0] += A;
+ ctx->Intermediate_Hash[1] += B;
+ ctx->Intermediate_Hash[2] += C;
+ ctx->Intermediate_Hash[3] += D;
+ ctx->Intermediate_Hash[4] += E;
+ ctx->Message_Block_Index = 0;
+}
+
+/*
+ * According to the standard, the message must be padded to an even
+ * 512 bits. The first padding bit must be a '1'. The last 64
+ * bits represent the length of the original message. All bits in
+ * between should be 0. This function will pad the message
+ * according to those rules by filling the Message_Block array
+ * accordingly. It will also call the ProcessMessageBlock function
+ * provided appropriately. When it returns, it can be assumed that
+ * the message digest has been computed.
+ *
+ * @param ctx [in, out] The SHA1 context
+ */
+static void SHA1PadMessage(SHA1_CTX *ctx)
+{
+ /*
+ * Check to see if the current message block is too small to hold
+ * the initial padding bits and length. If so, we will pad the
+ * block, process it, and then continue padding into a second
+ * block.
+ */
+ if (ctx->Message_Block_Index > 55)
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
+ while(ctx->Message_Block_Index < 64)
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+ }
+
+ SHA1ProcessMessageBlock(ctx);
+
+ while (ctx->Message_Block_Index < 56)
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+ }
+ }
+ else
+ {
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
+ while(ctx->Message_Block_Index < 56)
+ {
+
+ ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+ }
+ }
+
+ /*
+ * Store the message length as the last 8 octets
+ */
+ ctx->Message_Block[56] = ctx->Length_High >> 24;
+ ctx->Message_Block[57] = ctx->Length_High >> 16;
+ ctx->Message_Block[58] = ctx->Length_High >> 8;
+ ctx->Message_Block[59] = ctx->Length_High;
+ ctx->Message_Block[60] = ctx->Length_Low >> 24;
+ ctx->Message_Block[61] = ctx->Length_Low >> 16;
+ ctx->Message_Block[62] = ctx->Length_Low >> 8;
+ ctx->Message_Block[63] = ctx->Length_Low;
+ SHA1ProcessMessageBlock(ctx);
+}
diff --git a/gpxe/src/crypto/axtls_aes.c b/gpxe/src/crypto/axtls_aes.c
new file mode 100644
index 00000000..ac7e921d
--- /dev/null
+++ b/gpxe/src/crypto/axtls_aes.c
@@ -0,0 +1,54 @@
+#include "crypto/axtls/crypto.h"
+#include <string.h>
+#include <errno.h>
+#include <gpxe/crypto.h>
+#include <gpxe/aes.h>
+
+static int aes_setkey ( void *ctx, const void *key, size_t keylen ) {
+ AES_CTX *aesctx = ctx;
+ AES_MODE mode;
+
+ switch ( keylen ) {
+ case ( 128 / 8 ):
+ mode = AES_MODE_128;
+ break;
+ case ( 256 / 8 ):
+ mode = AES_MODE_256;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ AES_set_key ( aesctx, key, aesctx->iv, mode );
+ return 0;
+}
+
+static void aes_setiv ( void *ctx, const void *iv ) {
+ AES_CTX *aesctx = ctx;
+
+ memcpy ( aesctx->iv, iv, sizeof ( aesctx->iv ) );
+}
+
+static void aes_encrypt ( void *ctx, const void *data, void *dst,
+ size_t len ) {
+ AES_CTX *aesctx = ctx;
+
+ AES_cbc_encrypt ( aesctx, data, dst, len );
+}
+
+static void aes_decrypt ( void *ctx, const void *data, void *dst,
+ size_t len ) {
+ AES_CTX *aesctx = ctx;
+
+ AES_cbc_decrypt ( aesctx, data, dst, len );
+}
+
+struct crypto_algorithm aes_algorithm = {
+ .name = "aes",
+ .ctxsize = sizeof ( AES_CTX ),
+ .blocksize = 16,
+ .setkey = aes_setkey,
+ .setiv = aes_setiv,
+ .encode = aes_encrypt,
+ .decode = aes_decrypt,
+};
diff --git a/gpxe/src/crypto/axtls_sha1.c b/gpxe/src/crypto/axtls_sha1.c
new file mode 100644
index 00000000..62ff878a
--- /dev/null
+++ b/gpxe/src/crypto/axtls_sha1.c
@@ -0,0 +1,26 @@
+#include "crypto/axtls/crypto.h"
+#include <gpxe/crypto.h>
+#include <gpxe/sha1.h>
+
+static void sha1_init ( void *ctx ) {
+ SHA1Init ( ctx );
+}
+
+static void sha1_update ( void *ctx, const void *data, void *dst __unused,
+ size_t len ) {
+ SHA1Update ( ctx, data, len );
+}
+
+static void sha1_final ( void *ctx, void *out ) {
+ SHA1Final ( ctx, out );
+}
+
+struct crypto_algorithm sha1_algorithm = {
+ .name = "sha1",
+ .ctxsize = SHA1_CTX_SIZE,
+ .blocksize = 64,
+ .digestsize = SHA1_DIGEST_SIZE,
+ .init = sha1_init,
+ .encode = sha1_update,
+ .final = sha1_final,
+};
diff --git a/gpxe/src/crypto/chap.c b/gpxe/src/crypto/chap.c
new file mode 100644
index 00000000..13b8fda2
--- /dev/null
+++ b/gpxe/src/crypto/chap.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <gpxe/crypto.h>
+#include <gpxe/chap.h>
+
+/** @file
+ *
+ * CHAP protocol
+ *
+ */
+
+/**
+ * Initialise CHAP challenge/response
+ *
+ * @v chap CHAP challenge/response
+ * @v digest Digest algorithm to use
+ * @ret rc Return status code
+ *
+ * Initialises a CHAP challenge/response structure. This routine
+ * allocates memory, and so may fail. The allocated memory must
+ * eventually be freed by a call to chap_finish().
+ */
+int chap_init ( struct chap_challenge *chap,
+ struct crypto_algorithm *digest ) {
+ size_t state_len;
+ void *state;
+
+ assert ( chap->digest == NULL );
+ assert ( chap->digest_context == NULL );
+ assert ( chap->response == NULL );
+
+ DBG ( "CHAP %p initialising with %s digest\n", chap, digest->name );
+
+ state_len = ( digest->ctxsize + digest->digestsize );
+ state = malloc ( state_len );
+ if ( ! state ) {
+ DBG ( "CHAP %p could not allocate %zd bytes for state\n",
+ chap, state_len );
+ return -ENOMEM;
+ }
+
+ chap->digest = digest;
+ chap->digest_context = state;
+ chap->response = ( state + digest->ctxsize );
+ chap->response_len = digest->digestsize;
+ digest_init ( chap->digest, chap->digest_context );
+ return 0;
+}
+
+/**
+ * Add data to the CHAP challenge
+ *
+ * @v chap CHAP challenge/response
+ * @v data Data to add
+ * @v len Length of data to add
+ */
+void chap_update ( struct chap_challenge *chap, const void *data,
+ size_t len ) {
+ assert ( chap->digest != NULL );
+ assert ( chap->digest_context != NULL );
+
+ if ( ! chap->digest )
+ return;
+
+ digest_update ( chap->digest, chap->digest_context, data, len );
+}
+
+/**
+ * Respond to the CHAP challenge
+ *
+ * @v chap CHAP challenge/response
+ *
+ * Calculates the final CHAP response value, and places it in @c
+ * chap->response, with a length of @c chap->response_len.
+ */
+void chap_respond ( struct chap_challenge *chap ) {
+ assert ( chap->digest != NULL );
+ assert ( chap->digest_context != NULL );
+ assert ( chap->response != NULL );
+
+ DBG ( "CHAP %p responding to challenge\n", chap );
+
+ if ( ! chap->digest )
+ return;
+
+ digest_final ( chap->digest, chap->digest_context, chap->response );
+}
+
+/**
+ * Free resources used by a CHAP challenge/response
+ *
+ * @v chap CHAP challenge/response
+ */
+void chap_finish ( struct chap_challenge *chap ) {
+ void *state = chap->digest_context;
+
+ DBG ( "CHAP %p finished\n", chap );
+
+ free ( state );
+ memset ( chap, 0, sizeof ( *chap ) );
+}
diff --git a/gpxe/src/crypto/cipher.c b/gpxe/src/crypto/cipher.c
new file mode 100644
index 00000000..9c392009
--- /dev/null
+++ b/gpxe/src/crypto/cipher.c
@@ -0,0 +1,24 @@
+#include <stdint.h>
+#include <errno.h>
+#include <gpxe/crypto.h>
+
+int cipher_encrypt ( struct crypto_algorithm *crypto,
+ void *ctx, const void *src, void *dst,
+ size_t len ) {
+ if ( ( len & ( crypto->blocksize - 1 ) ) ) {
+ return -EINVAL;
+ }
+ crypto->encode ( ctx, src, dst, len );
+ return 0;
+}
+
+int cipher_decrypt ( struct crypto_algorithm *crypto,
+ void *ctx, const void *src, void *dst,
+ size_t len ) {
+ if ( ( len & ( crypto->blocksize - 1 ) ) ) {
+ return -EINVAL;
+ }
+ crypto->decode ( ctx, src, dst, len );
+ return 0;
+}
+
diff --git a/gpxe/src/crypto/cryptoLayer.h b/gpxe/src/crypto/cryptoLayer.h
new file mode 100644
index 00000000..28ce97bc
--- /dev/null
+++ b/gpxe/src/crypto/cryptoLayer.h
@@ -0,0 +1,120 @@
+#ifndef _MATRIXSSL_CRYPTOLAYER_H
+#define _MATRIXSSL_CRYPTOLAYER_H
+
+/** @file
+ *
+ * Compatibility layer for MatrixSSL
+ *
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <gpxe/bitops.h>
+#include <gpxe/crypto.h>
+
+/* Drag in pscrypto.h */
+typedef uint64_t ulong64;
+typedef void psPool_t;
+#define SMALL_CODE
+#define USE_INT64
+#define USE_RSA
+#define USE_RSA_PUBLIC_ENCRYPT
+#define CRYPT
+#include "matrixssl/pscrypto.h"
+#define SMALL_CODE
+#undef CLEAN_STACK
+
+#define sslAssert( ... ) assert ( __VA_ARGS__ )
+
+static inline __attribute__ (( always_inline )) void * __malloc
+psMalloc ( psPool_t *pool __unused, size_t len ) {
+ return malloc ( len );
+}
+
+static inline __attribute__ (( always_inline )) void *
+psRealloc ( void *ptr, size_t len ) {
+ return realloc ( ptr, len );
+}
+
+static inline __attribute__ (( always_inline )) void psFree ( void *ptr ) {
+ free ( ptr );
+}
+
+#define matrixStrDebugMsg( ... ) DBG ( __VA_ARGS__ )
+#define matrixIntDebugMsg( ... ) DBG ( __VA_ARGS__ )
+
+/* Use our standard cpu_to_leXX etc. macros */
+
+#undef LOAD32L
+#define LOAD32L( cpu32, ptr ) do { \
+ uint32_t *le32 = ( ( uint32_t * ) ptr ); \
+ cpu32 = le32_to_cpu ( *le32 ); \
+ } while ( 0 )
+
+#undef LOAD32H
+#define LOAD32H( cpu32, ptr ) do { \
+ uint32_t *be32 = ( ( uint32_t * ) ptr ); \
+ cpu32 = be32_to_cpu ( *be32 ); \
+ } while ( 0 )
+
+#undef LOAD64L
+#define LOAD64L( cpu64, ptr ) do { \
+ uint64_t *le64 = ( ( uint64_t * ) ptr ); \
+ cpu64 = le64_to_cpu ( *le64 ); \
+ } while ( 0 )
+
+#undef LOAD64H
+#define LOAD64H( cpu64, ptr ) do { \
+ uint64_t *be64 = ( ( uint64_t * ) ptr ); \
+ cpu64 = be64_to_cpu ( *be64 ); \
+ } while ( 0 )
+
+#undef STORE32L
+#define STORE32L( cpu32, ptr ) do { \
+ uint32_t *le32 = ( ( uint32_t * ) ptr ); \
+ *le32 = cpu_to_le32 ( cpu32 ); \
+ } while ( 0 )
+
+#undef STORE32H
+#define STORE32H( cpu32, ptr ) do { \
+ uint32_t *be32 = ( ( uint32_t * ) ptr ); \
+ *be32 = cpu_to_be32 ( cpu32 ); \
+ } while ( 0 )
+
+#undef STORE64L
+#define STORE64L( cpu64, ptr ) do { \
+ uint64_t *le64 = ( ( uint64_t * ) ptr ); \
+ *le64 = cpu_to_le64 ( cpu64 ); \
+ } while ( 0 )
+
+#undef STORE64H
+#define STORE64H( cpu64, ptr ) do { \
+ uint64_t *be64 = ( ( uint64_t * ) ptr ); \
+ *be64 = cpu_to_be64 ( cpu64 ); \
+ } while ( 0 )
+
+/* Use rolXX etc. from bitops.h */
+
+#undef ROL
+#define ROL( data, rotation ) rol32 ( (data), (rotation) )
+#undef ROLc
+#define ROLc( data, rotation ) rol32 ( (data), (rotation) )
+#undef ROR
+#define ROR( data, rotation ) ror32 ( (data), (rotation) )
+#undef RORc
+#define RORc( data, rotation ) ror32 ( (data), (rotation) )
+#undef ROL64
+#define ROL64( data, rotation ) rol64 ( (data), (rotation) )
+#undef ROL64c
+#define ROL64c( data, rotation ) rol64 ( (data), (rotation) )
+#undef ROR64
+#define ROR64( data, rotation ) ror64 ( (data), (rotation) )
+#undef ROR64c
+#define ROR64c( data, rotation ) ror64 ( (data), (rotation) )
+
+#endif /* _MATRIXSSL_CRYPTOLAYER_H */
diff --git a/gpxe/src/crypto/crypto_null.c b/gpxe/src/crypto/crypto_null.c
new file mode 100644
index 00000000..120ef0a6
--- /dev/null
+++ b/gpxe/src/crypto/crypto_null.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007 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
+ *
+ * Null crypto algorithm
+ */
+
+#include <string.h>
+#include <gpxe/crypto.h>
+
+static void null_init ( void *ctx __unused ) {
+ /* Do nothing */
+}
+
+static int null_setkey ( void *ctx __unused, const void *key __unused,
+ size_t keylen __unused ) {
+ /* Do nothing */
+ return 0;
+}
+
+static void null_setiv ( void *ctx __unused, const void *iv __unused ) {
+ /* Do nothing */
+}
+
+static void null_encode ( void *ctx __unused, const void *src,
+ void *dst, size_t len ) {
+ if ( dst )
+ memcpy ( dst, src, len );
+}
+
+static void null_decode ( void *ctx __unused, const void *src,
+ void *dst, size_t len ) {
+ if ( dst )
+ memcpy ( dst, src, len );
+}
+
+static void null_final ( void *ctx __unused, void *out __unused ) {
+ /* Do nothing */
+}
+
+struct crypto_algorithm crypto_null = {
+ .name = "null",
+ .ctxsize = 0,
+ .blocksize = 1,
+ .digestsize = 0,
+ .init = null_init,
+ .setkey = null_setkey,
+ .setiv = null_setiv,
+ .encode = null_encode,
+ .decode = null_decode,
+ .final = null_final,
+};
diff --git a/gpxe/src/crypto/framework.c b/gpxe/src/crypto/framework.c
new file mode 100644
index 00000000..0da2cbe3
--- /dev/null
+++ b/gpxe/src/crypto/framework.c
@@ -0,0 +1,86 @@
+/* mcb - this file breaks the build process; temporarily deactivating */
+#if 0
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "ssl.h"
+
+int main(int argc, char *argv[])
+{
+ SSL_t ssl;
+ int sockfd, portno, rc;
+ struct sockaddr_in serv_addr;
+ struct hostent *server;
+
+ portno = 443;
+ sockfd = socket(AF_INET,SOCK_STREAM,0);
+ if(sockfd<0){
+ fprintf(stderr,"Error creating socket\n");
+ exit(sockfd);
+ }
+
+ server = gethostbyname(argv[1]);
+ if(server==NULL){
+ fprintf(stderr,"Error looking up host %s\n",argv[1]);
+ exit(1);
+ }
+
+ /**
+ *matrixSslOpen()
+ *matrixSslReadKeys()
+ **/
+ printf("Calling CreateSSLHello()\n");
+ rc = CreateSSLHello(&ssl);
+ printf("Finished calling CreateSSLHello()\n");
+
+ bzero((char *) &serv_addr, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ bcopy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr,server->h_length);
+ serv_addr.sin_port = htons(portno);
+ if(connect(sockfd,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
+ fprintf(stderr,"ERROR connecting to server\n");
+ exit(1);
+ }
+
+ PrintSSLPacket(&ssl);
+
+ printf("Write ssl.buffer\n");
+ write(sockfd,ssl.buffer,ssl.length);
+ printf("Finished writing\n");
+ ssl.length = read(sockfd,ssl.buffer,ssl.max_size);
+ ReadSSLHello(&ssl);
+
+ /**
+ *matrixSslNewSession()
+ *matrixSslSetCetValidator()
+ *encodeSslHandshake()
+
+ *write handshake buffer
+
+ *readSslResponse() <-+
+ |
+ *read return code |-- similar/same function??
+ |
+ *sslEncode() |
+ *sslDecode() <-------+
+
+ *encodeSslCloseAlert()
+
+ *write close alert buffer
+ **/
+ close(sockfd);
+
+ /**
+ *sslClose()
+ * -free connection
+ * -free keys
+ * -close pki interface
+ **/
+
+ return 0;
+}
+
+#endif
diff --git a/gpxe/src/crypto/hmac.c b/gpxe/src/crypto/hmac.c
new file mode 100644
index 00000000..6884bde9
--- /dev/null
+++ b/gpxe/src/crypto/hmac.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2007 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
+ *
+ * Keyed-Hashing for Message Authentication
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <gpxe/crypto.h>
+#include <gpxe/hmac.h>
+
+/**
+ * Reduce HMAC key length
+ *
+ * @v digest Digest algorithm to use
+ * @v digest_ctx Digest context
+ * @v key Key
+ * @v key_len Length of key
+ */
+static void hmac_reduce_key ( struct crypto_algorithm *digest,
+ void *key, size_t *key_len ) {
+ uint8_t digest_ctx[digest->ctxsize];
+
+ digest_init ( digest, digest_ctx );
+ digest_update ( digest, digest_ctx, key, *key_len );
+ digest_final ( digest, digest_ctx, key );
+ *key_len = digest->digestsize;
+}
+
+/**
+ * Initialise HMAC
+ *
+ * @v digest Digest algorithm to use
+ * @v digest_ctx Digest context
+ * @v key Key
+ * @v key_len Length of key
+ *
+ * The length of the key should be less than the block size of the
+ * digest algorithm being used. (If the key length is greater, it
+ * will be replaced with its own digest, and key_len will be updated
+ * accordingly).
+ */
+void hmac_init ( struct crypto_algorithm *digest, void *digest_ctx,
+ void *key, size_t *key_len ) {
+ unsigned char k_ipad[digest->blocksize];
+ unsigned int i;
+
+ /* Reduce key if necessary */
+ if ( *key_len > sizeof ( k_ipad ) )
+ hmac_reduce_key ( digest, key, key_len );
+
+ /* Construct input pad */
+ memset ( k_ipad, 0, sizeof ( k_ipad ) );
+ memcpy ( k_ipad, key, *key_len );
+ for ( i = 0 ; i < sizeof ( k_ipad ) ; i++ ) {
+ k_ipad[i] ^= 0x36;
+ }
+
+ /* Start inner hash */
+ digest_init ( digest, digest_ctx );
+ digest_update ( digest, digest_ctx, k_ipad, sizeof ( k_ipad ) );
+}
+
+/**
+ * Finalise HMAC
+ *
+ * @v digest Digest algorithm to use
+ * @v digest_ctx Digest context
+ * @v key Key
+ * @v key_len Length of key
+ * @v hmac HMAC digest to fill in
+ *
+ * The length of the key should be less than the block size of the
+ * digest algorithm being used. (If the key length is greater, it
+ * will be replaced with its own digest, and key_len will be updated
+ * accordingly).
+ */
+void hmac_final ( struct crypto_algorithm *digest, void *digest_ctx,
+ void *key, size_t *key_len, void *hmac ) {
+ unsigned char k_opad[digest->blocksize];
+ unsigned int i;
+
+ /* Reduce key if necessary */
+ if ( *key_len > sizeof ( k_opad ) )
+ hmac_reduce_key ( digest, key, key_len );
+
+ /* Construct output pad */
+ memset ( k_opad, 0, sizeof ( k_opad ) );
+ memcpy ( k_opad, key, *key_len );
+ for ( i = 0 ; i < sizeof ( k_opad ) ; i++ ) {
+ k_opad[i] ^= 0x5c;
+ }
+
+ /* Finish inner hash */
+ digest_final ( digest, digest_ctx, hmac );
+
+ /* Perform outer hash */
+ digest_init ( digest, digest_ctx );
+ digest_update ( digest, digest_ctx, k_opad, sizeof ( k_opad ) );
+ digest_update ( digest, digest_ctx, hmac, digest->digestsize );
+ digest_final ( digest, digest_ctx, hmac );
+}
diff --git a/gpxe/src/crypto/matrixssl/mpi.h b/gpxe/src/crypto/matrixssl/mpi.h
new file mode 100644
index 00000000..bb2c9c57
--- /dev/null
+++ b/gpxe/src/crypto/matrixssl/mpi.h
@@ -0,0 +1,487 @@
+/*
+ * mpi.h
+ * Release $Name$
+ *
+ * multiple-precision integer library
+ */
+/*
+ * Copyright (c) PeerSec Networks, 2002-2006. All Rights Reserved.
+ * The latest version of this code is available at http://www.matrixssl.org
+ *
+ * This software is open source; 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 General Public License does NOT permit incorporating this software
+ * into proprietary programs. If you are unable to comply with the GPL, a
+ * commercial license for this software may be purchased from PeerSec Networks
+ * at http://www.peersec.com
+ *
+ * This program is distributed in 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/******************************************************************************/
+
+#ifndef _h_MPI
+#define _h_MPI
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+
+#undef MIN
+#define MIN(x,y) ((x)<(y)?(x):(y))
+#undef MAX
+#define MAX(x,y) ((x)>(y)?(x):(y))
+
+#ifdef __cplusplus
+extern "C" {
+
+
+/*
+ C++ compilers don't like assigning void * to mp_digit *
+ */
+#define OPT_CAST(x) (x *)
+
+#else
+
+/*
+ C on the other hand doesn't care
+ */
+#define OPT_CAST(x)
+
+#endif /* __cplusplus */
+
+/******************************************************************************/
+/*
+ some default configurations.
+
+ A "mp_digit" must be able to hold DIGIT_BIT + 1 bits
+ A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits
+
+ At the very least a mp_digit must be able to hold 7 bits
+ [any size beyond that is ok provided it doesn't overflow the data type]
+ */
+#ifdef MP_8BIT
+ typedef unsigned char mp_digit;
+ typedef unsigned short mp_word;
+#elif defined(MP_16BIT)
+ typedef unsigned short mp_digit;
+ typedef unsigned long mp_word;
+#elif defined(MP_64BIT)
+/*
+ for GCC only on supported platforms
+ */
+ #ifndef CRYPT
+ typedef unsigned long long ulong64;
+ typedef signed long long long64;
+ #endif /* CRYPT */
+
+ typedef ulong64 mp_digit;
+ typedef unsigned long mp_word __attribute__ ((mode(TI)));
+
+ #define DIGIT_BIT 60
+#else /* MP_8BIT */
+/*
+ this is the default case, 28-bit digits
+ */
+ #ifndef CRYPT
+ #if defined(_MSC_VER) || defined(__BORLANDC__)
+ typedef unsigned __int64 ulong64;
+ typedef signed __int64 long64;
+ #else
+ typedef unsigned long long ulong64;
+ typedef signed long long long64;
+ #endif
+ #endif /* CRYPT */
+
+ typedef unsigned long mp_digit;
+ typedef ulong64 mp_word;
+
+ #ifdef MP_31BIT
+/*
+ this is an extension that uses 31-bit digits
+ */
+ #define DIGIT_BIT 31
+ #else /* MP_31BIT */
+/*
+ default case is 28-bit digits, defines MP_28BIT as a handy macro to test
+ */
+ #define DIGIT_BIT 28
+ #define MP_28BIT
+ #endif /* MP_31BIT */
+#endif /* MP_8BIT */
+
+/*
+ otherwise the bits per digit is calculated automatically from the size of
+ a mp_digit
+ */
+#ifndef DIGIT_BIT
+ #define DIGIT_BIT ((int32)((CHAR_BIT * sizeof(mp_digit) - 1))) /* bits per digit */
+#endif /* DIGIT_BIT */
+
+#define MP_DIGIT_BIT DIGIT_BIT
+#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
+#define MP_DIGIT_MAX MP_MASK
+
+/******************************************************************************/
+/*
+ equalities
+ */
+#define MP_LT -1 /* less than */
+#define MP_EQ 0 /* equal to */
+#define MP_GT 1 /* greater than */
+
+#define MP_ZPOS 0 /* positive integer */
+#define MP_NEG 1 /* negative */
+
+#define MP_OKAY 0 /* ok result */
+#define MP_MEM -2 /* out of mem */
+#define MP_VAL -3 /* invalid input */
+#define MP_RANGE MP_VAL
+
+#define MP_YES 1 /* yes response */
+#define MP_NO 0 /* no response */
+
+typedef int32 mp_err;
+
+/******************************************************************************/
+/*
+ various build options
+ */
+#define MP_PREC 64 /* default digits of precision */
+
+/*
+ define this to use lower memory usage routines (exptmods mostly)
+ */
+#define MP_LOW_MEM
+
+/*
+ size of comba arrays, should be at least
+ 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2)
+ */
+#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
+
+typedef struct {
+ int32 used, alloc, sign;
+ mp_digit *dp;
+} mp_int;
+
+#define USED(m) ((m)->used)
+#define DIGIT(m,k) ((m)->dp[(k)])
+#define SIGN(m) ((m)->sign)
+
+/******************************************************************************/
+/*
+ init and deinit bignum functions
+ */
+
+/*
+ init a bignum
+ */
+extern int32 mp_init(psPool_t *pool, mp_int *a);
+
+/*
+ free a bignum
+ */
+extern void mp_clear(mp_int *a);
+
+/*
+ init a series of arguments
+ */
+extern int32 _mp_init_multi(psPool_t *pool, mp_int *mp0, mp_int *mp1, mp_int *mp2,
+ mp_int *mp3, mp_int *mp4, mp_int *mp5, mp_int *mp6,
+ mp_int *mp7);
+
+/*
+ clear a series of arguments
+ */
+extern void _mp_clear_multi(mp_int *mp0, mp_int *mp1, mp_int *mp2, mp_int *mp3,
+ mp_int *mp4, mp_int *mp5, mp_int *mp6, mp_int *mp7);
+
+/*
+ exchange two ints
+ */
+extern void mp_exch(mp_int *a, mp_int *b);
+
+/*
+ shrink ram required for a bignum
+ */
+extern int32 mp_shrink(mp_int *a);
+
+/*
+ grow an int32 to a given size
+ */
+extern int32 mp_grow(mp_int *a, int32 size);
+
+/*
+ init to a given number of digits
+ */
+extern int32 mp_init_size(psPool_t *pool, mp_int *a, int32 size);
+
+/******************************************************************************/
+/*
+ Basic Manipulations
+ */
+#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
+#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
+#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
+
+extern int32 mp_add_d (mp_int * a, mp_digit b, mp_int * c);
+extern int32 mp_sub_d (mp_int * a, mp_digit b, mp_int * c);
+/*
+ set to zero
+ */
+extern void mp_zero(mp_int *a);
+
+/*
+ set to a digit
+ */
+extern void mp_set(mp_int *a, mp_digit b);
+
+/*
+ copy, b = a
+ */
+extern int32 mp_copy(mp_int *a, mp_int *b);
+
+/*
+ inits and copies, a = b
+ */
+extern int32 mp_init_copy(psPool_t *pool, mp_int *a, mp_int *b);
+
+/*
+ trim unused digits
+ */
+extern void mp_clamp(mp_int *a);
+
+/******************************************************************************/
+/*
+ digit manipulation
+*/
+
+/*
+ right shift by "b" digits
+ */
+extern void mp_rshd(mp_int *a, int32 b);
+
+/*
+ left shift by "b" digits
+ */
+extern int32 mp_lshd(mp_int *a, int32 b);
+
+/*
+ c = a / 2**b
+ */
+extern int32 mp_div_2d(psPool_t *pool, mp_int *a, int32 b, mp_int *c, mp_int *d);
+
+/*
+ b = a/2
+ */
+extern int32 mp_div_2(mp_int *a, mp_int *b);
+
+/*
+ c = a * 2**b
+ */
+extern int32 mp_mul_2d(mp_int *a, int32 b, mp_int *c);
+
+/*
+ c = a mod 2**d
+ */
+extern int32 mp_mod_2d(mp_int *a, int32 b, mp_int *c);
+
+/*
+ computes a = 2**b
+ */
+extern int32 mp_2expt(mp_int *a, int32 b);
+
+/******************************************************************************/
+/*
+ Basic arithmetic
+ */
+
+/*
+ b = |a|
+ */
+extern int32 mp_abs(mp_int *a, mp_int *b);
+
+/*
+ compare a to b
+ */
+extern int32 mp_cmp(mp_int *a, mp_int *b);
+
+/*
+ compare |a| to |b|
+ */
+extern int32 mp_cmp_mag(mp_int *a, mp_int *b);
+
+/*
+ c = a + b
+ */
+extern int32 mp_add(mp_int *a, mp_int *b, mp_int *c);
+
+/*
+ c = a - b
+ */
+extern int32 mp_sub(mp_int *a, mp_int *b, mp_int *c);
+
+/*
+ c = a * b
+ b = a*a
+ */
+/* STEVE - moved mp_mul out of SLOW case */
+extern int32 mp_mul(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
+#ifdef USE_SMALL_WORD
+extern int32 mp_sqr(psPool_t *pool, mp_int *a, mp_int *b);
+#endif
+
+/*
+ a/b => cb + d == a
+ */
+extern int32 mp_div(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/*
+ c = a mod b, 0 <= c < b
+ */
+extern int32 mp_mod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
+
+/******************************************************************************/
+/*
+ single digit functions
+ */
+
+/*
+ compare against a single digit
+ */
+extern int32 mp_cmp_d(mp_int *a, mp_digit b);
+
+/*
+ c = a * b
+ */
+extern int32 mp_mul_d(mp_int *a, mp_digit b, mp_int *c);
+
+/******************************************************************************/
+/*
+ number theory
+ */
+
+/*
+ d = a + b (mod c)
+ */
+extern int32 mp_addmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/*
+ d = a * b (mod c)
+ */
+extern int32 mp_mulmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/*
+ c = 1/a (mod b)
+ */
+#ifdef USE_SMALL_WORD
+extern int32 mp_invmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
+#endif
+
+/*
+ setups the montgomery reduction
+ */
+extern int32 mp_montgomery_setup(mp_int *a, mp_digit *mp);
+
+/*
+ computes a = B**n mod b without division or multiplication useful for
+ normalizing numbers in a Montgomery system.
+ */
+extern int32 mp_montgomery_calc_normalization(mp_int *a, mp_int *b);
+
+/*
+ computes x/R == x (mod N) via Montgomery Reduction
+ */
+#ifdef USE_SMALL_WORD
+extern int32 mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
+#endif
+
+/*
+ d = a**b (mod c)
+ */
+/* TODO - we never define this */
+extern int32 mp_exptmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/******************************************************************************/
+/*
+ If we're using 1024 or 2048 bit keys and 28 bit digits, we only need the
+ fast_ versions of these functions, removing the others to save space.
+ Otherwise, we include the slow versions as well and which version to use
+ is done at runtime.
+*/
+#ifdef USE_SMALL_WORD
+extern int32 s_mp_mul_digs(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c,
+ int32 digs);
+extern int32 s_mp_sqr(psPool_t *pool, mp_int *a, mp_int *b);
+#else
+#define mp_montgomery_reduce fast_mp_montgomery_reduce
+#define mp_sqr fast_s_mp_sqr
+#if STEVE
+#define mp_mul(P, A, B, C) fast_s_mp_mul_digs(P, A, B, C, (A)->used + (B)->used + 1)
+#endif
+#define s_mp_mul_digs fast_s_mp_mul_digs
+#define mp_invmod fast_mp_invmod
+#endif
+
+/******************************************************************************/
+/*
+ radix conversion
+ */
+extern int32 mp_count_bits(mp_int *a);
+
+extern int32 mp_unsigned_bin_size(mp_int *a);
+extern int32 mp_read_unsigned_bin(mp_int *a, unsigned char *b, int32 c);
+extern int32 mp_to_unsigned_bin(psPool_t *pool, mp_int *a, unsigned char *b);
+
+extern int32 mp_signed_bin_size(mp_int *a);
+
+/*
+ lowlevel functions, do not call!
+ */
+#if STEVE
+#ifdef USE_SMALL_WORD
+#define s_mp_mul(P, A, B, C) s_mp_mul_digs(P, A, B, C, (A)->used + (B)->used + 1)
+#else
+#define s_mp_mul(P, A, B, C) sslAssert();
+#endif
+#endif /* STEVE */
+/* define this in all cases for now STEVE */
+#define s_mp_mul(P, A, B, C) s_mp_mul_digs(P, A, B, C, (A)->used + (B)->used + 1)
+
+
+/*
+ b = a*2
+ */
+extern int32 mp_mul_2(mp_int *a, mp_int *b);
+
+extern int32 s_mp_add(mp_int *a, mp_int *b, mp_int *c);
+extern int32 s_mp_sub(mp_int *a, mp_int *b, mp_int *c);
+
+extern int32 fast_s_mp_mul_digs(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c,
+ int32 digs);
+extern int32 fast_s_mp_sqr(psPool_t *pool, mp_int *a, mp_int *b);
+
+extern int32 fast_mp_invmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
+extern int32 fast_mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
+
+extern void bn_reverse(unsigned char *s, int32 len);
+
+
+#ifdef __cplusplus
+ }
+#endif /* __cplusplus */
+
+#endif /* _h_MPI */
+
diff --git a/gpxe/src/crypto/matrixssl/pscrypto.h b/gpxe/src/crypto/matrixssl/pscrypto.h
new file mode 100644
index 00000000..4d684327
--- /dev/null
+++ b/gpxe/src/crypto/matrixssl/pscrypto.h
@@ -0,0 +1,661 @@
+/*
+ * pscrypto.h
+ * Release $Name$
+ *
+ * Internal definitions for PeerSec Networks MatrixSSL cryptography provider
+ */
+/*
+ * Copyright (c) PeerSec Networks, 2002-2006. All Rights Reserved.
+ * The latest version of this code is available at http://www.matrixssl.org
+ *
+ * This software is open source; 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 General Public License does NOT permit incorporating this software
+ * into proprietary programs. If you are unable to comply with the GPL, a
+ * commercial license for this software may be purchased from PeerSec Networks
+ * at http://www.peersec.com
+ *
+ * This program is distributed in 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/******************************************************************************/
+
+#ifndef _h_PSCRYPTO
+#define _h_PSCRYPTO
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ PeerSec crypto-specific defines.
+ */
+#define SMALL_CODE
+#define CLEAN_STACK
+/*
+ If Native 64 bit integers are not supported, we must set the 16 bit flag
+ to produce 32 bit mp_words in mpi.h
+ We must also include the slow MPI functions because the fast ones only
+ work with larger (28 bit) digit sizes.
+*/
+#ifndef USE_INT64
+#define MP_16BIT
+#define USE_SMALL_WORD
+#endif /* USE_INT64 */
+
+/******************************************************************************/
+
+#ifdef USE_RSA
+
+#include "mpi.h"
+
+#if LINUX
+ #define _stat stat
+#endif
+
+/* this is the "32-bit at least" data type
+ * Re-define it to suit your platform but it must be at least 32-bits
+ */
+typedef unsigned long ulong32;
+
+/*
+ Primary RSA Key struct. Define here for crypto
+*/
+typedef struct {
+ mp_int e, d, N, qP, dP, dQ, p, q;
+ int32 size; /* Size of the key in bytes */
+ int32 optimized; /* 1 for optimized */
+} sslRsaKey_t;
+
+#endif /* USE_RSA */
+
+
+/*
+ * Private
+ */
+extern int32 ps_base64_decode(const unsigned char *in, uint32 len,
+ unsigned char *out, uint32 *outlen);
+
+/*
+ * Memory routines
+ */
+extern void psZeromem(void *dst, size_t len);
+extern void psBurnStack(unsigned long len);
+
+
+/* max size of either a cipher/hash block or symmetric key [largest of the two] */
+#define MAXBLOCKSIZE 24
+
+/* ch1-01-1 */
+/* error codes [will be expanded in future releases] */
+enum {
+ CRYPT_OK=0, /* Result OK */
+ CRYPT_ERROR, /* Generic Error */
+ CRYPT_NOP, /* Not a failure but no operation was performed */
+
+ CRYPT_INVALID_KEYSIZE, /* Invalid key size given */
+ CRYPT_INVALID_ROUNDS, /* Invalid number of rounds */
+ CRYPT_FAIL_TESTVECTOR, /* Algorithm failed test vectors */
+
+ CRYPT_BUFFER_OVERFLOW, /* Not enough space for output */
+ CRYPT_INVALID_PACKET, /* Invalid input packet given */
+
+ CRYPT_INVALID_PRNGSIZE, /* Invalid number of bits for a PRNG */
+ CRYPT_ERROR_READPRNG, /* Could not read enough from PRNG */
+
+ CRYPT_INVALID_CIPHER, /* Invalid cipher specified */
+ CRYPT_INVALID_HASH, /* Invalid hash specified */
+ CRYPT_INVALID_PRNG, /* Invalid PRNG specified */
+
+ CRYPT_MEM, /* Out of memory */
+
+ CRYPT_PK_TYPE_MISMATCH, /* Not equivalent types of PK keys */
+ CRYPT_PK_NOT_PRIVATE, /* Requires a private PK key */
+
+ CRYPT_INVALID_ARG, /* Generic invalid argument */
+ CRYPT_FILE_NOTFOUND, /* File Not Found */
+
+ CRYPT_PK_INVALID_TYPE, /* Invalid type of PK key */
+ CRYPT_PK_INVALID_SYSTEM, /* Invalid PK system specified */
+ CRYPT_PK_DUP, /* Duplicate key already in key ring */
+ CRYPT_PK_NOT_FOUND, /* Key not found in keyring */
+ CRYPT_PK_INVALID_SIZE, /* Invalid size input for PK parameters */
+
+ CRYPT_INVALID_PRIME_SIZE /* Invalid size of prime requested */
+};
+
+/******************************************************************************/
+/*
+ hash defines
+ */
+struct sha1_state {
+#ifdef USE_INT64
+ ulong64 length;
+#else
+ ulong32 lengthHi;
+ ulong32 lengthLo;
+#endif /* USE_INT64 */
+ ulong32 state[5], curlen;
+ unsigned char buf[64];
+};
+
+struct md5_state {
+#ifdef USE_INT64
+ ulong64 length;
+#else
+ ulong32 lengthHi;
+ ulong32 lengthLo;
+#endif /* USE_INT64 */
+ ulong32 state[4], curlen;
+ unsigned char buf[64];
+};
+
+#ifdef USE_MD2
+struct md2_state {
+ unsigned char chksum[16], X[48], buf[16];
+ unsigned long curlen;
+};
+#endif /* USE_MD2 */
+
+#ifdef USE_SHA256
+struct sha256_state {
+ ulong64 length;
+ ulong32 state[8], curlen;
+ unsigned char buf[64];
+};
+#endif /* USE_SHA256 */
+
+typedef union {
+ struct sha1_state sha1;
+ struct md5_state md5;
+#ifdef USE_MD2
+ struct md2_state md2;
+#endif /* USE_MD2 */
+#ifdef USE_SHA256
+ struct sha256_state sha256;
+#endif
+} hash_state;
+
+typedef hash_state sslSha1Context_t;
+typedef hash_state sslMd5Context_t;
+#ifdef USE_MD2
+typedef hash_state sslMd2Context_t;
+#endif /* USE_MD2 */
+#ifdef USE_SHA256
+typedef hash_state sslSha256Context_t;
+#endif /* USE_SHA256 */
+
+typedef struct {
+ unsigned char pad[64];
+ union {
+ sslMd5Context_t md5;
+ sslSha1Context_t sha1;
+ } u;
+} sslHmacContext_t;
+
+/******************************************************************************/
+/*
+ RC4
+ */
+#ifdef USE_ARC4
+typedef struct {
+ unsigned char state[256];
+ uint32 byteCount;
+ unsigned char x;
+ unsigned char y;
+} rc4_key;
+#endif /* USE_ARC4 */
+
+#define SSL_DES3_KEY_LEN 24
+#define SSL_DES3_IV_LEN 8
+#ifdef USE_3DES
+
+typedef struct {
+ ulong32 ek[3][32], dk[3][32];
+} des3_key;
+
+/*
+ A block cipher CBC structure
+ */
+typedef struct {
+ int32 blocklen;
+ unsigned char IV[8];
+ des3_key key;
+ int32 explicitIV; /* 1 if yes */
+} des3_CBC;
+
+extern int32 des3_setup(const unsigned char *key, int32 keylen, int32 num_rounds,
+ des3_CBC *skey);
+extern void des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct,
+ des3_CBC *key);
+extern void des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt,
+ des3_CBC *key);
+extern int32 des3_keysize(int32 *desired_keysize);
+
+extern int32 des_setup(const unsigned char *key, int32 keylen, int32 num_rounds,
+ des3_CBC *skey);
+extern void des_ecb_encrypt(const unsigned char *pt, unsigned char *ct,
+ des3_CBC *key);
+extern void des_ecb_decrypt(const unsigned char *ct, unsigned char *pt,
+ des3_CBC *key);
+
+#endif /* USE_3DES */
+
+
+typedef union {
+#ifdef USE_ARC4
+ rc4_key arc4;
+#endif
+#ifdef USE_3DES
+ des3_CBC des3;
+#endif
+} sslCipherContext_t;
+
+
+/*
+ Controls endianess and size of registers. Leave uncommented to get
+ platform neutral [slower] code detect x86-32 machines somewhat
+ */
+#if (defined(_MSC_VER) && defined(WIN32)) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__)))
+ #define ENDIAN_LITTLE
+ #define ENDIAN_32BITWORD
+#endif
+
+
+/* #define ENDIAN_LITTLE */
+/* #define ENDIAN_BIG */
+
+/* #define ENDIAN_32BITWORD */
+/* #define ENDIAN_64BITWORD */
+
+#if (defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) && !(defined(ENDIAN_32BITWORD) || defined(ENDIAN_64BITWORD))
+ #error You must specify a word size as well as endianess
+#endif
+
+#if !(defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE))
+ #define ENDIAN_NEUTRAL
+#endif
+
+/*
+ helper macros
+ */
+#if defined (ENDIAN_NEUTRAL)
+
+#define STORE32L(x, y) \
+ { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD32L(x, y) \
+ { x = ((unsigned long)((y)[3] & 255)<<24) | \
+ ((unsigned long)((y)[2] & 255)<<16) | \
+ ((unsigned long)((y)[1] & 255)<<8) | \
+ ((unsigned long)((y)[0] & 255)); }
+
+#define STORE64L(x, y) \
+ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y) \
+ { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+ (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+ (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+ (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#define STORE32H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y) \
+ { x = ((unsigned long)((y)[0] & 255)<<24) | \
+ ((unsigned long)((y)[1] & 255)<<16) | \
+ ((unsigned long)((y)[2] & 255)<<8) | \
+ ((unsigned long)((y)[3] & 255)); }
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+ (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+ (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+ (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
+
+#endif /* ENDIAN_NEUTRAL */
+
+#ifdef ENDIAN_LITTLE
+
+#define STORE32H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y) \
+ { x = ((unsigned long)((y)[0] & 255)<<24) | \
+ ((unsigned long)((y)[1] & 255)<<16) | \
+ ((unsigned long)((y)[2] & 255)<<8) | \
+ ((unsigned long)((y)[3] & 255)); }
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+ (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+ (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+ (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
+
+#ifdef ENDIAN_32BITWORD
+
+#define STORE32L(x, y) \
+ { unsigned long __t = (x); memcpy(y, &__t, 4); }
+
+#define LOAD32L(x, y) \
+ memcpy(&(x), y, 4);
+
+#define STORE64L(x, y) \
+ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y) \
+ { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+ (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+ (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+ (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#else /* 64-bit words then */
+
+#define STORE32L(x, y) \
+ { unsigned long __t = (x); memcpy(y, &__t, 4); }
+
+#define LOAD32L(x, y) \
+ { memcpy(&(x), y, 4); x &= 0xFFFFFFFF; }
+
+#define STORE64L(x, y) \
+ { ulong64 __t = (x); memcpy(y, &__t, 8); }
+
+#define LOAD64L(x, y) \
+ { memcpy(&(x), y, 8); }
+
+#endif /* ENDIAN_64BITWORD */
+#endif /* ENDIAN_LITTLE */
+
+#ifdef ENDIAN_BIG
+#define STORE32L(x, y) \
+ { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD32L(x, y) \
+ { x = ((unsigned long)((y)[3] & 255)<<24) | \
+ ((unsigned long)((y)[2] & 255)<<16) | \
+ ((unsigned long)((y)[1] & 255)<<8) | \
+ ((unsigned long)((y)[0] & 255)); }
+
+#define STORE64L(x, y) \
+ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y) \
+ { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48) | \
+ (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32) | \
+ (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16) | \
+ (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#ifdef ENDIAN_32BITWORD
+
+#define STORE32H(x, y) \
+ { unsigned long __t = (x); memcpy(y, &__t, 4); }
+
+#define LOAD32H(x, y) \
+ memcpy(&(x), y, 4);
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48)| \
+ (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32)| \
+ (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16)| \
+ (((ulong64)((y)[6] & 255))<<8)| (((ulong64)((y)[7] & 255))); }
+
+#else /* 64-bit words then */
+
+#define STORE32H(x, y) \
+ { unsigned long __t = (x); memcpy(y, &__t, 4); }
+
+#define LOAD32H(x, y) \
+ { memcpy(&(x), y, 4); x &= 0xFFFFFFFF; }
+
+#define STORE64H(x, y) \
+ { ulong64 __t = (x); memcpy(y, &__t, 8); }
+
+#define LOAD64H(x, y) \
+ { memcpy(&(x), y, 8); }
+
+#endif /* ENDIAN_64BITWORD */
+#endif /* ENDIAN_BIG */
+
+/*
+ packet code */
+#if defined(USE_RSA) || defined(MDH) || defined(MECC)
+ #define PACKET
+
+/*
+ size of a packet header in bytes */
+ #define PACKET_SIZE 4
+
+/*
+ Section tags
+ */
+ #define PACKET_SECT_RSA 0
+ #define PACKET_SECT_DH 1
+ #define PACKET_SECT_ECC 2
+ #define PACKET_SECT_DSA 3
+
+/*
+ Subsection Tags for the first three sections
+ */
+ #define PACKET_SUB_KEY 0
+ #define PACKET_SUB_ENCRYPTED 1
+ #define PACKET_SUB_SIGNED 2
+ #define PACKET_SUB_ENC_KEY 3
+#endif
+
+/*
+ fix for MSVC ...evil!
+ */
+#ifdef WIN32
+#ifdef _MSC_VER
+ #define CONST64(n) n ## ui64
+ typedef unsigned __int64 ulong64;
+#else
+ #define CONST64(n) n ## ULL
+ typedef unsigned long long ulong64;
+#endif
+#endif /* WIN32 */
+
+
+#define BSWAP(x) ( ((x>>24)&0x000000FFUL) | ((x<<24)&0xFF000000UL) | \
+ ((x>>8)&0x0000FF00UL) | ((x<<8)&0x00FF0000UL) )
+
+#ifdef _MSC_VER
+
+/*
+ instrinsic rotate
+ */
+#include <stdlib.h>
+#pragma intrinsic(_lrotr,_lrotl)
+#define ROR(x,n) _lrotr(x,n)
+#define ROL(x,n) _lrotl(x,n)
+#define RORc(x,n) _lrotr(x,n)
+#define ROLc(x,n) _lrotl(x,n)
+
+/*
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) && !defined(PS_NO_ASM)
+
+static inline unsigned ROL(unsigned word, int32 i)
+{
+ asm ("roll %%cl,%0"
+ :"0" (word),"c" (i));
+ return word;
+}
+
+static inline unsigned ROR(unsigned word, int32 i)
+{
+ asm ("rorl %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+*/
+/*
+#ifndef PS_NO_ROLC
+
+static inline unsigned ROLc(unsigned word, const int32 i)
+{
+ asm ("roll %2,%0"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+static inline unsigned RORc(unsigned word, const int32 i)
+{
+ asm ("rorl %2,%0"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+#else
+
+#define ROLc ROL
+#define RORc ROR
+
+#endif
+*/
+
+#else /* _MSC_VER */
+
+/*
+ rotates the hard way
+ */
+#define ROL(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROR(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROLc(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+
+#endif /* _MSC_VER */
+
+/* 64-bit Rotates */
+#if 0
+
+#if defined(__GNUC__) && defined(__x86_64__) && !defined(PS_NO_ASM)
+
+static inline unsigned long ROL64(unsigned long word, int32 i)
+{
+ asm("rolq %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+static inline unsigned long ROR64(unsigned long word, int32 i)
+{
+ asm("rorq %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+#ifndef PS_NO_ROLC
+
+static inline unsigned long ROL64c(unsigned long word, const int32 i)
+{
+ asm("rolq %2,%0"
+ :"=r" (word)
+ :"0" (word),"J" (i));
+ return word;
+}
+
+static inline unsigned long ROR64c(unsigned long word, const int32 i)
+{
+ asm("rorq %2,%0"
+ :"=r" (word)
+ :"0" (word),"J" (i));
+ return word;
+}
+
+#else /* PS_NO_ROLC */
+
+#define ROL64c ROL
+#define ROR64c ROR
+
+#endif /* PS_NO_ROLC */
+#endif
+#endif /* commented out */
+
+#define ROL64(x, y) \
+ ( (((x)<<((ulong64)(y)&63)) | \
+ (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64(x, y) \
+ ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+ ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROL64c(x, y) \
+ ( (((x)<<((ulong64)(y)&63)) | \
+ (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64c(x, y) \
+ ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+ ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#undef MAX
+#undef MIN
+#define MAX(x, y) ( ((x)>(y))?(x):(y) )
+#define MIN(x, y) ( ((x)<(y))?(x):(y) )
+
+/*
+ extract a byte portably This MSC code causes runtime errors in VS.NET,
+ always use the other
+ */
+/*
+#ifdef _MSC_VER
+ #define byte(x, n) ((unsigned char)((x) >> (8 * (n))))
+#else
+*/
+ #define byte(x, n) (((x) >> (8 * (n))) & 255)
+/*
+#endif
+*/
+#ifdef __cplusplus
+ }
+#endif /* __cplusplus */
+
+#endif /* _h_PSCRYPTO */
+
+/******************************************************************************/
+
diff --git a/gpxe/src/crypto/md5.c b/gpxe/src/crypto/md5.c
new file mode 100644
index 00000000..1fed24fc
--- /dev/null
+++ b/gpxe/src/crypto/md5.c
@@ -0,0 +1,235 @@
+/*
+ * Cryptographic API.
+ *
+ * MD5 Message Digest Algorithm (RFC1321).
+ *
+ * Derived from cryptoapi implementation, originally based on the
+ * public domain implementation written by Colin Plumb in 1993.
+ *
+ * Reduced object size by around 50% compared to the original Linux
+ * version for use in Etherboot by Michael Brown.
+ *
+ * Copyright (c) Cryptoapi developers.
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * Copyright (c) 2006 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 (at your option)
+ * any later version.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <gpxe/crypto.h>
+#include <gpxe/md5.h>
+
+#define __md5step __attribute__ (( regparm ( 3 ) ))
+
+struct md5_step {
+ u32 __md5step ( * f ) ( u32 b, u32 c, u32 d );
+ u8 coefficient;
+ u8 constant;
+};
+
+static u32 __md5step f1(u32 b, u32 c, u32 d)
+{
+ return ( d ^ ( b & ( c ^ d ) ) );
+}
+
+static u32 __md5step f2(u32 b, u32 c, u32 d)
+{
+ return ( c ^ ( d & ( b ^ c ) ) );
+}
+
+static u32 __md5step f3(u32 b, u32 c, u32 d)
+{
+ return ( b ^ c ^ d );
+}
+
+static u32 __md5step f4(u32 b, u32 c, u32 d)
+{
+ return ( c ^ ( b | ~d ) );
+}
+
+static struct md5_step md5_steps[4] = {
+ {
+ .f = f1,
+ .coefficient = 1,
+ .constant = 0,
+ },
+ {
+ .f = f2,
+ .coefficient = 5,
+ .constant = 1,
+ },
+ {
+ .f = f3,
+ .coefficient = 3,
+ .constant = 5,
+ },
+ {
+ .f = f4,
+ .coefficient = 7,
+ .constant = 0,
+ }
+};
+
+static const u8 r[64] = {
+ 7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
+ 5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
+ 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
+ 6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
+};
+
+static const u32 k[64] = {
+ 0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL,
+ 0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL,
+ 0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL,
+ 0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL,
+ 0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL,
+ 0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL,
+ 0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL,
+ 0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL,
+ 0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL,
+ 0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL,
+ 0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL,
+ 0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL,
+ 0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL,
+ 0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL,
+ 0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL,
+ 0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL,
+};
+
+static void md5_transform(u32 *hash, const u32 *in)
+{
+ u32 a, b, c, d, f, g, temp;
+ int i;
+ struct md5_step *step;
+
+ a = hash[0];
+ b = hash[1];
+ c = hash[2];
+ d = hash[3];
+
+ for ( i = 0 ; i < 64 ; i++ ) {
+ step = &md5_steps[i >> 4];
+ f = step->f ( b, c, d );
+ g = ( ( i * step->coefficient + step->constant ) & 0xf );
+ temp = d;
+ d = c;
+ c = b;
+ a += ( f + k[i] + in[g] );
+ a = ( ( a << r[i] ) | ( a >> ( 32-r[i] ) ) );
+ b += a;
+ a = temp;
+ }
+
+ hash[0] += a;
+ hash[1] += b;
+ hash[2] += c;
+ hash[3] += d;
+}
+
+/* XXX: this stuff can be optimized */
+static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
+{
+ while (words--) {
+ le32_to_cpus(buf);
+ buf++;
+ }
+}
+
+static inline void cpu_to_le32_array(u32 *buf, unsigned int words)
+{
+ while (words--) {
+ cpu_to_le32s(buf);
+ buf++;
+ }
+}
+
+static inline void md5_transform_helper(struct md5_ctx *ctx)
+{
+ le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32));
+ md5_transform(ctx->hash, ctx->block);
+}
+
+static void md5_init(void *context)
+{
+ struct md5_ctx *mctx = context;
+
+ mctx->hash[0] = 0x67452301;
+ mctx->hash[1] = 0xefcdab89;
+ mctx->hash[2] = 0x98badcfe;
+ mctx->hash[3] = 0x10325476;
+ mctx->byte_count = 0;
+}
+
+static void md5_update(void *context, const void *data, void *dst __unused,
+ size_t len)
+{
+ struct md5_ctx *mctx = context;
+ const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
+
+ mctx->byte_count += len;
+
+ if (avail > len) {
+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+ data, len);
+ return;
+ }
+
+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+ data, avail);
+
+ md5_transform_helper(mctx);
+ data += avail;
+ len -= avail;
+
+ while (len >= sizeof(mctx->block)) {
+ memcpy(mctx->block, data, sizeof(mctx->block));
+ md5_transform_helper(mctx);
+ data += sizeof(mctx->block);
+ len -= sizeof(mctx->block);
+ }
+
+ memcpy(mctx->block, data, len);
+}
+
+static void md5_final(void *context, void *out)
+{
+ struct md5_ctx *mctx = context;
+ const unsigned int offset = mctx->byte_count & 0x3f;
+ char *p = (char *)mctx->block + offset;
+ int padding = 56 - (offset + 1);
+
+ *p++ = 0x80;
+ if (padding < 0) {
+ memset(p, 0x00, padding + sizeof (u64));
+ md5_transform_helper(mctx);
+ p = (char *)mctx->block;
+ padding = 56;
+ }
+
+ memset(p, 0, padding);
+ mctx->block[14] = mctx->byte_count << 3;
+ mctx->block[15] = mctx->byte_count >> 29;
+ le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
+ sizeof(u64)) / sizeof(u32));
+ md5_transform(mctx->hash, mctx->block);
+ cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
+ memcpy(out, mctx->hash, sizeof(mctx->hash));
+ memset(mctx, 0, sizeof(*mctx));
+}
+
+struct crypto_algorithm md5_algorithm = {
+ .name = "md5",
+ .ctxsize = MD5_CTX_SIZE,
+ .blocksize = ( MD5_BLOCK_WORDS * 4 ),
+ .digestsize = MD5_DIGEST_SIZE,
+ .init = md5_init,
+ .encode = md5_update,
+ .final = md5_final,
+};
diff --git a/gpxe/src/crypto/ssl.c b/gpxe/src/crypto/ssl.c
new file mode 100644
index 00000000..8abd7af8
--- /dev/null
+++ b/gpxe/src/crypto/ssl.c
@@ -0,0 +1,136 @@
+#if 0
+
+#include "ssl.h"
+#include "ssl_constructs.h"
+#include <string.h> // for bcopy()
+#include <time.h> // for time()
+#include <stdlib.h> // for rand(), htons?, htonl?
+// note net byte order is big-endian
+// Need to set error codes
+
+int CreateSSLHello(SSL_t *ssl)
+{
+ printf("In CreateSSLHello()\n",ssl);
+
+ // Initalize the structure
+ bzero(ssl,sizeof(SSL_t));
+ //ssl->max_size = sizeof(ssl->buffer);
+ ssl->max_size = 18456;
+
+ // Declare variables
+ int i; void *ptr;
+
+ // Set pointers into buffer
+ SSLPlaintext *record = (SSLPlaintext *)ssl->buffer;
+ Handshake *handshake = (Handshake *)record->fragment;
+ // the body starts right after the handshake
+ printf("sizeof(Handshake) = %d\n",sizeof(Handshake));
+ ClientHello *hello = (ClientHello *)(handshake + 1);
+
+ printf("record->%#x, handshake->%#x, hello->%#x\n",record,handshake,hello);
+
+ // Construct ClientHello Message
+ hello->client_version = version;
+ i = htonl(time(NULL));
+ bcopy(&i,hello->random.gmt_unix_time,4);
+ for(i=0;i<28;i++){ hello->random.random_bytes[i] = (uint8)rand(); }
+ hello->session_id_length = 0;
+ hello->session_id = &hello->session_id_length;
+ hello->session_id_end = hello->session_id;
+ hello->cipher_suites_length = (CipherSuiteLength *)(hello->session_id_end + 1);
+ hello->cipher_suites = (hello->cipher_suites_length + 1);
+ hello->cipher_suites_end = hello->cipher_suites;
+ i = htons(2*5); // 2 bytes per Suite * 5 Suites
+ bcopy(&i,hello->cipher_suites_length,2);
+ bcopy(SSL_NULL_WITH_NULL_NULL,hello->cipher_suites_end,sizeof(CipherSuite));
+ *hello->cipher_suites_end++;
+ bcopy(SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,hello->cipher_suites_end,sizeof(CipherSuite));
+ *hello->cipher_suites_end++;
+ bcopy(SSL_DH_DSS_WITH_DES_CBC_SHA,hello->cipher_suites_end,sizeof(CipherSuite));
+ *hello->cipher_suites_end++;
+ bcopy(SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,hello->cipher_suites_end,sizeof(CipherSuite));
+ *hello->cipher_suites_end++;
+ bcopy(SSL_DH_anon_WITH_RC4_128_MD5,hello->cipher_suites_end,sizeof(CipherSuite));
+ hello->compression_methods_length = (CompressionMethodLength *)(hello->cipher_suites_end + 1);
+ hello->compression_methods = (hello->compression_methods_length + 1);
+ hello->compression_methods_end = hello->compression_methods;
+ *hello->compression_methods_length = 1;
+ *hello->compression_methods_end = compression_method_null;
+
+ // Construct Handshake Message
+ handshake->msg_type = handshake_type_client_hello;
+ i = (void *)(hello->compression_methods_end + 1) - (void *)hello;
+ printf("Handshake.length = %d\n", i);
+ handshake->length[0] = (char)*(&i+8);
+ handshake->length[1] = (char)*(&i+8);
+ handshake->length[2] = (char)i;
+ //bcopy((&i+1),handshake->length,3); // +1 so we copy 3 bytes
+
+ // Construct SSL Record
+ printf("sizeof(ContentType)=%d\n",sizeof(ContentType));
+ printf("sizeof(uint8)=%d\n",sizeof(uint8));
+ record->type = content_type_handshake;
+ record->version = version;
+ i += sizeof(Handshake);
+ printf("SSLPlaintext.length = %d\n",i);
+ record->length[0] = (char)*(&i+8);
+ record->length[1] = (char)i;
+ //bcopy(&i,record->length,4); // length of handshake
+
+ // Set total size of message
+ i += sizeof(ContentType) + sizeof(ProtocolVersion) + sizeof(uint16);
+ ssl->length = i;
+ printf("End of CreateSSLHello\n");
+ return 0;
+}
+
+void PrintSSLPacket(SSL_t *ssl)
+{
+ printf("Printing packet with length:%d\n", ssl->length);
+ char *ptr = ssl->buffer;
+ char *begin = ptr;
+ char *tmp;
+ char *end = ssl->buffer + ssl->length;
+ printf("Record Layer:\n");
+ printf("\tContentType: %2hhX\n",(char)*ptr++);
+ printf("\tVersion: %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++);
+ printf("\tLength: %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++);
+
+ printf("Handshake:\n");
+ printf("\tType: %2hhX\n", (char)*ptr++);
+ printf("\tLength: %2hhX %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++, (char)*ptr++);
+ printf("\tVersion: %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++);
+ printf("\tgmt_unix_time: %2hhX %2hhX %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++, (char)*ptr++, (char)*ptr++);
+ printf("\trandom: ");
+ tmp = ptr + 28;
+ for(;ptr<tmp;ptr++){printf("%2hhX ", (char)*ptr);}
+
+ printf("\n\nHexDump:\n");
+
+ int ctr = 0;
+ for(;begin<end;begin++){printf("%2hhX ",(char)*begin);if(++ctr%10==0){printf("\n");}}
+ printf("\n\n");
+}
+
+int ReadSSLHello(SSL_t *ssl)
+{
+ SSLCiphertext *ct = (SSLCiphertext *)ssl->buffer;
+
+ if(ct->type == content_type_alert){
+ // assuming text is still plaintext
+ Alert *a = (Alert *)&ct->fragment;
+ if(a->level == alert_level_fatal){
+ printf("Fatal Alert %d, connection terminated\n",a->description);
+ return (1);
+ }else if(a->level == alert_level_warning){
+ printf("Warning Alert %d\n", a->description);
+ }else{
+ printf("Unknown alert level %d\n", a->level);
+ }
+ }else{
+ printf("SSL type %d\n",ct->type);
+ }
+ return (0);
+}
+
+#endif
diff --git a/gpxe/src/crypto/ssl.h b/gpxe/src/crypto/ssl.h
new file mode 100644
index 00000000..06d43008
--- /dev/null
+++ b/gpxe/src/crypto/ssl.h
@@ -0,0 +1,19 @@
+// At the moment I have hard coded one buffer. The size
+// is the max size of SSLCiphertext.length (so, actually it should
+// be increased to include the other information in the struct)
+// I might need to make a new, or split the current, buffer because
+// I have to have space to read in and write out, as well as keep
+// any data that has not been translated.
+// It works for now.
+typedef struct _ssl_t{
+ char buffer[18456];
+ int length;
+ int max_size; // can't define const here
+ // Current CipherSuite
+ // Client random / Server random ???
+ // pointers to different crypto functions
+} SSL_t;
+
+int CreateSSLHello(SSL_t *ssl);
+int ReadSSLHello(SSL_t *ssl);
+void PrintSSLPacket(SSL_t *ssl);
diff --git a/gpxe/src/crypto/ssl_constructs.h b/gpxe/src/crypto/ssl_constructs.h
new file mode 100644
index 00000000..ab3aa703
--- /dev/null
+++ b/gpxe/src/crypto/ssl_constructs.h
@@ -0,0 +1,342 @@
+// Note: This file still needs some work.
+// Note: I had to redefine the enums to a set of const values,
+// so that the size of the variable would be correct.
+
+// Typedefs
+// (As defined by the SSL v3.0 RFC Draft)
+// URL: http://wp.netscape.com/eng/ssl3/draft302.txt
+typedef unsigned char uint8;
+typedef uint8 uint16[2];
+typedef uint8 uint24[3];
+typedef uint8 uint32[4];
+typedef uint8 uint64[8];
+
+// Record layers
+typedef struct _ProtocolVersion{
+ uint8 major, minor;
+} ProtocolVersion;
+
+const ProtocolVersion version = { 3, 0 };
+
+typedef uint8 ContentType;
+const ContentType content_type_change_cipher_spec_type = 20;
+const ContentType content_type_alert = 21;
+const ContentType content_type_handshake = 22;
+const ContentType content_type_application_data = 23;
+
+typedef struct _SSLPlaintext{
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length; // can not exceed 2^14 bytes
+ uint8 fragment[16384]; // 2^14 = 16,384 bytes
+} SSLPlaintext;
+
+typedef struct _SSLCompressed{
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length; // can not exceed 2^14 + 1024
+ uint8 fragment[17408]; // SSLCompressed.length
+} SSLCompressed;
+
+typedef struct _SSLCiphertext{
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length;
+ uint8 fragment; // so we have a pointer to the data, and don't have to do math
+ // fragment; type GenericStreamCipher or GenericBlockCipher
+} SSLCiphertext; // recast to get fragment
+
+typedef struct _GenericStreamCipher{
+ uint8 content[17408]; // SSLCompressed.length
+ uint8 MAC[]; // CipherSpec.hash_size
+} GenericStreamCipher;
+
+typedef struct _SSLStreamCiphertext{
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length; // can not exceed 2^14 + 2048 = 18,456
+ GenericStreamCipher fragment;
+} SSLStreamCiphertext;
+
+typedef struct _GenericBlockCipher{
+ uint8 content[17408]; // SSLConpressed.length
+ uint8 MAC[0]; // CipherSpec.hash_size
+ // padding is used to bring the plaintext to
+ // a multiple of the block cipher's block length.
+ uint8 padding[0]; // GenericBlockCipher.padding_length
+ uint8 padding_length;
+} GenericBlockCipher;
+
+typedef struct _SSLBlockCiphertext{
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length; // can not exceed 2^14 + 2048 = 18,456
+ GenericBlockCipher fragment;
+} SSLBlockCiphertext;
+
+// Change cipher specs message
+typedef struct _ChangeCipherSpec{
+ enum { type_change_cipher_spec=1, type_size=255 } type;
+} ChangeCipherSpec;
+
+// Alert messages
+typedef uint8 AlertLevel;
+const AlertLevel alert_level_warning = 1;
+const AlertLevel alert_level_fatal=2;
+
+typedef uint8 AlertDescription;
+const AlertDescription alert_description_close_notify = 0;
+const AlertDescription alert_description_unexpected_message = 10;
+const AlertDescription alert_description_bad_record_mac = 20;
+const AlertDescription alert_description_decompression_failure = 30;
+const AlertDescription alert_description_handshake_failure = 40;
+const AlertDescription alert_description_no_certificate = 41;
+const AlertDescription alert_description_bad_certificate = 42;
+const AlertDescription alert_description_unsupported_certificate = 43;
+const AlertDescription alert_description_certificate_revoked = 44;
+const AlertDescription alert_description_certificate_expired = 45;
+const AlertDescription alert_description_certificate_unknown = 46;
+const AlertDescription alert_description_illegal_parameter = 47;
+
+typedef struct _Alert{
+ AlertLevel level;
+ AlertDescription description;
+} Alert;
+
+// Handshake protocol
+// What is the best way to have a generic pointer to the body struct??
+typedef uint8 HandshakeType;
+const HandshakeType handshake_type_hello_request = 0;
+const HandshakeType handshake_type_client_hello = 1;
+const HandshakeType handshake_type_server_hello = 2;
+const HandshakeType handshake_type_certificate = 11;
+const HandshakeType handshake_type_server_key_exchange = 12;
+const HandshakeType handshake_type_certificate_request = 13;
+const HandshakeType handshake_type_server_done = 14;
+const HandshakeType handshake_type_certificate_verify = 15;
+const HandshakeType handshake_type_client_key_exchange = 16;
+const HandshakeType handshake_type_finished = 20;
+
+typedef struct _Handshake{
+ HandshakeType msg_type;
+ uint24 length;
+ // body; // one of HandshakeType structs
+} Handshake; // generic Handshake, need to recast to get body
+
+// Hello messages
+typedef struct _HelloRequest{} HelloRequest;
+
+typedef struct _HelloRequestHandshake{
+ HandshakeType msg_type;
+ uint24 length;
+ HelloRequest body;
+} HelloRequestHandshake;
+
+typedef struct _Random{
+ uint32 gmt_unix_time;
+ uint8 random_bytes[28];
+} Random;
+
+//typedef uint8 SessionID[32]; // <0..32>
+typedef uint8 SessionIDLength;
+typedef uint8 SessionID;
+
+typedef uint16 CipherSuiteLength;
+typedef uint8 CipherSuite[2];
+
+typedef uint8 CompressionMethodLength;
+typedef uint8 CompressionMethod;
+const CompressionMethod compression_method_null = 0;
+
+
+typedef struct _ClientHello{
+ ProtocolVersion client_version;
+ Random random;
+ SessionIDLength session_id_length;
+ SessionID *session_id;
+ SessionID *session_id_end;
+ CipherSuiteLength *cipher_suites_length;
+ CipherSuite *cipher_suites; // min size is one entry
+ CipherSuite *cipher_suites_end;
+ //CipherSuite cipher_suites[32768]; // <2..2^16-1> = 65,536 bytes and CipherSuite is 2 bytes
+ CompressionMethodLength *compression_methods_length;
+ CompressionMethod *compression_methods;
+ CompressionMethod *compression_methods_end;
+ //CompressionMethod *compression_methods; // min size is zero
+ //CompressionMethod compression_methods[256]; // <0..2^8-1> = 256 bytes and CompressionMethod is 1 byte
+} ClientHello;
+
+typedef struct _ClientHelloHandshake{
+ //HandshakeType msg_type;
+ uint8 msg_type;
+ uint24 length;
+ ClientHello body;
+} ClientHelloHandshake;
+
+typedef struct _ServerHello{
+ ProtocolVersion server_version;
+ Random random;
+ SessionID session_id;
+ CipherSuite cipher_suite;
+ CompressionMethod compression_method;
+} ServerHello;
+
+typedef struct _ServerHelloHandshake{
+ HandshakeType msg_type;
+ uint24 length;
+ ServerHello body;
+} ServerHelloHandshake;
+
+// Server authentication and key exchange messages
+typedef uint8 ASN1Cert[16777216]; // <1..2^24-1> = 16,777,216 bytes
+
+typedef struct _Certificate{
+ ASN1Cert certificate_list[1]; // <1..2^24-1> / ANS1Cert = 1
+ // for some reason the size of certificate_list and ASN1Cert is the same, so only one certificate in the list
+} Certificate;
+
+typedef uint8 KeyExchangeAlgorithm;
+const KeyExchangeAlgorithm key_exchange_algorithm_rsa = 0;
+const KeyExchangeAlgorithm key_exchange_algorithm_diffie_hellman = 1;
+const KeyExchangeAlgorithm key_exchange_algorithm_fortezza_kea = 2;
+
+typedef struct _AnonSignature{
+ struct {};
+} AnonSignature;
+
+typedef struct _RSASignature{
+ uint8 md5_hash[16];
+ uint8 sha_hash[20];
+} RSASignature;
+
+typedef struct _DSASignature{
+ uint8 sha_hash[20];
+} DSASignature;
+
+// use union??, make a mess to reference, but easy to make Signature type.
+typedef union _Signature{ AnonSignature anon; RSASignature rsa; DSASignature dsa; } Signature;
+
+typedef struct _ServerRSAParams{
+ uint8 RSA_modulus[65536]; // <1..2^16-1> = 65,536
+ uint8 RSA_exponent[65536]; // <1..2^16-1> = 65,536
+} ServerRSAParams;
+
+typedef struct _ServerDHParams{
+ uint8 DH_p[65536]; // <1..2^16-1>
+ uint8 DH_g[65536]; // <1..2^16-1>
+ uint8 DH_Ys[65536]; // <1..2^16-1>
+} ServerDHParams;
+
+typedef struct _ServerDHKeyExchange{
+ ServerDHParams params;
+ Signature signed_params;
+} ServerDHKeyExchange;
+
+typedef struct _ServerRSAKeyExchange{
+ ServerRSAParams params;
+ Signature signed_params;
+} ServerRSAKeyExchange;
+
+typedef uint8 SignatureAlgorithm;
+const SignatureAlgorithm signature_algorithm_anonymous = 0;
+const SignatureAlgorithm signature_algorithm_rsa = 1;
+const SignatureAlgorithm signature_algorithm_dsa = 2;
+
+typedef uint8 CertificateType;
+const CertificateType certificate_type_RSA_sign = 1;
+const CertificateType certificate_type_DSS_sign = 2;
+const CertificateType certificate_type_RSA_fixed_DH = 3;
+const CertificateType certificate_type_DSS_fixed_DH = 4;
+const CertificateType certificate_type_RSA_ephemeral_DH = 5;
+const CertificateType certificate_type_DSS_ephemeral_DH = 6;
+const CertificateType certificate_type_FORTEZZA_MISSI = 20;
+
+typedef uint8 DistinguishedName[65536]; // <1..2^16-1> = 65,536
+
+typedef struct _CertificateRequest{
+ CertificateType certificate_types[256]; // <1..2^8-1>
+ DistinguishedName certificate_authorities[1]; // <3...2^16-1> / DistinguishedName
+ // this is another one that is odd with a list size of 1
+} CertificateRequest;
+
+typedef struct _ServerHelloDone{} ServerHelloDone;
+
+// Client authentication and key exchange messages
+typedef struct _PreMasterSecret{
+ ProtocolVersion client_version;
+ uint8 random[46];
+} PreMasterSecret;
+
+typedef struct _EncryptedPreMasterSecret{
+ PreMasterSecret pre_master_secret;
+} EncryptedPreMasterSecret;
+
+typedef struct _RSAClientKeyExchange{
+ EncryptedPreMasterSecret exchange_keys;
+} RSAClientKeyExchange;
+
+typedef uint8 PublicValueEncoding;
+const PublicValueEncoding public_value_encoding_implicit = 0;
+const PublicValueEncoding public_value_encoding_explicit = 1;
+
+typedef struct _ClientDiffieHellmanPublic{
+ // This is a select on PublicValueEncoding, and I chose the larger size
+ uint8 dh_public[65536]; // DH_Yc<1..2^16-1>, the dh public value
+} ClientDiffieHellmanPublic;
+
+typedef struct _DHClientKeyExhange{
+ ClientDiffieHellmanPublic exchange_keys;
+} DHClientKeyExchange;
+
+typedef struct _CertificateVerify{
+ Signature signature;
+} CertificateVerify;
+
+// Handshake finalization message
+typedef struct _Finished{
+ uint8 md5_hash[16];
+ uint8 sha_hash[20];
+} Finished;
+
+// The CipherSuite
+CipherSuite SSL_NULL_WITH_NULL_NULL = { 0x00, 0x13 };
+CipherSuite SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x0B };
+CipherSuite SSL_DH_DSS_WITH_DES_CBC_SHA = { 0x00, 0x0C };
+CipherSuite SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x11 };
+CipherSuite SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 = { 0x00, 0x17 };
+CipherSuite SSL_DH_anon_WITH_RC4_128_MD5 = { 0x00, 0x18 };
+
+// The CipherSpec
+typedef uint8 CipherType;
+const CipherType cipher_type_stream = 0;
+const CipherType cipher_type_block = 1;
+
+typedef uint8 IsExportable;
+const IsExportable is_exportable_true = 0;
+const IsExportable is_exportable_false = 1;
+
+typedef uint8 BulkCipherAlgorithm;
+const BulkCipherAlgorithm bulk_cipher_algorithm_null = 0;
+const BulkCipherAlgorithm bulk_cipher_algorithm_rc4 = 1;
+const BulkCipherAlgorithm bulk_cipher_algorithm_rc2 = 2;
+const BulkCipherAlgorithm bulk_cipher_algorithm_des = 3;
+const BulkCipherAlgorithm bulk_cipher_algorithm_3des = 4;
+const BulkCipherAlgorithm bulk_cipher_algorithm_des40 = 5;
+const BulkCipherAlgorithm bulk_cipher_algorithm_fortezza = 6;
+
+typedef uint8 MACAlgorithm;
+const MACAlgorithm mac_algorithm_null = 0;
+const MACAlgorithm mac_algorithm_md5 = 1;
+const MACAlgorithm mac_algorithm_sha = 2;
+
+typedef struct _CipherSpec{
+ BulkCipherAlgorithm bulk_cipher_algorithm;
+ MACAlgorithm mac_algorithm;
+ CipherType cipher_type;
+ IsExportable is_exportable;
+ uint8 hash_size;
+ uint8 key_material;
+ uint8 IV_size;
+} CipherSpec;
+
+