From 4e0ccaf9b2d38b7f4697d8ce26f4186da24f48aa Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sun, 30 Aug 2015 13:34:00 +0300 Subject: [PATCH] Import axTLS 1.4.9 --- LICENSE | 24 + VERSION | 1 + crypto/aes.c | 457 +++++++++ crypto/aes.o | Bin 0 -> 35312 bytes crypto/bigint.c | 1512 +++++++++++++++++++++++++++++ crypto/bigint.h | 99 ++ crypto/bigint.o | Bin 0 -> 94704 bytes crypto/bigint_impl.h | 131 +++ crypto/crypto.h | 230 +++++ crypto/crypto_misc.c | 367 +++++++ crypto/hmac.c | 105 ++ crypto/hmac.o | Bin 0 -> 10444 bytes crypto/md2.c | 162 ++++ crypto/md2.o | Bin 0 -> 9808 bytes crypto/md5.c | 294 ++++++ crypto/md5.o | Bin 0 -> 19348 bytes crypto/os_int.h | 67 ++ crypto/rc4.c | 92 ++ crypto/rc4.o | Bin 0 -> 6232 bytes crypto/rsa.c | 269 ++++++ crypto/rsa.o | Bin 0 -> 25612 bytes crypto/sha1.c | 249 +++++ crypto/sha1.o | Bin 0 -> 13688 bytes ssl/asn1.c | 566 +++++++++++ ssl/asn1.o | Bin 0 -> 48176 bytes ssl/cert.h | 43 + ssl/config.h | 127 +++ ssl/crypto_misc.h | 172 ++++ ssl/gen_cert.c | 364 +++++++ ssl/gen_cert.o | Bin 0 -> 828 bytes ssl/loader.c | 483 ++++++++++ ssl/loader.o | Bin 0 -> 38320 bytes ssl/openssl.c | 323 +++++++ ssl/openssl.o | Bin 0 -> 827 bytes ssl/os_int.h | 8 + ssl/os_port.c | 158 +++ ssl/os_port.h | 199 ++++ ssl/os_port.o | Bin 0 -> 13424 bytes ssl/p12.c | 483 ++++++++++ ssl/p12.o | Bin 0 -> 1812 bytes ssl/private_key.h | 54 ++ ssl/ssl.h | 499 ++++++++++ ssl/tls1.c | 2191 ++++++++++++++++++++++++++++++++++++++++++ ssl/tls1.h | 297 ++++++ ssl/tls1_clnt.c | 395 ++++++++ ssl/tls1_svr.c | 478 +++++++++ ssl/version.h | 1 + ssl/x509.c | 559 +++++++++++ 48 files changed, 11459 insertions(+) create mode 100644 LICENSE create mode 100644 VERSION create mode 100644 crypto/aes.c create mode 100644 crypto/aes.o create mode 100644 crypto/bigint.c create mode 100644 crypto/bigint.h create mode 100644 crypto/bigint.o create mode 100644 crypto/bigint_impl.h create mode 100644 crypto/crypto.h create mode 100644 crypto/crypto_misc.c create mode 100644 crypto/hmac.c create mode 100644 crypto/hmac.o create mode 100644 crypto/md2.c create mode 100644 crypto/md2.o create mode 100644 crypto/md5.c create mode 100644 crypto/md5.o create mode 100644 crypto/os_int.h create mode 100644 crypto/rc4.c create mode 100644 crypto/rc4.o create mode 100644 crypto/rsa.c create mode 100644 crypto/rsa.o create mode 100644 crypto/sha1.c create mode 100644 crypto/sha1.o create mode 100644 ssl/asn1.c create mode 100644 ssl/asn1.o create mode 100644 ssl/cert.h create mode 100644 ssl/config.h create mode 100644 ssl/crypto_misc.h create mode 100644 ssl/gen_cert.c create mode 100644 ssl/gen_cert.o create mode 100644 ssl/loader.c create mode 100644 ssl/loader.o create mode 100644 ssl/openssl.c create mode 100644 ssl/openssl.o create mode 100644 ssl/os_int.h create mode 100644 ssl/os_port.c create mode 100644 ssl/os_port.h create mode 100644 ssl/os_port.o create mode 100644 ssl/p12.c create mode 100644 ssl/p12.o create mode 100644 ssl/private_key.h create mode 100644 ssl/ssl.h create mode 100644 ssl/tls1.c create mode 100644 ssl/tls1.h create mode 100644 ssl/tls1_clnt.c create mode 100644 ssl/tls1_svr.c create mode 100644 ssl/version.h create mode 100644 ssl/x509.c diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..eed70a9a6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2008, Cameron Rich All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. Redistributions in binary +form must reproduce the above copyright notice, this list of conditions and +the following disclaimer in the documentation and/or other materials +provided with the distribution. Neither the name of the axTLS Project nor +the names of its contributors may be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. diff --git a/VERSION b/VERSION new file mode 100644 index 000000000..4ea2b1f40 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.4.9 diff --git a/crypto/aes.c b/crypto/aes.c new file mode 100644 index 000000000..9b07e27ea --- /dev/null +++ b/crypto/aes.c @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * 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 +#include "os_port.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 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)) + +/* + * 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&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> 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) +{ + int i; + uint32_t tin[4], tout[4], iv[4]; + + memcpy(iv, ctx->iv, AES_IV_SIZE); + for (i = 0; i < 4; i++) + tout[i] = ntohl(iv[i]); + + for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE) + { + uint32_t msg_32[4]; + uint32_t out_32[4]; + memcpy(msg_32, msg, AES_BLOCKSIZE); + msg += AES_BLOCKSIZE; + + for (i = 0; i < 4; i++) + tin[i] = ntohl(msg_32[i])^tout[i]; + + AES_encrypt(ctx, tin); + + for (i = 0; i < 4; i++) + { + tout[i] = tin[i]; + out_32[i] = htonl(tout[i]); + } + + memcpy(out, out_32, AES_BLOCKSIZE); + out += AES_BLOCKSIZE; + } + + for (i = 0; i < 4; i++) + iv[i] = htonl(tout[i]); + memcpy(ctx->iv, iv, AES_IV_SIZE); +} + +/** + * 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) +{ + int i; + uint32_t tin[4], xor[4], tout[4], data[4], iv[4]; + + memcpy(iv, ctx->iv, AES_IV_SIZE); + for (i = 0; i < 4; i++) + xor[i] = ntohl(iv[i]); + + for (length -= 16; length >= 0; length -= 16) + { + uint32_t msg_32[4]; + uint32_t out_32[4]; + memcpy(msg_32, msg, AES_BLOCKSIZE); + msg += AES_BLOCKSIZE; + + for (i = 0; i < 4; i++) + { + tin[i] = ntohl(msg_32[i]); + data[i] = tin[i]; + } + + AES_decrypt(ctx, data); + + for (i = 0; i < 4; i++) + { + tout[i] = data[i]^xor[i]; + xor[i] = tin[i]; + out_32[i] = htonl(tout[i]); + } + + memcpy(out, out_32, AES_BLOCKSIZE); + out += AES_BLOCKSIZE; + } + + for (i = 0; i < 4; i++) + iv[i] = htonl(xor[i]); + memcpy(ctx->iv, iv, AES_IV_SIZE); +} + +/** + * 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; + const uint32_t *k = 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/crypto/aes.o b/crypto/aes.o new file mode 100644 index 0000000000000000000000000000000000000000..2d10e6d61b32126958a595851154435673e62722 GIT binary patch literal 35312 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 t!(2xi=Knf2JW(*$dB$J8UxT!HEfM})+Zma4g13 + * and GMP . It gets most of its implementation + * detail from "The Handbook of Applied Cryptography" + * + * @{ + */ + +#include +#include +#include +#include +#include +#include "os_port.h" +#include "bigint.h" + +#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 */ + +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 *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); +#else +#define check(A) /**< disappears in normal production mode */ +#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) +{ + 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(); + } + + bi_clear_cache(ctx); + free(ctx); +} + +/** + *@brief Clear the memory cache. + */ +void bi_clear_cache(BI_CTX *ctx) +{ + bigint *p, *pn; + + if (ctx->free_list == NULL) + return; + + for (p = ctx->free_list; p != NULL; p = pn) + { + pn = p->next; + free(p->comps); + free(p); + } + + ctx->free_count = 0; + ctx->free_list = NULL; +} + +/** + * @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, bigint *biR, comp denom) +{ + int i = biR->size - 1; + long_comp r = 0; + + check(biR); + + do + { + r = (r<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) + { + goto buf_done; + } + } + } +buf_done: + + 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. + * + * 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 *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, + int inner_partial, int outer_partial) +{ + int i = 0, 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)); + + do + { + long_comp tmp; + comp carry = 0; + int r_index = i; + j = 0; + + if (outer_partial && outer_partial-i > 0 && outer_partial < n) + { + r_index = outer_partial-1; + j = outer_partial-i-1; + } + + do + { + if (inner_partial && r_index >= inner_partial) + { + break; + } + + tmp = sr[r_index] + ((long_comp)sa[j])*sb[i] + carry; + sr[r_index++] = (comp)tmp; /* downsize */ + carry = tmp >> COMP_BIT_SIZE; + } while (++j < n); + + sr[r_index] = 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, 0, 0); + } + + return karatsuba(ctx, bia, bib, 0); +#else + return regular_multiply(ctx, bia, bib, 0, 0); +#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+1); + comp *w = biR->comps; + comp *x = bi->comps; + long_comp carry; + memset(w, 0, biR->size*COMP_BYTE_SIZE); + + do + { + long_comp tmp = w[2*i] + (long_comp)x[i]*x[i]; + w[2*i] = (comp)tmp; + carry = tmp >> COMP_BIT_SIZE; + + for (j = i+1; j < t; j++) + { + uint8_t c = 0; + long_comp xx = (long_comp)x[i]*x[j]; + if ((COMP_MAX-xx) < xx) + c = 1; + + tmp = (xx<<1); + + if ((COMP_MAX-tmp) < w[i+j]) + c = 1; + + tmp += w[i+j]; + + if ((COMP_MAX-tmp) < carry) + c = 1; + + tmp += carry; + w[i+j] = (comp)tmp; + carry = tmp >> COMP_BIT_SIZE; + + if (c) + carry += COMP_RADIX; + } + + tmp = w[i+t] + carry; + w[i+t] = (comp)tmp; + w[i+t+1] = tmp >> COMP_BIT_SIZE; + } 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) != 0; +} + +#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; +} + +/** + * @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 = regular_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(regular_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. + * @return The result of the mod exponentiation operation + * @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. + * @return The result of the mod exponentiation operation + * @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 + +#ifdef CONFIG_BIGINT_CRT +/** + * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts. + * + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint to perform the exp/mod. + * @param dP [in] CRT's dP bigint + * @param dQ [in] CRT's dQ bigint + * @param p [in] CRT's p bigint + * @param q [in] CRT's q bigint + * @param qInv [in] CRT's qInv bigint + * @return The result of the CRT operation + */ +bigint *bi_crt(BI_CTX *ctx, bigint *bi, + bigint *dP, bigint *dQ, + bigint *p, bigint *q, bigint *qInv) +{ + 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), dP); + + ctx->mod_offset = BIGINT_Q_OFFSET; + m2 = bi_mod_power(ctx, bi, dQ); + + h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL); + h = bi_multiply(ctx, h, 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, q, h)); +} +#endif +/** @} */ diff --git a/crypto/bigint.h b/crypto/bigint.h new file mode 100644 index 000000000..2966a3edb --- /dev/null +++ b/crypto/bigint.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BIGINT_HEADER +#define BIGINT_HEADER + +#include "crypto.h" + +BI_CTX *bi_initialize(void); +void bi_terminate(BI_CTX *ctx); +void bi_permanent(bigint *bi); +void bi_depermanent(bigint *bi); +void bi_clear_cache(BI_CTX *ctx); +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 + +#ifdef CONFIG_BIGINT_CRT +bigint *bi_crt(BI_CTX *ctx, bigint *bi, + bigint *dP, bigint *dQ, + bigint *p, bigint *q, + bigint *qInv); +#endif + +#endif diff --git a/crypto/bigint.o b/crypto/bigint.o new file mode 100644 index 0000000000000000000000000000000000000000..f693e65a52a047cf7f70423bfec166164ec7f502 GIT binary patch literal 94704 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 A^8f$< literal 0 HcmV?d00001 diff --git a/crypto/bigint_impl.h b/crypto/bigint_impl.h new file mode 100644 index 000000000..fef6e0378 --- /dev/null +++ b/crypto/bigint_impl.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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 */ +#if defined(CONFIG_INTEGER_8BIT) +#define COMP_RADIX 256U /**< Max component + 1 */ +#define COMP_MAX 0xFFFFU/**< (Max dbl comp -1) */ +#define COMP_BIT_SIZE 8 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 1 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 2 /**< Used For diagnostics only. */ +typedef uint8_t comp; /**< A single precision component. */ +typedef uint16_t long_comp; /**< A double precision component. */ +typedef int16_t slong_comp; /**< A signed double precision component. */ +#elif defined(CONFIG_INTEGER_16BIT) +#define COMP_RADIX 65536U /**< Max component + 1 */ +#define COMP_MAX 0xFFFFFFFFU/**< (Max dbl comp -1) */ +#define COMP_BIT_SIZE 16 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 2 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 4 /**< Used For diagnostics only. */ +typedef uint16_t comp; /**< A single precision component. */ +typedef uint32_t long_comp; /**< A double precision component. */ +typedef int32_t slong_comp; /**< A signed double precision component. */ +#else /* regular 32 bit */ +#ifdef WIN32 +#define COMP_RADIX 4294967296i64 +#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64 +#else +#define COMP_RADIX 4294967296ULL /**< Max component + 1 */ +#define COMP_MAX 0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */ +#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. */ +#endif + +/** + * @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. */ + +#endif diff --git a/crypto/crypto.h b/crypto/crypto.h new file mode 100644 index 000000000..8a314a332 --- /dev/null +++ b/crypto/crypto.h @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file crypto.h + */ + +#ifndef HEADER_CRYPTO_H +#define HEADER_CRYPTO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "config.h" +#include "bigint_impl.h" +#include "bigint.h" + +#ifndef STDCALL +#define STDCALL +#endif +#ifndef EXP_FUNC +#define EXP_FUNC +#endif + + +/* 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 + +/************************************************************************** + * AES declarations + **************************************************************************/ + +#define AES_MAXROUNDS 14 +#define AES_BLOCKSIZE 16 +#define AES_IV_SIZE 16 + +typedef struct aes_key_st +{ + uint16_t rounds; + uint16_t key_size; + uint32_t ks[(AES_MAXROUNDS+1)*8]; + uint8_t iv[AES_IV_SIZE]; +} 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 +{ + uint8_t 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 SHA1_Init(SHA1_CTX *); +void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len); +void SHA1_Final(uint8_t *digest, SHA1_CTX *); + +/************************************************************************** + * MD2 declarations + **************************************************************************/ + +#define MD2_SIZE 16 + +typedef struct +{ + unsigned char cksum[16]; /* checksum of the data block */ + unsigned char state[48]; /* intermediate digest state */ + unsigned char buffer[16]; /* data block being processed */ + int left; /* amount of data in buffer */ +} MD2_CTX; + +EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx); +EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen); +EXP_FUNC void STDCALL MD2_Final(uint8_t *digest, MD2_CTX *ctx); + +/************************************************************************** + * MD5 declarations + **************************************************************************/ + +#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; + +EXP_FUNC void STDCALL MD5_Init(MD5_CTX *); +EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len); +EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *); + +/************************************************************************** + * 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); + +/************************************************************************** + * 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; + 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); +#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT) +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 + +/************************************************************************** + * RNG declarations + **************************************************************************/ +EXP_FUNC void STDCALL RNG_initialize(void); +EXP_FUNC void STDCALL RNG_custom_init(const uint8_t *seed_buf, int size); +EXP_FUNC void STDCALL RNG_terminate(void); +EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data); +void get_random_NZ(int num_rand_bytes, uint8_t *rand_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/crypto/crypto_misc.c b/crypto/crypto_misc.c new file mode 100644 index 000000000..62eb6fe70 --- /dev/null +++ b/crypto/crypto_misc.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Some misc. routines to help things out + */ + +#include +#include +#include +#include +#include "os_port.h" +#include "crypto_misc.h" +#ifdef CONFIG_WIN32_USE_CRYPTO_LIB +#include "wincrypt.h" +#endif + +#ifndef WIN32 +static int rng_fd = -1; +#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB) +static HCRYPTPROV gCryptProv; +#endif + +#if (!defined(CONFIG_USE_DEV_URANDOM) && !defined(CONFIG_WIN32_USE_CRYPTO_LIB)) +/* change to processor registers as appropriate */ +#define ENTROPY_POOL_SIZE 32 +#define ENTROPY_COUNTER1 ((((uint64_t)tv.tv_sec)<<32) | tv.tv_usec) +#define ENTROPY_COUNTER2 rand() +static uint8_t entropy_pool[ENTROPY_POOL_SIZE]; +#endif + +const char * const unsupported_str = "Error: Feature not supported\n"; + +#ifndef CONFIG_SSL_SKELETON_MODE +/** + * Retrieve a file and put it into memory + * @return The size of the file, or -1 on failure. + */ +int get_file(const char *filename, uint8_t **buf) +{ + int total_bytes = 0; + int bytes_read = 0; + int filesize; + FILE *stream = fopen(filename, "rb"); + + if (stream == NULL) + { +#ifdef CONFIG_SSL_FULL_MODE + printf("file '%s' does not exist\n", filename); TTY_FLUSH(); +#endif + return -1; + } + + /* Win CE doesn't support stat() */ + fseek(stream, 0, SEEK_END); + filesize = ftell(stream); + *buf = (uint8_t *)malloc(filesize); + fseek(stream, 0, SEEK_SET); + + do + { + bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream); + total_bytes += bytes_read; + } while (total_bytes < filesize && bytes_read > 0); + + fclose(stream); + return filesize; +} +#endif + +/** + * Initialise the Random Number Generator engine. + * - On Win32 use the platform SDK's crypto engine. + * - On Linux use /dev/urandom + * - If none of these work then use a custom RNG. + */ +EXP_FUNC void STDCALL RNG_initialize() +{ +#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM) + rng_fd = ax_open("/dev/urandom", O_RDONLY); +#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB) + if (!CryptAcquireContext(&gCryptProv, + NULL, NULL, PROV_RSA_FULL, 0)) + { + if (GetLastError() == NTE_BAD_KEYSET && + !CryptAcquireContext(&gCryptProv, + NULL, + NULL, + PROV_RSA_FULL, + CRYPT_NEWKEYSET)) + { + printf("CryptoLib: %x\n", unsupported_str, GetLastError()); + exit(1); + } + } +#else + /* start of with a stack to copy across */ + int i; + memcpy(entropy_pool, &i, ENTROPY_POOL_SIZE); + srand((unsigned int)&i); +#endif +} + +/** + * If no /dev/urandom, then initialise the RNG with something interesting. + */ +EXP_FUNC void STDCALL RNG_custom_init(const uint8_t *seed_buf, int size) +{ +#if defined(WIN32) || defined(CONFIG_WIN32_USE_CRYPTO_LIB) + int i; + + for (i = 0; i < ENTROPY_POOL_SIZE && i < size; i++) + entropy_pool[i] ^= seed_buf[i]; +#endif +} + +/** + * Terminate the RNG engine. + */ +EXP_FUNC void STDCALL RNG_terminate(void) +{ +#ifndef WIN32 + close(rng_fd); +#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB) + CryptReleaseContext(gCryptProv, 0); +#endif +} + +/** + * Set a series of bytes with a random number. Individual bytes can be 0 + */ +EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data) +{ +#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM) + /* use the Linux default */ + read(rng_fd, rand_data, num_rand_bytes); /* read from /dev/urandom */ +#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB) + /* use Microsoft Crypto Libraries */ + CryptGenRandom(gCryptProv, num_rand_bytes, rand_data); +#else /* nothing else to use, so use a custom RNG */ + /* The method we use when we've got nothing better. Use RC4, time + and a couple of random seeds to generate a random sequence */ + RC4_CTX rng_ctx; + struct timeval tv; + MD5_CTX rng_digest_ctx; + uint8_t digest[MD5_SIZE]; + uint64_t *ep; + int i; + + /* A proper implementation would use counters etc for entropy */ + gettimeofday(&tv, NULL); + ep = (uint64_t *)entropy_pool; + ep[0] ^= ENTROPY_COUNTER1; + ep[1] ^= ENTROPY_COUNTER2; + + /* use a digested version of the entropy pool as a key */ + MD5_Init(&rng_digest_ctx); + MD5_Update(&rng_digest_ctx, entropy_pool, ENTROPY_POOL_SIZE); + MD5_Final(digest, &rng_digest_ctx); + + /* come up with the random sequence */ + RC4_setup(&rng_ctx, digest, MD5_SIZE); /* use as a key */ + memcpy(rand_data, entropy_pool, num_rand_bytes < ENTROPY_POOL_SIZE ? + num_rand_bytes : ENTROPY_POOL_SIZE); + RC4_crypt(&rng_ctx, rand_data, rand_data, num_rand_bytes); + + /* move things along */ + for (i = ENTROPY_POOL_SIZE-1; i >= MD5_SIZE ; i--) + entropy_pool[i] = entropy_pool[i-MD5_SIZE]; + + /* insert the digest at the start of the entropy pool */ + memcpy(entropy_pool, digest, MD5_SIZE); +#endif +} + +/** + * Set a series of bytes with a random number. Individual bytes are not zero. + */ +void get_random_NZ(int num_rand_bytes, uint8_t *rand_data) +{ + int i; + get_random(num_rand_bytes, rand_data); + + for (i = 0; i < num_rand_bytes; i++) + { + while (rand_data[i] == 0) /* can't be 0 */ + rand_data[i] = (uint8_t)(rand()); + } +} + +/** + * Some useful diagnostic routines + */ +#if defined(CONFIG_SSL_FULL_MODE) || defined(CONFIG_DEBUG) +int hex_finish; +int hex_index; + +static void print_hex_init(int finish) +{ + hex_finish = finish; + hex_index = 0; +} + +static void print_hex(uint8_t hex) +{ + static int column; + + if (hex_index == 0) + { + column = 0; + } + + printf("%02x ", hex); + if (++column == 8) + { + printf(": "); + } + else if (column >= 16) + { + printf("\n"); + column = 0; + } + + if (++hex_index >= hex_finish && column > 0) + { + printf("\n"); + } +} + +/** + * Spit out a blob of data for diagnostics. The data is is a nice column format + * for easy reading. + * + * @param format [in] The string (with possible embedded format characters) + * @param size [in] The number of numbers to print + * @param data [in] The start of data to use + * @param ... [in] Any additional arguments + */ +EXP_FUNC void STDCALL print_blob(const char *format, + const uint8_t *data, int size, ...) +{ + int i; + char tmp[80]; + va_list(ap); + + va_start(ap, size); + sprintf(tmp, "%s\n", format); + vprintf(tmp, ap); + print_hex_init(size); + for (i = 0; i < size; i++) + { + print_hex(data[i]); + } + + va_end(ap); + TTY_FLUSH(); +} +#elif defined(WIN32) +/* VC6.0 doesn't handle variadic macros */ +EXP_FUNC void STDCALL print_blob(const char *format, const unsigned char *data, + int size, ...) {} +#endif + +#if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION) +/* base64 to binary lookup table */ +static const uint8_t map[128] = +{ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, + 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, + 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 255, 255, 255, 255, 255 +}; + +EXP_FUNC int STDCALL base64_decode(const char *in, int len, + uint8_t *out, int *outlen) +{ + int g, t, x, y, z; + uint8_t c; + int ret = -1; + + g = 3; + for (x = y = z = t = 0; x < len; x++) + { + if ((c = map[in[x]&0x7F]) == 0xff) + continue; + + if (c == 254) /* this is the end... */ + { + c = 0; + + if (--g < 0) + goto error; + } + else if (g != 3) /* only allow = at end */ + goto error; + + t = (t<<6) | c; + + if (++y == 4) + { + out[z++] = (uint8_t)((t>>16)&255); + + if (g > 1) + out[z++] = (uint8_t)((t>>8)&255); + + if (g > 2) + out[z++] = (uint8_t)(t&255); + + y = t = 0; + } + + /* check that we don't go past the output buffer */ + if (z > *outlen) + goto error; + } + + if (y != 0) + goto error; + + *outlen = z; + ret = 0; + +error: +#ifdef CONFIG_SSL_FULL_MODE + if (ret < 0) + printf("Error: Invalid base64\n"); TTY_FLUSH(); +#endif + TTY_FLUSH(); + return ret; + +} +#endif + diff --git a/crypto/hmac.c b/crypto/hmac.c new file mode 100644 index 000000000..24a04d77a --- /dev/null +++ b/crypto/hmac.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * HMAC implementation - This code was originally taken from RFC2104 + * See http://www.ietf.org/rfc/rfc2104.txt and + * http://www.faqs.org/rfcs/rfc2202.html + */ + +#include +#include "os_port.h" +#include "crypto.h" + +/** + * Perform HMAC-MD5 + * NOTE: does not handle keys larger than the block size. + */ +void hmac_md5(const uint8_t *msg, int length, const uint8_t *key, + int key_len, uint8_t *digest) +{ + MD5_CTX context; + uint8_t k_ipad[64]; + uint8_t k_opad[64]; + int i; + + memset(k_ipad, 0, sizeof k_ipad); + memset(k_opad, 0, sizeof k_opad); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + for (i = 0; i < 64; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + MD5_Init(&context); + MD5_Update(&context, k_ipad, 64); + MD5_Update(&context, msg, length); + MD5_Final(digest, &context); + MD5_Init(&context); + MD5_Update(&context, k_opad, 64); + MD5_Update(&context, digest, MD5_SIZE); + MD5_Final(digest, &context); +} + +/** + * Perform HMAC-SHA1 + * NOTE: does not handle keys larger than the block size. + */ +void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, + int key_len, uint8_t *digest) +{ + SHA1_CTX context; + uint8_t k_ipad[64]; + uint8_t k_opad[64]; + int i; + + memset(k_ipad, 0, sizeof k_ipad); + memset(k_opad, 0, sizeof k_opad); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + for (i = 0; i < 64; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + SHA1_Init(&context); + SHA1_Update(&context, k_ipad, 64); + SHA1_Update(&context, msg, length); + SHA1_Final(digest, &context); + SHA1_Init(&context); + SHA1_Update(&context, k_opad, 64); + SHA1_Update(&context, digest, SHA1_SIZE); + SHA1_Final(digest, &context); +} diff --git a/crypto/hmac.o b/crypto/hmac.o new file mode 100644 index 0000000000000000000000000000000000000000..69cf2c4ffaf1b84ac3c043ffcfffe464d200d0bf GIT binary patch literal 10444 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 +#include +#include "os_port.h" +#include "crypto.h" + +/** + * This code is only here to enable the verification of Verisign root + * certificates. So only enable it for verification mode. + */ +#ifdef CONFIG_SSL_CERT_VERIFICATION + +static const uint8_t PI_SUBST[256] = +{ + 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, + 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3, + 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, + 0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, + 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 0xBE, 0x4E, + 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, + 0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, + 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, + 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, + 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 0xFF, 0x19, 0x30, 0xB3, + 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, + 0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, + 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D, + 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, + 0xE6, 0x2D, 0xA8, 0x02, 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, + 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, + 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, + 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E, + 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, + 0x4D, 0x52, 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, + 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88, + 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, + 0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, + 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, + 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, + 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14 +}; + +/* + * MD2 context setup + */ +EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx) +{ + memset(ctx, 0, sizeof *ctx); +} + +static void md2_process(MD2_CTX *ctx) +{ + int i, j; + uint8_t t = 0; + + for (i = 0; i < 16; i++) + { + ctx->state[i + 16] = ctx->buffer[i]; + ctx->state[i + 32] = ctx->buffer[i] ^ ctx->state[i]; + } + + for (i = 0; i < 18; i++) + { + for (j = 0; j < 48; j++) + t = (ctx->state[j] ^= PI_SUBST[t]); + + t = (t + i) & 0xFF; + } + + t = ctx->cksum[15]; + + for (i = 0; i < 16; i++) + t = (ctx->cksum[i] ^= PI_SUBST[ctx->buffer[i] ^ t]); +} + +/* + * MD2 process buffer + */ +EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen) +{ + int fill; + + while (ilen > 0) + { + if (ctx->left + ilen > 16) + fill = 16 - ctx->left; + else + fill = ilen; + + memcpy(ctx->buffer + ctx->left, input, fill); + + ctx->left += fill; + input += fill; + ilen -= fill; + + if (ctx->left == 16) + { + ctx->left = 0; + md2_process(ctx); + } + } +} + +/* + * MD2 final digest + */ +EXP_FUNC void STDCALL MD2_Final(uint8_t *output, MD2_CTX *ctx) +{ + int i; + uint8_t x; + + x = (uint8_t)(16 - ctx->left); + + for (i = ctx->left; i < 16; i++) + ctx->buffer[i] = x; + + md2_process(ctx); + + memcpy(ctx->buffer, ctx->cksum, 16); + md2_process(ctx); + + memcpy(output, ctx->state, 16); +} + +#endif diff --git a/crypto/md2.o b/crypto/md2.o new file mode 100644 index 0000000000000000000000000000000000000000..46d054d9e05ed333f27f95b69b909ea413b7557c GIT binary patch literal 9808 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 literal 0 HcmV?d00001 diff --git a/crypto/md5.c b/crypto/md5.c new file mode 100644 index 000000000..7f5071300 --- /dev/null +++ b/crypto/md5.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This file implements the MD5 algorithm as defined in RFC1321 + */ + +#include +#include "os_port.h" +#include "crypto.h" + +/* Constants for MD5Transform routine. + */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +/* ----- static functions ----- */ +static void MD5Transform(uint32_t state[4], const uint8_t block[64]); +static void Encode(uint8_t *output, uint32_t *input, uint32_t len); +static void Decode(uint32_t *output, const uint8_t *input, uint32_t len); + +static const uint8_t PADDING[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + Rotation is separate from addition to prevent recomputation. */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/** + * MD5 initialization - begins an MD5 operation, writing a new ctx. + */ +EXP_FUNC void STDCALL MD5_Init(MD5_CTX *ctx) +{ + ctx->count[0] = ctx->count[1] = 0; + + /* Load magic initialization constants. + */ + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xefcdab89; + ctx->state[2] = 0x98badcfe; + ctx->state[3] = 0x10325476; +} + +/** + * Accepts an array of octets as the next portion of the message. + */ +EXP_FUNC void STDCALL MD5_Update(MD5_CTX *ctx, const uint8_t * msg, int len) +{ + uint32_t x; + int i, partLen; + + /* Compute number of bytes mod 64 */ + x = (uint32_t)((ctx->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((ctx->count[0] += ((uint32_t)len << 3)) < ((uint32_t)len << 3)) + ctx->count[1]++; + ctx->count[1] += ((uint32_t)len >> 29); + + partLen = 64 - x; + + /* Transform as many times as possible. */ + if (len >= partLen) + { + memcpy(&ctx->buffer[x], msg, partLen); + MD5Transform(ctx->state, ctx->buffer); + + for (i = partLen; i + 63 < len; i += 64) + MD5Transform(ctx->state, &msg[i]); + + x = 0; + } + else + i = 0; + + /* Buffer remaining input */ + memcpy(&ctx->buffer[x], &msg[i], len-i); +} + +/** + * Return the 128-bit message digest into the user's array + */ +EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *ctx) +{ + uint8_t bits[8]; + uint32_t x, padLen; + + /* Save number of bits */ + Encode(bits, ctx->count, 8); + + /* Pad out to 56 mod 64. + */ + x = (uint32_t)((ctx->count[0] >> 3) & 0x3f); + padLen = (x < 56) ? (56 - x) : (120 - x); + MD5_Update(ctx, PADDING, padLen); + + /* Append length (before padding) */ + MD5_Update(ctx, bits, 8); + + /* Store state in digest */ + Encode(digest, ctx->state, MD5_SIZE); +} + +/** + * MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform(uint32_t state[4], const uint8_t block[64]) +{ + uint32_t a = state[0], b = state[1], c = state[2], + d = state[3], x[MD5_SIZE]; + + Decode(x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; +} + +/** + * Encodes input (uint32_t) into output (uint8_t). Assumes len is + * a multiple of 4. + */ +static void Encode(uint8_t *output, uint32_t *input, uint32_t len) +{ + uint32_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[j] = (uint8_t)(input[i] & 0xff); + output[j+1] = (uint8_t)((input[i] >> 8) & 0xff); + output[j+2] = (uint8_t)((input[i] >> 16) & 0xff); + output[j+3] = (uint8_t)((input[i] >> 24) & 0xff); + } +} + +/** + * Decodes input (uint8_t) into output (uint32_t). Assumes len is + * a multiple of 4. + */ +static void Decode(uint32_t *output, const uint8_t *input, uint32_t len) +{ + uint32_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) | + (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24); +} diff --git a/crypto/md5.o b/crypto/md5.o new file mode 100644 index 0000000000000000000000000000000000000000..3bb00b7a4309c39bc8e25351f7642c3b8f4a74bb GIT binary patch literal 19348 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 literal 0 HcmV?d00001 diff --git a/crypto/os_int.h b/crypto/os_int.h new file mode 100644 index 000000000..878856723 --- /dev/null +++ b/crypto/os_int.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file os_int.h + * + * Ensure a consistent bit size + */ + +#ifndef HEADER_OS_INT_H +#define HEADER_OS_INT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(WIN32) +typedef UINT8 uint8_t; +typedef INT8 int8_t; +typedef UINT16 uint16_t; +typedef INT16 int16_t; +typedef UINT32 uint32_t; +typedef INT32 int32_t; +typedef UINT64 uint64_t; +typedef INT64 int64_t; +#else /* Not Win32 */ + +#ifdef CONFIG_PLATFORM_SOLARIS +#include +#else +#include +#endif /* Not Solaris */ + +#endif /* Not Win32 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/crypto/rc4.c b/crypto/rc4.c new file mode 100644 index 000000000..12a121151 --- /dev/null +++ b/crypto/rc4.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * An implementation of the RC4/ARC4 algorithm. + * Originally written by Christophe Devine. + */ + +#include +#include "os_port.h" +#include "crypto.h" + +/** + * Get ready for an encrypt/decrypt operation + */ +void RC4_setup(RC4_CTX *ctx, const uint8_t *key, int length) +{ + int i, j = 0, k = 0, a; + uint8_t *m; + + ctx->x = 0; + ctx->y = 0; + m = ctx->m; + + for (i = 0; i < 256; i++) + m[i] = i; + + for (i = 0; i < 256; i++) + { + a = m[i]; + j = (uint8_t)(j + a + key[k]); + m[i] = m[j]; + m[j] = a; + + if (++k >= length) + k = 0; + } +} + +/** + * Perform the encrypt/decrypt operation (can use it for either since + * this is a stream cipher). + * NOTE: *msg and *out must be the same pointer (performance tweak) + */ +void RC4_crypt(RC4_CTX *ctx, const uint8_t *msg, uint8_t *out, int length) +{ + int i; + uint8_t *m, x, y, a, b; + + x = ctx->x; + y = ctx->y; + m = ctx->m; + + for (i = 0; i < length; i++) + { + a = m[++x]; + y += a; + m[x] = b = m[y]; + m[y] = a; + out[i] ^= m[(uint8_t)(a + b)]; + } + + ctx->x = x; + ctx->y = y; +} diff --git a/crypto/rc4.o b/crypto/rc4.o new file mode 100644 index 0000000000000000000000000000000000000000..104525ceec999c31adb503b09319f55875470aae GIT binary patch literal 6232 zcma)=YiwM_6~|}pKD_Jo+XNDvs_XD*9_+4dg^&aS#CC|CLQ;R9`&Dxw%g2viDEMMYcGRstz%(^jnztyDlNAQePu`9LW}w5dq{|G6{k zV?b(;GjfTaagNXsuijsGSsVvdi92f z);y}#?_aY+b*!0u|DO$!RQ#D&^ey@12~QoUR_fHD>7$be5Bi4|&eW-n(KEg3#7?;G zyh1lbe*DlYjqf35+Y9f#()p|IcUoWa)VQZNR32Z^cgxx1FFug$xcB&R|Lafm)T^x~ z$f;-IYU|&g*`?li)bANoPhRs-SoMTd*OsoHe$~Y#qKM4H;Oima& zp87^S&0Kw#I^@|PQ=X3Ypup3yMp!&AlAz|*rJ#kvkwVE=Ubyb3EQ>`r3tp`59J6p_ z9X-Q!ZyT+ygPD$fj4b>*9-;MD;TiF?H}(`DIHUneUp0r>vF7jy)E4%$Im~D43KkEz70?eSOrHkW zCp}a@Q=LL7d-NQf>&tUKR7QLiYMbfez;@tyBzAHa6;3Ie-ff!xVk5@5n{8EKZ^Q_V z@;xf(uTg$aW!x(7LqX%M`iiFZM5w8wsa3Z{TQ0#&Uak^}>tVvWSd3wvE>@wYt%++B zgY8(UcAbb&(NLm|DijM!c&h5O9&D#Q)~N>DGqA+d`i50Otq@)w_x=^^sat z4=pEzx>Dgh)|&L7Hf~(z+$2<#HaDZ!>|4u~Xcja6nT=vLMNl+pgu7X*A!gh)A+>PV zqA9?m9?9%>)wRf+TNl2a$ZkN2s)|}rs~5@rNOjPX6}4uO3WGTZU`<%rLpTF;jpMx?{YG6yPJjWT--DWvA~BEf|- zCD4_+9f@(+apvDds#89i99g|cSZple6LEyk`09P_;ha)QG2f&A_U2m4#WqtTLn3e5INxOjXKk2PNt3>};m5T=MfJRNIw3 zlFdw`(jD1K-UZ2(XB=kya=BQ|%)`5yO%><6yEdir#mP?_3Z-0eZX%EA%WX{OFo7!Q zbb6Xx^(SzNgUtj)%rmq>hr)4;E~MiT^Tc~5ucUR z-T)4n`d?v9)C!_3MVvSGdSj0n&u~0m^K|~KduKdq+m6!P_5!VaqCXy^7~5U7-g>nf zrnk0+i*hvHg81=xGoHpXbc}5Uy+t%Eb}(I;VEX1t)xuOMKatE~ZB(&bno8D8d>dA$ z%N2jQY3I$O$-d;q^yYL=GBv|0xoojm1((VxKR@rMs@N!naw%0T`1wkfMN`StUSxYw z11q#Gw`EH*H3|1ZsaPoGQJ1?Kf&imLJ`EIqWYo@cG?lCr{zj+KjFC5ML z3$yuPP{xk~GUFWT+c?%Yvd@l=W?Ia|7^>#|x!ItinFKjS`O=h+lfJXBZ)w>8<-!Ms@F{FKFSC0*rCd+Dcc*ofG-r>D_Mn`sx?HL@|F|>Wp z@V2h{?Y)EBx_MVy39k(xxVnQY{34jvAax>LX1O0Z*45Z~!BS$V%gggpBpw0YHrFGu zE-#B#%kEZ)L09SO!i=9CNA6dGeA-bZU(BYtv?@K3^|LBHUahLMu}L6f^X`MPvW`{gZ4U5ET)B-UqH1JadN=cg&A^zUxu>>u|9%h(X5>x8 zdjo}xSBK={jeuPpIqIw*)ETTYxfSY zY^Hai8m3;lD!EdB_7^8_o- z?>YyF z3O-1-ZB3GG{6kGM)1pm-xADU<*uI`gBut3nPWENn0JKZ zq+sqVXLoxECUdVk`!&MnTERO7?-smI@RtP73ibuxDfqbHdj#Jv__W|h1V1kLNx{zv z=00)bIxCoa#@SyL{F>mm1ivHrykK6OE>09{_k(#~k$HBDmig}B-k^OHJa3ujn0tfv+rW2Qz8(CajV!79ua&{a8dAo0Urm0#Q*>R literal 0 HcmV?d00001 diff --git a/crypto/rsa.c b/crypto/rsa.c new file mode 100644 index 000000000..143e66add --- /dev/null +++ b/crypto/rsa.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Implements the RSA public encryption algorithm. Uses the bigint library to + * perform its calculations. + */ + +#include +#include +#include +#include +#include "os_port.h" +#include "crypto.h" + +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; + + if (*ctx) /* if we load multiple certs, dump the old one */ + RSA_free(*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; + 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) +{ + const int byte_size = ctx->num_octets; + int i, size; + bigint *decrypted_bi, *dat_bi; + uint8_t *block = (uint8_t *)alloca(byte_size); + + 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 */ + 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); + + 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_ctx, bi_msg, c->dP, c->dQ, c->p, c->q, c->qInv); +#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_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 + +#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT) +/** + * 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); + + /* save a few bytes of memory */ + bi_clear_cache(ctx->bi_ctx); + return byte_size; +} + +#endif /* CONFIG_SSL_CERT_VERIFICATION */ diff --git a/crypto/rsa.o b/crypto/rsa.o new file mode 100644 index 0000000000000000000000000000000000000000..320410453e6cc58e9a49c78d923a2f93303eb47c GIT binary patch literal 25612 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 G;Qs +#include "os_port.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 SHA1_Init(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 SHA1_Update(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 SHA1_Final(uint8_t *digest, SHA1_CTX *ctx) +{ + 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/crypto/sha1.o b/crypto/sha1.o new file mode 100644 index 0000000000000000000000000000000000000000..ba9443f4f713ad41c46b1ac272d819d8640fcad7 GIT binary patch literal 13688 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 An*aa+ literal 0 HcmV?d00001 diff --git a/ssl/asn1.c b/ssl/asn1.c new file mode 100644 index 000000000..b082275b2 --- /dev/null +++ b/ssl/asn1.c @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Some primitive asn methods for extraction ASN.1 data. + */ + +#include +#include +#include +#include +#include "os_port.h" +#include "crypto.h" +#include "crypto_misc.h" + +#define SIG_OID_PREFIX_SIZE 8 +#define SIG_IIS6_OID_SIZE 5 +#define SIG_SUBJECT_ALT_NAME_SIZE 3 + +/* 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 +}; + +static const uint8_t sig_sha1WithRSAEncrypt[SIG_IIS6_OID_SIZE] = +{ + 0x2b, 0x0e, 0x03, 0x02, 0x1d +}; + +static const uint8_t sig_subject_alt_name[SIG_SUBJECT_ALT_NAME_SIZE] = +{ + 0x55, 0x1d, 0x11 +}; + +/* CN, O, OU */ +static const uint8_t g_dn_types[] = { 3, 10, 11 }; + +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; + + if (len > 1 && buf[*offset] == 0x00) /* ignore the negative byte */ + { + len--; + (*offset)++; + } + + *object = (uint8_t *)malloc(len); + memcpy(*object, &buf[*offset], len); + *offset += len; + +end_int_array: + return len; +} + +/** + * 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 = NULL, *priv_exp = NULL, *pub_exp = NULL; + int mod_len, priv_len, pub_len; +#ifdef CONFIG_BIGINT_CRT + uint8_t *p = NULL, *q = NULL, *dP = NULL, *dQ = NULL, *qInv = NULL; + 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; + } + + /* Use the private key to mix up the RNG if possible. */ + RNG_custom_init(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) + */ +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. + */ +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; + int asn1_type = buf[*offset]; + + /* some certs have this awful crud in them for some reason */ + if (asn1_type != ASN1_PRINTABLE_STR && + asn1_type != ASN1_PRINTABLE_STR2 && + asn1_type != ASN1_TELETEX_STR && + asn1_type != ASN1_IA5_STR && + asn1_type != ASN1_UNICODE_STR) + goto end_pnt_str; + + (*offset)++; + len = get_asn1_length(buf, offset); + + if (asn1_type == ASN1_UNICODE_STR) + { + int i; + *str = (char *)malloc(len/2+1); /* allow for null */ + + for (i = 0; i < len; i += 2) + (*str)[i/2] = buf[*offset + i + 1]; + + (*str)[len/2] = 0; /* null terminate */ + } + else + { + *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. + */ +int asn1_name(const uint8_t *cert, int *offset, char *dn[]) +{ + int ret = X509_NOT_OK; + int dn_type; + char *tmp; + + 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; + + tmp = NULL; + + 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. + */ +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 = NULL, *pub_exp = NULL; + + 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)++; /* ignore the padding bit field */ + + 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. + */ +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)-1; + (*offset)++; /* ignore bit string padding bits */ + 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; + + if (dn1 == NULL && dn2 == NULL) + ret = 0; + else + ret = (dn1 && dn2) ? strcmp(dn1, dn2) : 1; + + return ret; +} + +/** + * Clean up all of the CA certificates. + */ +void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx) +{ + int i = 0; + + if (ca_cert_ctx == NULL) + return; + + 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 + */ +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 */ +} + +int asn1_find_oid(const uint8_t* cert, int* offset, + const uint8_t* oid, int oid_length) +{ + int seqlen; + if ((seqlen = asn1_next_obj(cert, offset, ASN1_SEQUENCE))> 0) + { + int end = *offset + seqlen; + + while (*offset < end) + { + int type = cert[(*offset)++]; + int length = get_asn1_length(cert, offset); + int noffset = *offset + length; + + if (type == ASN1_SEQUENCE) + { + type = cert[(*offset)++]; + length = get_asn1_length(cert, offset); + + if (type == ASN1_OID && length == oid_length && + memcmp(cert + *offset, oid, oid_length) == 0) + { + *offset += oid_length; + return 1; + } + } + + *offset = noffset; + } + } + + return 0; +} + +int asn1_find_subjectaltname(const uint8_t* cert, int offset) +{ + if (asn1_find_oid(cert, &offset, sig_subject_alt_name, + SIG_SUBJECT_ALT_NAME_SIZE)) + { + return offset; + } + + return 0; +} + +#endif /* CONFIG_SSL_CERT_VERIFICATION */ + +/** + * Read the signature type of the certificate. We only support RSA-MD5 and + * RSA-SHA1 signature types. + */ +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 (len == 5 && memcmp(sig_sha1WithRSAEncrypt, &cert[*offset], + SIG_IIS6_OID_SIZE) == 0) + { + x509_ctx->sig_type = SIG_TYPE_SHA1; + } + else + { + 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; + asn1_skip_obj(cert, offset, ASN1_NULL); /* if it's there */ + ret = X509_OK; + +end_check_sig: + return ret; +} + diff --git a/ssl/asn1.o b/ssl/asn1.o new file mode 100644 index 0000000000000000000000000000000000000000..7f8f449c11af05a9cbd3901e0328945bdcecc67b GIT binary patch literal 48176 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 i=ChFHm5MojV vCMH2%N!fA?@n?^V~EdL)ENaHa8 literal 0 HcmV?d00001 diff --git a/ssl/cert.h b/ssl/cert.h new file mode 100644 index 000000000..30c7b6588 --- /dev/null +++ b/ssl/cert.h @@ -0,0 +1,43 @@ +unsigned char default_certificate[] = { + 0x30, 0x82, 0x01, 0xd7, 0x30, 0x82, 0x01, 0x40, 0x02, 0x09, 0x00, 0xab, + 0x08, 0x18, 0xa7, 0x03, 0x07, 0x27, 0xfd, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x34, + 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x29, 0x61, + 0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x20, 0x44, 0x6f, 0x64, 0x67, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x31, 0x32, + 0x32, 0x36, 0x32, 0x32, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x17, 0x0d, 0x32, + 0x34, 0x30, 0x39, 0x30, 0x33, 0x32, 0x32, 0x33, 0x33, 0x33, 0x39, 0x5a, + 0x30, 0x2c, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0d, 0x61, 0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81, + 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, + 0x81, 0x81, 0x00, 0xcd, 0xfd, 0x89, 0x48, 0xbe, 0x36, 0xb9, 0x95, 0x76, + 0xd4, 0x13, 0x30, 0x0e, 0xbf, 0xb2, 0xed, 0x67, 0x0a, 0xc0, 0x16, 0x3f, + 0x51, 0x09, 0x9d, 0x29, 0x2f, 0xb2, 0x6d, 0x3f, 0x3e, 0x6c, 0x2f, 0x90, + 0x80, 0xa1, 0x71, 0xdf, 0xbe, 0x38, 0xc5, 0xcb, 0xa9, 0x9a, 0x40, 0x14, + 0x90, 0x0a, 0xf9, 0xb7, 0x07, 0x0b, 0xe1, 0xda, 0xe7, 0x09, 0xbf, 0x0d, + 0x57, 0x41, 0x86, 0x60, 0xa1, 0xc1, 0x27, 0x91, 0x5b, 0x0a, 0x98, 0x46, + 0x1b, 0xf6, 0xa2, 0x84, 0xf8, 0x65, 0xc7, 0xce, 0x2d, 0x96, 0x17, 0xaa, + 0x91, 0xf8, 0x61, 0x04, 0x50, 0x70, 0xeb, 0xb4, 0x43, 0xb7, 0xdc, 0x9a, + 0xcc, 0x31, 0x01, 0x14, 0xd4, 0xcd, 0xcc, 0xc2, 0x37, 0x6d, 0x69, 0x82, + 0xd6, 0xc6, 0xc4, 0xbe, 0xf2, 0x34, 0xa5, 0xc9, 0xa6, 0x19, 0x53, 0x32, + 0x7a, 0x86, 0x0e, 0x91, 0x82, 0x0f, 0xa1, 0x42, 0x54, 0xaa, 0x01, 0x02, + 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x40, + 0xb4, 0x94, 0x9a, 0xa8, 0x89, 0x72, 0x1d, 0x07, 0xe5, 0xb3, 0x6b, 0x88, + 0x21, 0xc2, 0x38, 0x36, 0x9e, 0x7a, 0x8c, 0x49, 0x48, 0x68, 0x0c, 0x06, + 0xe8, 0xdb, 0x1f, 0x4e, 0x05, 0xe6, 0x31, 0xe3, 0xfd, 0xe6, 0x0d, 0x6b, + 0xd8, 0x13, 0x17, 0xe0, 0x2d, 0x0d, 0xb8, 0x7e, 0xcb, 0x20, 0x6c, 0xa8, + 0x73, 0xa7, 0xfd, 0xe3, 0xa7, 0xfa, 0xf3, 0x02, 0x60, 0x78, 0x1f, 0x13, + 0x40, 0x45, 0xee, 0x75, 0xf5, 0x10, 0xfd, 0x8f, 0x68, 0x74, 0xd4, 0xac, + 0xae, 0x04, 0x09, 0x55, 0x2c, 0xdb, 0xd8, 0x07, 0x07, 0x65, 0x69, 0x27, + 0x6e, 0xbf, 0x5e, 0x61, 0x40, 0x56, 0x8b, 0xd7, 0x33, 0x3b, 0xff, 0x6e, + 0x53, 0x7e, 0x9d, 0x3f, 0xc0, 0x40, 0x3a, 0xab, 0xa0, 0x50, 0x4e, 0x80, + 0x47, 0x46, 0x0d, 0x1e, 0xdb, 0x4c, 0xf1, 0x1b, 0x5d, 0x3c, 0x2a, 0x54, + 0xa7, 0x4d, 0xfa, 0x7b, 0x72, 0x66, 0xc5 +}; +unsigned int default_certificate_len = 475; diff --git a/ssl/config.h b/ssl/config.h new file mode 100644 index 000000000..3404b5be5 --- /dev/null +++ b/ssl/config.h @@ -0,0 +1,127 @@ +/* + * Automatically generated header file: don't edit + */ + +#define HAVE_DOT_CONFIG 1 +#undef CONFIG_PLATFORM_LINUX +#define CONFIG_PLATFORM_CYGWIN 1 +#undef CONFIG_PLATFORM_WIN32 + +/* + * General Configuration + */ +#define PREFIX "/usr/local" +#define CONFIG_DEBUG 1 +#undef CONFIG_STRIP_UNWANTED_SECTIONS +#undef CONFIG_VISUAL_STUDIO_7_0 +#undef CONFIG_VISUAL_STUDIO_8_0 +#undef CONFIG_VISUAL_STUDIO_10_0 +#define CONFIG_VISUAL_STUDIO_7_0_BASE "" +#define CONFIG_VISUAL_STUDIO_8_0_BASE "" +#define CONFIG_VISUAL_STUDIO_10_0_BASE "" +#define CONFIG_EXTRA_CFLAGS_OPTIONS "" +#define CONFIG_EXTRA_LDFLAGS_OPTIONS "" + +/* + * SSL Library + */ +#undef CONFIG_SSL_SERVER_ONLY +#undef CONFIG_SSL_CERT_VERIFICATION +#undef CONFIG_SSL_ENABLE_CLIENT +#define CONFIG_SSL_FULL_MODE 1 +#undef CONFIG_SSL_SKELETON_MODE +#undef CONFIG_SSL_PROT_LOW +#define CONFIG_SSL_PROT_MEDIUM 1 +#undef CONFIG_SSL_PROT_HIGH +#define CONFIG_SSL_USE_DEFAULT_KEY +#define CONFIG_SSL_PRIVATE_KEY_LOCATION "" +#define CONFIG_SSL_PRIVATE_KEY_PASSWORD "" +#define CONFIG_SSL_X509_CERT_LOCATION "" +#undef CONFIG_SSL_GENERATE_X509_CERT +#define CONFIG_SSL_X509_COMMON_NAME "" +#define CONFIG_SSL_X509_ORGANIZATION_NAME "" +#define CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME "" +#undef CONFIG_SSL_ENABLE_V23_HANDSHAKE +#define CONFIG_SSL_HAS_PEM 1 +#undef CONFIG_SSL_USE_PKCS12 +#define CONFIG_SSL_EXPIRY_TIME 24 +#define CONFIG_X509_MAX_CA_CERTS 150 +#define CONFIG_SSL_MAX_CERTS 3 +#undef CONFIG_SSL_CTX_MUTEXING +//#define CONFIG_USE_DEV_URANDOM 1 +#undef CONFIG_WIN32_USE_CRYPTO_LIB +#undef CONFIG_OPENSSL_COMPATIBLE +#undef CONFIG_PERFORMANCE_TESTING +#define CONFIG_SSL_TEST 1 +#undef CONFIG_AXTLSWRAP +#define CONFIG_AXHTTPD 1 + +/* + * Axhttpd Configuration + */ +#undef CONFIG_HTTP_STATIC_BUILD +#define CONFIG_HTTP_PORT 80 +#define CONFIG_HTTP_HTTPS_PORT 443 +#define CONFIG_HTTP_SESSION_CACHE_SIZE 5 +#define CONFIG_HTTP_WEBROOT "../www" +#define CONFIG_HTTP_TIMEOUT 300 + +/* + * CGI + */ +#undef CONFIG_HTTP_HAS_CGI +#define CONFIG_HTTP_CGI_EXTENSIONS ".lua,.lp,.php" +#define CONFIG_HTTP_ENABLE_LUA 1 +#define CONFIG_HTTP_LUA_PREFIX "/usr" +#undef CONFIG_HTTP_BUILD_LUA +#define CONFIG_HTTP_CGI_LAUNCHER "/usr/bin/cgi" +#define CONFIG_HTTP_DIRECTORIES 1 +#define CONFIG_HTTP_HAS_AUTHORIZATION 1 +#undef CONFIG_HTTP_HAS_IPV6 +#undef CONFIG_HTTP_ENABLE_DIFFERENT_USER +#define CONFIG_HTTP_USER "" +#define CONFIG_HTTP_VERBOSE 0 +#undef CONFIG_HTTP_IS_DAEMON + +/* + * Language Bindings + */ +#undef CONFIG_BINDINGS +#undef CONFIG_CSHARP_BINDINGS +#undef CONFIG_VBNET_BINDINGS +#define CONFIG_DOT_NET_FRAMEWORK_BASE "" +#undef CONFIG_JAVA_BINDINGS +#define CONFIG_JAVA_HOME "" +#undef CONFIG_PERL_BINDINGS +#define CONFIG_PERL_CORE "" +#define CONFIG_PERL_LIB "" +#undef CONFIG_LUA_BINDINGS +#define CONFIG_LUA_CORE "" + +/* + * Samples + */ +#define CONFIG_SAMPLES 1 +#define CONFIG_C_SAMPLES 1 +#undef CONFIG_CSHARP_SAMPLES +#undef CONFIG_VBNET_SAMPLES +#undef CONFIG_JAVA_SAMPLES +#undef CONFIG_PERL_SAMPLES +#undef CONFIG_LUA_SAMPLES + +/* + * BigInt Options + */ +#undef CONFIG_BIGINT_CLASSICAL +#undef CONFIG_BIGINT_MONTGOMERY +#define CONFIG_BIGINT_BARRETT 1 +#define CONFIG_BIGINT_CRT 1 +#undef CONFIG_BIGINT_KARATSUBA +#define MUL_KARATSUBA_THRESH +#define SQU_KARATSUBA_THRESH +#define CONFIG_BIGINT_SLIDING_WINDOW 1 +#define CONFIG_BIGINT_SQUARE 1 +#define CONFIG_BIGINT_CHECK_ON 1 +#define CONFIG_INTEGER_32BIT 1 +#undef CONFIG_INTEGER_16BIT +#undef CONFIG_INTEGER_8BIT diff --git a/ssl/crypto_misc.h b/ssl/crypto_misc.h new file mode 100644 index 000000000..1fd514eeb --- /dev/null +++ b/ssl/crypto_misc.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file crypto_misc.h + */ + +#ifndef HEADER_CRYPTO_MISC_H +#define HEADER_CRYPTO_MISC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "crypto.h" +#include "bigint.h" + +/************************************************************************** + * X509 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_UNIT 2 + +struct _x509_ctx +{ + char *ca_cert_dn[X509_NUM_DN_TYPES]; + char *cert_dn[X509_NUM_DN_TYPES]; + char **subject_alt_dnsnames; + time_t not_before; + time_t not_after; + 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 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); +#endif +#ifdef CONFIG_SSL_FULL_MODE +void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx); +const char * x509_display_error(int error); +#endif + +/************************************************************************** + * ASN1 declarations + **************************************************************************/ +#define ASN1_INTEGER 0x02 +#define ASN1_BIT_STRING 0x03 +#define ASN1_OCTET_STRING 0x04 +#define ASN1_NULL 0x05 +#define ASN1_PRINTABLE_STR2 0x0C +#define ASN1_OID 0x06 +#define ASN1_PRINTABLE_STR2 0x0C +#define ASN1_PRINTABLE_STR 0x13 +#define ASN1_TELETEX_STR 0x14 +#define ASN1_IA5_STR 0x16 +#define ASN1_UTC_TIME 0x17 +#define ASN1_UNICODE_STR 0x1e +#define ASN1_SEQUENCE 0x30 +#define ASN1_CONTEXT_DNSNAME 0x82 +#define ASN1_SET 0x31 +#define ASN1_V3_DATA 0xa3 +#define ASN1_IMPLICIT_TAG 0x80 +#define ASN1_CONTEXT_DNSNAME 0x82 +#define ASN1_EXPLICIT_TAG 0xa0 +#define ASN1_V3_DATA 0xa3 + +#define SIG_TYPE_MD2 0x02 +#define SIG_TYPE_MD5 0x04 +#define SIG_TYPE_SHA1 0x05 + +int get_asn1_length(const uint8_t *buf, int *offset); +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 asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +int asn1_name(const uint8_t *cert, int *offset, char *dn[]); +int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +#ifdef CONFIG_SSL_CERT_VERIFICATION +int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +int asn1_find_subjectaltname(const uint8_t* cert, int offset); +int asn1_compare_dn(char * const dn1[], char * const dn2[]); +#endif /* CONFIG_SSL_CERT_VERIFICATION */ +int asn1_signature_type(const uint8_t *cert, + int *offset, X509_CTX *x509_ctx); + +/************************************************************************** + * MISC declarations + **************************************************************************/ +#define SALT_SIZE 8 + +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); + +int get_file(const char *filename, uint8_t **buf); + +#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG) +EXP_FUNC void STDCALL print_blob(const char *format, const uint8_t *data, int size, ...); +#else + #define print_blob(...) +#endif + +EXP_FUNC int STDCALL base64_decode(const char *in, int len, + uint8_t *out, int *outlen); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ssl/gen_cert.c b/ssl/gen_cert.c new file mode 100644 index 000000000..c2fe381eb --- /dev/null +++ b/ssl/gen_cert.c @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#ifdef CONFIG_SSL_GENERATE_X509_CERT +#include +#include +#include "os_port.h" +#include "ssl.h" + +/** + * Generate a basic X.509 certificate + */ + +static uint8_t set_gen_length(int len, uint8_t *buf, int *offset) +{ + if (len < 0x80) /* short form */ + { + buf[(*offset)++] = len; + return 1; + } + else /* long form */ + { + int i, length_bytes = 0; + + if (len & 0x00FF0000) + length_bytes = 3; + else if (len & 0x0000FF00) + length_bytes = 2; + else if (len & 0x000000FF) + length_bytes = 1; + + buf[(*offset)++] = 0x80 + length_bytes; + + for (i = length_bytes-1; i >= 0; i--) + { + buf[*offset+i] = len & 0xFF; + len >>= 8; + } + + *offset += length_bytes; + return length_bytes+1; + } +} + +static int pre_adjust_with_size(uint8_t type, + int *seq_offset, uint8_t *buf, int *offset) +{ + buf[(*offset)++] = type; + *seq_offset = *offset; + *offset += 4; /* fill in later */ + return *offset; +} + +static void adjust_with_size(int seq_size, int seq_start, + uint8_t *buf, int *offset) +{ + uint8_t seq_byte_size; + int orig_seq_size = seq_size; + int orig_seq_start = seq_start; + + seq_size = *offset-seq_size; + seq_byte_size = set_gen_length(seq_size, buf, &seq_start); + + if (seq_byte_size != 4) + { + memmove(&buf[orig_seq_start+seq_byte_size], + &buf[orig_seq_size], seq_size); + *offset -= 4-seq_byte_size; + } +} + +static void gen_serial_number(uint8_t *buf, int *offset) +{ + static const uint8_t ser_oid[] = { ASN1_INTEGER, 1, 0x7F }; + memcpy(&buf[*offset], ser_oid , sizeof(ser_oid)); + *offset += sizeof(ser_oid); +} + +static void gen_signature_alg(uint8_t *buf, int *offset) +{ + /* OBJECT IDENTIFIER sha1withRSAEncryption (1 2 840 113549 1 1 5) */ + static const uint8_t sig_oid[] = + { + ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, + ASN1_NULL, 0x00 + }; + + memcpy(&buf[*offset], sig_oid, sizeof(sig_oid)); + *offset += sizeof(sig_oid); +} + +static int gen_dn(const char *name, uint8_t dn_type, + uint8_t *buf, int *offset) +{ + int ret = X509_OK; + int name_size = strlen(name); + + if (name_size > 0x70) /* just too big */ + { + ret = X509_NOT_OK; + goto error; + } + + buf[(*offset)++] = ASN1_SET; + set_gen_length(9+name_size, buf, offset); + buf[(*offset)++] = ASN1_SEQUENCE; + set_gen_length(7+name_size, buf, offset); + buf[(*offset)++] = ASN1_OID; + buf[(*offset)++] = 3; + buf[(*offset)++] = 0x55; + buf[(*offset)++] = 0x04; + buf[(*offset)++] = dn_type; + buf[(*offset)++] = ASN1_PRINTABLE_STR; + buf[(*offset)++] = name_size; + strcpy(&buf[*offset], name); + *offset += name_size; + +error: + return ret; +} + +static int gen_issuer(const char * dn[], uint8_t *buf, int *offset) +{ + int ret = X509_OK; + int seq_offset; + int seq_size = pre_adjust_with_size( + ASN1_SEQUENCE, &seq_offset, buf, offset); + char fqdn[128]; + + /* we need the common name, so if not configured, work out the fully + * qualified domain name */ + if (dn[X509_COMMON_NAME] == NULL || strlen(dn[X509_COMMON_NAME]) == 0) + { + int fqdn_len; + gethostname(fqdn, sizeof(fqdn)); + fqdn_len = strlen(fqdn); + fqdn[fqdn_len++] = '.'; + getdomainname(&fqdn[fqdn_len], sizeof(fqdn)-fqdn_len); + fqdn_len = strlen(fqdn); + + if (fqdn[fqdn_len-1] == '.') /* ensure '.' is not last char */ + fqdn[fqdn_len-1] = 0; + + dn[X509_COMMON_NAME] = fqdn; + } + + if ((ret = gen_dn(dn[X509_COMMON_NAME], 3, buf, offset))) + goto error; + + if (dn[X509_ORGANIZATION] != NULL && strlen(dn[X509_ORGANIZATION]) > 0) + { + if ((ret = gen_dn(dn[X509_ORGANIZATION], 10, buf, offset))) + goto error; + } + + if (dn[X509_ORGANIZATIONAL_UNIT] != NULL && + strlen(dn[X509_ORGANIZATIONAL_UNIT]) > 0) + { + if ((ret = gen_dn(dn[X509_ORGANIZATIONAL_UNIT], 11, buf, offset))) + goto error; + } + + adjust_with_size(seq_size, seq_offset, buf, offset); + +error: + return ret; +} + +static void gen_utc_time(uint8_t *buf, int *offset) +{ + static const uint8_t time_seq[] = + { + ASN1_SEQUENCE, 30, + ASN1_UTC_TIME, 13, + '0', '7', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z', + ASN1_UTC_TIME, 13, /* make it good for 30 or so years */ + '3', '8', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z' + }; + + /* fixed time */ + memcpy(&buf[*offset], time_seq, sizeof(time_seq)); + *offset += sizeof(time_seq); +} + +static void gen_pub_key2(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset) +{ + static const uint8_t pub_key_seq[] = + { + ASN1_INTEGER, 0x03, 0x01, 0x00, 0x01 /* INTEGER 65537 */ + }; + + int seq_offset; + int pub_key_size = rsa_ctx->num_octets; + uint8_t *block = (uint8_t *)alloca(pub_key_size); + int seq_size = pre_adjust_with_size( + ASN1_SEQUENCE, &seq_offset, buf, offset); + buf[(*offset)++] = ASN1_INTEGER; + bi_export(rsa_ctx->bi_ctx, rsa_ctx->m, block, pub_key_size); + + if (*block & 0x80) /* make integer positive */ + { + set_gen_length(pub_key_size+1, buf, offset); + buf[(*offset)++] = 0; + } + else + set_gen_length(pub_key_size, buf, offset); + + memcpy(&buf[*offset], block, pub_key_size); + *offset += pub_key_size; + memcpy(&buf[*offset], pub_key_seq, sizeof(pub_key_seq)); + *offset += sizeof(pub_key_seq); + adjust_with_size(seq_size, seq_offset, buf, offset); +} + +static void gen_pub_key1(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset) +{ + int seq_offset; + int seq_size = pre_adjust_with_size( + ASN1_BIT_STRING, &seq_offset, buf, offset); + buf[(*offset)++] = 0; /* bit string is multiple of 8 */ + gen_pub_key2(rsa_ctx, buf, offset); + adjust_with_size(seq_size, seq_offset, buf, offset); +} + +static void gen_pub_key(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset) +{ + /* OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) */ + static const uint8_t rsa_enc_oid[] = + { + ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + ASN1_NULL, 0x00 + }; + + int seq_offset; + int seq_size = pre_adjust_with_size( + ASN1_SEQUENCE, &seq_offset, buf, offset); + + memcpy(&buf[*offset], rsa_enc_oid, sizeof(rsa_enc_oid)); + *offset += sizeof(rsa_enc_oid); + gen_pub_key1(rsa_ctx, buf, offset); + adjust_with_size(seq_size, seq_offset, buf, offset); +} + +static void gen_signature(const RSA_CTX *rsa_ctx, const uint8_t *sha_dgst, + uint8_t *buf, int *offset) +{ + static const uint8_t asn1_sig[] = + { + ASN1_SEQUENCE, 0x21, ASN1_SEQUENCE, 0x09, ASN1_OID, 0x05, + 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* sha1 (1 3 14 3 2 26) */ + ASN1_NULL, 0x00, ASN1_OCTET_STRING, 0x14 + }; + + uint8_t *enc_block = (uint8_t *)alloca(rsa_ctx->num_octets); + uint8_t *block = (uint8_t *)alloca(sizeof(asn1_sig) + SHA1_SIZE); + int sig_size; + + /* add the digest as an embedded asn.1 sequence */ + memcpy(block, asn1_sig, sizeof(asn1_sig)); + memcpy(&block[sizeof(asn1_sig)], sha_dgst, SHA1_SIZE); + + sig_size = RSA_encrypt(rsa_ctx, block, + sizeof(asn1_sig) + SHA1_SIZE, enc_block, 1); + + buf[(*offset)++] = ASN1_BIT_STRING; + set_gen_length(sig_size+1, buf, offset); + buf[(*offset)++] = 0; /* bit string is multiple of 8 */ + memcpy(&buf[*offset], enc_block, sig_size); + *offset += sig_size; +} + +static int gen_tbs_cert(const char * dn[], + const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset, + uint8_t *sha_dgst) +{ + int ret = X509_OK; + SHA1_CTX sha_ctx; + int seq_offset; + int begin_tbs = *offset; + int seq_size = pre_adjust_with_size( + ASN1_SEQUENCE, &seq_offset, buf, offset); + + gen_serial_number(buf, offset); + gen_signature_alg(buf, offset); + + /* CA certicate issuer */ + if ((ret = gen_issuer(dn, buf, offset))) + goto error; + + gen_utc_time(buf, offset); + + /* certificate issuer */ + if ((ret = gen_issuer(dn, buf, offset))) + goto error; + + gen_pub_key(rsa_ctx, buf, offset); + adjust_with_size(seq_size, seq_offset, buf, offset); + + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx, &buf[begin_tbs], *offset-begin_tbs); + SHA1_Final(sha_dgst, &sha_ctx); + +error: + return ret; +} + +/** + * Create a new certificate. + */ +EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data) +{ + int ret = X509_OK, offset = 0, seq_offset; + /* allocate enough space to load a new certificate */ + uint8_t *buf = (uint8_t *)alloca(ssl_ctx->rsa_ctx->num_octets*2 + 512); + uint8_t sha_dgst[SHA1_SIZE]; + int seq_size = pre_adjust_with_size(ASN1_SEQUENCE, + &seq_offset, buf, &offset); + + if ((ret = gen_tbs_cert(dn, ssl_ctx->rsa_ctx, buf, &offset, sha_dgst)) < 0) + goto error; + + gen_signature_alg(buf, &offset); + gen_signature(ssl_ctx->rsa_ctx, sha_dgst, buf, &offset); + adjust_with_size(seq_size, seq_offset, buf, &offset); + *cert_data = (uint8_t *)malloc(offset); /* create the exact memory for it */ + memcpy(*cert_data, buf, offset); + +error: + return ret < 0 ? ret : offset; +} + +#endif + diff --git a/ssl/gen_cert.o b/ssl/gen_cert.o new file mode 100644 index 0000000000000000000000000000000000000000..d31834c7a965f77cc907f6522e6a8bbeb4d37f31 GIT binary patch literal 828 zcma)4O-sW-5S^I%RXyn0OY~v|UDDEn2tBkVmO@alt?0#&##jq&0?i8btb&oFqDq zCnpyjtEy_YvX88~I#o5=hT8(U(~SG(cSORylyx7l%;8!D% yexfB7>m~a9k~&B8*92J?Z^F8GB5S@)4wF`Mfz14Q1&gxDlNyDQ7lbpd0{R9ra6;1n literal 0 HcmV?d00001 diff --git a/ssl/loader.c b/ssl/loader.c new file mode 100644 index 000000000..333fb18e9 --- /dev/null +++ b/ssl/loader.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Load certificates/keys into memory. These can be in many different formats. + * PEM support and other formats can be processed here. + * + * The PEM private keys may be optionally encrypted with AES128 or AES256. + * The encrypted PEM keys were generated with something like: + * + * openssl genrsa -aes128 -passout pass:abcd -out axTLS.key_aes128.pem 512 + */ + +#include +#include +#include +#include "os_port.h" +#include "ssl.h" + +static int do_obj(SSL_CTX *ssl_ctx, int obj_type, + SSLObjLoader *ssl_obj, const char *password); +#ifdef CONFIG_SSL_HAS_PEM +static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, + SSLObjLoader *ssl_obj, const char *password); +#endif + +/* + * Load a file into memory that is in binary DER (or ascii PEM) format. + */ +EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, + const char *filename, const char *password) +{ +#ifndef CONFIG_SSL_SKELETON_MODE + static const char * const begin = "-----BEGIN"; + int ret = SSL_OK; + SSLObjLoader *ssl_obj = NULL; + + if (filename == NULL) + { + ret = SSL_ERROR_INVALID_KEY; + goto error; + } + + ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader)); + ssl_obj->len = get_file(filename, &ssl_obj->buf); + if (ssl_obj->len <= 0) + { + ret = SSL_ERROR_INVALID_KEY; + goto error; + } + + /* is the file a PEM file? */ + if (strstr((char *)ssl_obj->buf, begin) != NULL) + { +#ifdef CONFIG_SSL_HAS_PEM + ret = ssl_obj_PEM_load(ssl_ctx, obj_type, ssl_obj, password); +#else + printf(unsupported_str); + ret = SSL_ERROR_NOT_SUPPORTED; +#endif + } + else + ret = do_obj(ssl_ctx, obj_type, ssl_obj, password); + +error: + ssl_obj_free(ssl_obj); + return ret; +#else + printf(unsupported_str); + return SSL_ERROR_NOT_SUPPORTED; +#endif /* CONFIG_SSL_SKELETON_MODE */ +} + +/* + * Transfer binary data into the object loader. + */ +EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int mem_type, + const uint8_t *data, int len, const char *password) +{ + int ret; + SSLObjLoader *ssl_obj; + + ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader)); + ssl_obj->buf = (uint8_t *)malloc(len); + memcpy(ssl_obj->buf, data, len); + ssl_obj->len = len; + ret = do_obj(ssl_ctx, mem_type, ssl_obj, password); + ssl_obj_free(ssl_obj); + return ret; +} + +/* + * Actually work out what we are doing + */ +static int do_obj(SSL_CTX *ssl_ctx, int obj_type, + SSLObjLoader *ssl_obj, const char *password) +{ + int ret = SSL_OK; + + switch (obj_type) + { + case SSL_OBJ_RSA_KEY: + ret = add_private_key(ssl_ctx, ssl_obj); + break; + + case SSL_OBJ_X509_CERT: + ret = add_cert(ssl_ctx, ssl_obj->buf, ssl_obj->len); + break; + +#ifdef CONFIG_SSL_CERT_VERIFICATION + case SSL_OBJ_X509_CACERT: + add_cert_auth(ssl_ctx, ssl_obj->buf, ssl_obj->len); + break; +#endif + +#ifdef CONFIG_SSL_USE_PKCS12 + case SSL_OBJ_PKCS8: + ret = pkcs8_decode(ssl_ctx, ssl_obj, password); + break; + + case SSL_OBJ_PKCS12: + ret = pkcs12_decode(ssl_ctx, ssl_obj, password); + break; +#endif + default: + printf(unsupported_str); + ret = SSL_ERROR_NOT_SUPPORTED; + break; + } + + return ret; +} + +/* + * Clean up our mess. + */ +void ssl_obj_free(SSLObjLoader *ssl_obj) +{ + if (ssl_obj) + { + free(ssl_obj->buf); + free(ssl_obj); + } +} + +/* + * Support for PEM encoded keys/certificates. + */ +#ifdef CONFIG_SSL_HAS_PEM + +#define NUM_PEM_TYPES 4 +#define IV_SIZE 16 +#define IS_RSA_PRIVATE_KEY 0 +#define IS_ENCRYPTED_PRIVATE_KEY 1 +#define IS_PRIVATE_KEY 2 +#define IS_CERTIFICATE 3 + +static const char * const begins[NUM_PEM_TYPES] = +{ + "-----BEGIN RSA PRIVATE KEY-----", + "-----BEGIN ENCRYPTED PRIVATE KEY-----", + "-----BEGIN PRIVATE KEY-----", + "-----BEGIN CERTIFICATE-----", +}; + +static const char * const ends[NUM_PEM_TYPES] = +{ + "-----END RSA PRIVATE KEY-----", + "-----END ENCRYPTED PRIVATE KEY-----", + "-----END PRIVATE KEY-----", + "-----END CERTIFICATE-----", +}; + +static const char * const aes_str[2] = +{ + "DEK-Info: AES-128-CBC,", + "DEK-Info: AES-256-CBC," +}; + +/** + * Take a base64 blob of data and decrypt it (using AES) into its + * proper ASN.1 form. + */ +static int pem_decrypt(const char *where, const char *end, + const char *password, SSLObjLoader *ssl_obj) +{ + int ret = -1; + int is_aes_256 = 0; + char *start = NULL; + uint8_t iv[IV_SIZE]; + int i, pem_size; + MD5_CTX md5_ctx; + AES_CTX aes_ctx; + uint8_t key[32]; /* AES256 size */ + + if (password == NULL || strlen(password) == 0) + { +#ifdef CONFIG_SSL_FULL_MODE + printf("Error: Need a password for this PEM file\n"); TTY_FLUSH(); +#endif + goto error; + } + + if ((start = strstr((const char *)where, aes_str[0]))) /* AES128? */ + { + start += strlen(aes_str[0]); + } + else if ((start = strstr((const char *)where, aes_str[1]))) /* AES256? */ + { + is_aes_256 = 1; + start += strlen(aes_str[1]); + } + else + { +#ifdef CONFIG_SSL_FULL_MODE + printf("Error: Unsupported password cipher\n"); TTY_FLUSH(); +#endif + goto error; + } + + /* convert from hex to binary - assumes uppercase hex */ + for (i = 0; i < IV_SIZE; i++) + { + char c = *start++ - '0'; + iv[i] = (c > 9 ? c + '0' - 'A' + 10 : c) << 4; + c = *start++ - '0'; + iv[i] += (c > 9 ? c + '0' - 'A' + 10 : c); + } + + while (*start == '\r' || *start == '\n') + start++; + + /* turn base64 into binary */ + pem_size = (int)(end-start); + if (base64_decode(start, pem_size, ssl_obj->buf, &ssl_obj->len) != 0) + goto error; + + /* work out the key */ + MD5_Init(&md5_ctx); + MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password)); + MD5_Update(&md5_ctx, iv, SALT_SIZE); + MD5_Final(key, &md5_ctx); + + if (is_aes_256) + { + MD5_Init(&md5_ctx); + MD5_Update(&md5_ctx, key, MD5_SIZE); + MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password)); + MD5_Update(&md5_ctx, iv, SALT_SIZE); + MD5_Final(&key[MD5_SIZE], &md5_ctx); + } + + /* decrypt using the key/iv */ + AES_set_key(&aes_ctx, key, iv, is_aes_256 ? AES_MODE_256 : AES_MODE_128); + AES_convert_key(&aes_ctx); + AES_cbc_decrypt(&aes_ctx, ssl_obj->buf, ssl_obj->buf, ssl_obj->len); + ret = 0; + +error: + return ret; +} + +/** + * Take a base64 blob of data and turn it into its proper ASN.1 form. + */ +static int new_pem_obj(SSL_CTX *ssl_ctx, int is_cacert, char *where, + int remain, const char *password) +{ + int ret = SSL_ERROR_BAD_CERTIFICATE; + SSLObjLoader *ssl_obj = NULL; + + while (remain > 0) + { + int i, pem_size, obj_type; + char *start = NULL, *end = NULL; + + for (i = 0; i < NUM_PEM_TYPES; i++) + { + if ((start = strstr(where, begins[i])) && + (end = strstr(where, ends[i]))) + { + remain -= (int)(end-where); + start += strlen(begins[i]); + pem_size = (int)(end-start); + + ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader)); + + /* 4/3 bigger than what we need but so what */ + ssl_obj->buf = (uint8_t *)calloc(1, pem_size); + ssl_obj->len = pem_size; + + if (i == IS_RSA_PRIVATE_KEY && + strstr(start, "Proc-Type:") && + strstr(start, "4,ENCRYPTED")) + { + /* check for encrypted PEM file */ + if (pem_decrypt(start, end, password, ssl_obj) < 0) + { + ret = SSL_ERROR_BAD_CERTIFICATE; + goto error; + } + } + else + { + ssl_obj->len = pem_size; + if (base64_decode(start, pem_size, + ssl_obj->buf, &ssl_obj->len) != 0) + { + ret = SSL_ERROR_BAD_CERTIFICATE; + goto error; + } + } + + switch (i) + { + case IS_RSA_PRIVATE_KEY: + obj_type = SSL_OBJ_RSA_KEY; + break; + + case IS_ENCRYPTED_PRIVATE_KEY: + case IS_PRIVATE_KEY: + obj_type = SSL_OBJ_PKCS8; + break; + + case IS_CERTIFICATE: + obj_type = is_cacert ? + SSL_OBJ_X509_CACERT : SSL_OBJ_X509_CERT; + break; + + default: + ret = SSL_ERROR_BAD_CERTIFICATE; + goto error; + } + + /* In a format we can now understand - so process it */ + if ((ret = do_obj(ssl_ctx, obj_type, ssl_obj, password))) + goto error; + + end += strlen(ends[i]); + remain -= strlen(ends[i]); + while (remain > 0 && (*end == '\r' || *end == '\n')) + { + end++; + remain--; + } + + where = end; + break; + } + } + + ssl_obj_free(ssl_obj); + ssl_obj = NULL; + if (start == NULL) + break; + } +error: + ssl_obj_free(ssl_obj); + return ret; +} + +/* + * Load a file into memory that is in ASCII PEM format. + */ +static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, + SSLObjLoader *ssl_obj, const char *password) +{ + char *start; + + /* add a null terminator */ + ssl_obj->len++; + ssl_obj->buf = (uint8_t *)realloc(ssl_obj->buf, ssl_obj->len); + ssl_obj->buf[ssl_obj->len-1] = 0; + start = (char *)ssl_obj->buf; + return new_pem_obj(ssl_ctx, obj_type == SSL_OBJ_X509_CACERT, + start, ssl_obj->len, password); +} +#endif /* CONFIG_SSL_HAS_PEM */ + +/** + * Load the key/certificates in memory depending on compile-time and user + * options. + */ +int load_key_certs(SSL_CTX *ssl_ctx) +{ + int ret = SSL_OK; + uint32_t options = ssl_ctx->options; +#ifdef CONFIG_SSL_GENERATE_X509_CERT + uint8_t *cert_data = NULL; + int cert_size; + static const char *dn[] = + { + CONFIG_SSL_X509_COMMON_NAME, + CONFIG_SSL_X509_ORGANIZATION_NAME, + CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME + }; +#endif + + /* do the private key first */ + if (strlen(CONFIG_SSL_PRIVATE_KEY_LOCATION) > 0) + { + if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, + CONFIG_SSL_PRIVATE_KEY_LOCATION, + CONFIG_SSL_PRIVATE_KEY_PASSWORD)) < 0) + goto error; + } + else if (!(options & SSL_NO_DEFAULT_KEY)) + { +#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE) + static const /* saves a few more bytes */ +#include "private_key.h" + + ssl_obj_memory_load(ssl_ctx, SSL_OBJ_RSA_KEY, default_private_key, + default_private_key_len, NULL); +#endif + } + + /* now load the certificate */ +#ifdef CONFIG_SSL_GENERATE_X509_CERT + if ((cert_size = ssl_x509_create(ssl_ctx, 0, dn, &cert_data)) < 0) + { + ret = cert_size; + goto error; + } + + ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, cert_data, cert_size, NULL); + free(cert_data); +#else + if (strlen(CONFIG_SSL_X509_CERT_LOCATION)) + { + if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, + CONFIG_SSL_X509_CERT_LOCATION, NULL)) < 0) + goto error; + } + else if (!(options & SSL_NO_DEFAULT_KEY)) + { +#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE) + static const /* saves a few bytes and RAM */ +#include "cert.h" + ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, + default_certificate, default_certificate_len, NULL); +#endif + } +#endif + +error: +#ifdef CONFIG_SSL_FULL_MODE + if (ret) + { + printf("Error: Certificate or key not loaded\n"); TTY_FLUSH(); + } +#endif + + return ret; + +} diff --git a/ssl/loader.o b/ssl/loader.o new file mode 100644 index 0000000000000000000000000000000000000000..17758504edd98f44158f57f73a8403e39913fddd GIT binary patch literal 38320 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%0D-mkXXHxLz>-!;DFH znc$UzZx(!~;Clo=Ab7LjCj|4ko=J=U(8lnqg8Bb#jQoh;j|86-{H5Sig83ZK*f}FO z0?)sUoX-ah#|VxU+*NQ7!O4RA3C6Jx2)o|!F;A^?8FN0D!7MWKHoI@=J_U;W2`|!o-25yVE&sr6PM3D4F?4C|J50JjbQ#S z93x*Qc%|T*1>Y`stziBW9b@M)!A}W(RxtmejnRKq@BzVx1b-m-pMv?nZ;YMq1pgwK zFTEL^7{RfE`Cn^{PG7;eX0x`8rQ)zY!%SS=7yKWrhnV{O7R+yB zxc#IV%irqT7Rvb^BG*aC{3M~hX4X?@&0Ht$uDL(Br)GW+(pPgnnCm38QwY9T^X1?{ znz?2?OmhHSpt%Y>PV+o)iRSs>t2EyTp00T%c!uU%!8Mw11JBcZ2Y9LG4d7LpH-Yce zycxVf^V48{zr+0VeMY|fP2K_Csd+b;-}O+w56pEB@^SDX%_qQo|BdpKV6KOd`CSR$ zg(Js;xgJ7}2lKr+at`=M&HV3^d`FIQuF-lt4o?U3eL2c&z%iQnJ|o|qqx=qVH_iMf zk$jJia()}awGlG^0VLn4BOeCy-EuP5LAg#s=DUqtCn0|UF4WAm&+(f1O~ypc{1)SC z&0OycXy*4CGd1)7FV<=v3g)ll(*79i^ELCkt;L%8e!>l!OTqk}iuwWUTvs8NW4}vt z4fuY|A@C;6T>E@f^BV9In)yuz-(RO4u6^#%%paNGrFlD;@7Ys_-(T<_2$TPc{T{IrRI;o-)TMp{zdbbU^nj5X`jC?j9+F{debX0qnq;8e|Azs%M=3OrCV$6T)F$zZ-qPx~ByTyG&y1s7=!fG2C_ zw;IzlSA+R{l=`#4*J!Qf+u{J7>!@Y9;PzW8U&Twi=iGvD*wt9dl|4b2n42Q{-_b8UxpG7HT2UCFgzuI-Td zZRIDL8^K>`4uQYd%;)>RXy&tc3u_3B%lCr0**rn(%`mTX%sHLcIfi=*=Jkw`^SZ?_ zuUicB`o!>b!8L-L1Ya+BwcvGv9~Qh#@J_*R2tF+MBf(z@{zb44=N^-1o;wZm+-bO< zV4g>fJWuch!BYfR2@VNfB6yWxKF2in`Rvm06M}iJHS+y}4+%adnCDuf|D#}@YmJ=G z77ce3oGh5n6OB%;V4h!%oaa=-6@nWC^SPnXQQsiI&+T?0UoUuzV4g2c+&zL12tFeC zq+njJnz$C`T*JIZHO%W$!@L$X%rBHu&l#RBnAecz-IXT6*9%@P`2PX* CP`p_H literal 0 HcmV?d00001 diff --git a/ssl/openssl.c b/ssl/openssl.c new file mode 100644 index 000000000..6b5c4d8ee --- /dev/null +++ b/ssl/openssl.c @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Enable a subset of openssl compatible functions. We don't aim to be 100% + * compatible - just to be able to do basic ports etc. + * + * Only really tested on mini_httpd, so I'm not too sure how extensive this + * port is. + */ + +#include "config.h" + +#ifdef CONFIG_OPENSSL_COMPATIBLE +#include +#include +#include +#include "os_port.h" +#include "ssl.h" + +#define OPENSSL_CTX_ATTR ((OPENSSL_CTX *)ssl_ctx->bonus_attr) + +static char *key_password = NULL; + +void *SSLv23_server_method(void) { return NULL; } +void *SSLv3_server_method(void) { return NULL; } +void *TLSv1_server_method(void) { return NULL; } +void *SSLv23_client_method(void) { return NULL; } +void *SSLv3_client_method(void) { return NULL; } +void *TLSv1_client_method(void) { return NULL; } + +typedef void * (*ssl_func_type_t)(void); +typedef void * (*bio_func_type_t)(void); + +typedef struct +{ + ssl_func_type_t ssl_func_type; +} OPENSSL_CTX; + +SSL_CTX * SSL_CTX_new(ssl_func_type_t meth) +{ + SSL_CTX *ssl_ctx = ssl_ctx_new(0, 5); + ssl_ctx->bonus_attr = malloc(sizeof(OPENSSL_CTX)); + OPENSSL_CTX_ATTR->ssl_func_type = meth; + return ssl_ctx; +} + +void SSL_CTX_free(SSL_CTX * ssl_ctx) +{ + free(ssl_ctx->bonus_attr); + ssl_ctx_free(ssl_ctx); +} + +SSL * SSL_new(SSL_CTX *ssl_ctx) +{ + SSL *ssl; + ssl_func_type_t ssl_func_type; + + ssl = ssl_new(ssl_ctx, -1); /* fd is set later */ + ssl_func_type = OPENSSL_CTX_ATTR->ssl_func_type; + +#ifdef CONFIG_SSL_ENABLE_CLIENT + if (ssl_func_type == SSLv23_client_method || + ssl_func_type == SSLv3_client_method || + ssl_func_type == TLSv1_client_method) + { + SET_SSL_FLAG(SSL_IS_CLIENT); + } + else +#endif + { + ssl->next_state = HS_CLIENT_HELLO; + } + + return ssl; +} + +int SSL_set_fd(SSL *s, int fd) +{ + s->client_fd = fd; + return 1; /* always succeeds */ +} + +int SSL_accept(SSL *ssl) +{ + while (ssl_read(ssl, NULL) == SSL_OK) + { + if (ssl->next_state == HS_CLIENT_HELLO) + return 1; /* we're done */ + } + + return -1; +} + +#ifdef CONFIG_SSL_ENABLE_CLIENT +int SSL_connect(SSL *ssl) +{ + return do_client_connect(ssl) == SSL_OK ? 1 : -1; +} +#endif + +void SSL_free(SSL *ssl) +{ + ssl_free(ssl); +} + +int SSL_read(SSL *ssl, void *buf, int num) +{ + uint8_t *read_buf; + int ret; + + while ((ret = ssl_read(ssl, &read_buf)) == SSL_OK); + + if (ret > SSL_OK) + { + memcpy(buf, read_buf, ret > num ? num : ret); + } + + return ret; +} + +int SSL_write(SSL *ssl, const void *buf, int num) +{ + return ssl_write(ssl, buf, num); +} + +int SSL_CTX_use_certificate_file(SSL_CTX *ssl_ctx, const char *file, int type) +{ + return (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, file, NULL) == SSL_OK); +} + +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type) +{ + return (ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, file, key_password) == SSL_OK); +} + +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ssl_ctx, int len, const uint8_t *d) +{ + return (ssl_obj_memory_load(ssl_ctx, + SSL_OBJ_X509_CERT, d, len, NULL) == SSL_OK); +} + +int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx, + unsigned int sid_ctx_len) +{ + return 1; +} + +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) +{ + return 1; +} + +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file) +{ + return (ssl_obj_load(ssl_ctx, + SSL_OBJ_X509_CERT, file, NULL) == SSL_OK); +} + +int SSL_shutdown(SSL *ssl) +{ + return 1; +} + +/*** get/set session ***/ +SSL_SESSION *SSL_get1_session(SSL *ssl) +{ + return (SSL_SESSION *)ssl_get_session_id(ssl); /* note: wrong cast */ +} + +int SSL_set_session(SSL *ssl, SSL_SESSION *session) +{ + memcpy(ssl->session_id, (uint8_t *)session, SSL_SESSION_ID_SIZE); + return 1; +} + +void SSL_SESSION_free(SSL_SESSION *session) { } +/*** end get/set session ***/ + +long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) +{ + return 0; +} + +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*verify_callback)(int, void *)) { } + +void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth) { } + +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath) +{ + return 1; +} + +void *SSL_load_client_CA_file(const char *file) +{ + return (void *)file; +} + +void SSL_CTX_set_client_CA_list(SSL_CTX *ssl_ctx, void *file) +{ + + ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, (const char *)file, NULL); +} + +void SSLv23_method(void) { } + +void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, void *cb) { } + +void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u) +{ + key_password = (char *)u; +} + +int SSL_peek(SSL *ssl, void *buf, int num) +{ + memcpy(buf, ssl->bm_data, num); + return num; +} + +void SSL_set_bio(SSL *ssl, void *rbio, void *wbio) { } + +long SSL_get_verify_result(const SSL *ssl) +{ + return ssl_handshake_status(ssl); +} + +int SSL_state(SSL *ssl) +{ + return 0x03; // ok state +} + +/** end of could do better list */ + +void *SSL_get_peer_certificate(const SSL *ssl) +{ + return &ssl->ssl_ctx->certs[0]; +} + +int SSL_clear(SSL *ssl) +{ + return 1; +} + + +int SSL_CTX_check_private_key(const SSL_CTX *ctx) +{ + return 1; +} + +int SSL_CTX_set_cipher_list(SSL *s, const char *str) +{ + return 1; +} + +int SSL_get_error(const SSL *ssl, int ret) +{ + ssl_display_error(ret); + return 0; /* TODO: return proper return code */ +} + +void SSL_CTX_set_options(SSL_CTX *ssl_ctx, int option) {} +int SSL_library_init(void ) { return 1; } +void SSL_load_error_strings(void ) {} +void ERR_print_errors_fp(FILE *fp) {} + +#ifndef CONFIG_SSL_SKELETON_MODE +long SSL_CTX_get_timeout(const SSL_CTX *ssl_ctx) { + return CONFIG_SSL_EXPIRY_TIME*3600; } +long SSL_CTX_set_timeout(SSL_CTX *ssl_ctx, long t) { + return SSL_CTX_get_timeout(ssl_ctx); } +#endif +void BIO_printf(FILE *f, const char *format, ...) +{ + va_list(ap); + va_start(ap, format); + vfprintf(f, format, ap); + va_end(ap); +} + +void* BIO_s_null(void) { return NULL; } +FILE *BIO_new(bio_func_type_t func) +{ + if (func == BIO_s_null) + return fopen("/dev/null", "r"); + else + return NULL; +} + +FILE *BIO_new_fp(FILE *stream, int close_flag) { return stream; } +int BIO_free(FILE *a) { if (a != stdout && a != stderr) fclose(a); return 1; } + + + +#endif diff --git a/ssl/openssl.o b/ssl/openssl.o new file mode 100644 index 0000000000000000000000000000000000000000..43ec25c066ecd050aa44d403ebc94b187c45af2d GIT binary patch literal 827 zcma)4O-sW-5S^I%)q2pgm*~X`x}>FtBJ|LfSPDVGwxSn9TB8=)M4A=q$$udJ1b?1a ze}TS9GbVxsA3SE>?AzJRWM3Tj)G!PZ7<5CKBKqJ3lc<&$%2c8aqE5SgVwFd;D2{a$ zO^(kxRz+29Wgl8KRaaHog4+VQ)0Gaw*!Q~OT||SP<275ob9c~pJh$6-E}CwyVHcaN zZlh9!S;fy&?GF+4Y!M$M)4^Pmy7jeBY8b~zgW=P?HyMY4q3KnIPClx*7ImZ( +#include +#include + +#endif //OS_INT_H \ No newline at end of file diff --git a/ssl/os_port.c b/ssl/os_port.c new file mode 100644 index 000000000..6a71000b4 --- /dev/null +++ b/ssl/os_port.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file os_port.c + * + * OS specific functions. + */ +#include +#include +#include +#include +#include "os_port.h" + +#ifdef WIN32 +/** + * gettimeofday() not in Win32 + */ +EXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone) +{ +#if defined(_WIN32_WCE) + t->tv_sec = time(NULL); + t->tv_usec = 0; /* 1sec precision only */ +#else + struct _timeb timebuffer; + _ftime(&timebuffer); + t->tv_sec = (long)timebuffer.time; + t->tv_usec = 1000 * timebuffer.millitm; /* 1ms precision */ +#endif +} + +/** + * strcasecmp() not in Win32 + */ +EXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2) +{ + while (tolower(*s1) == tolower(*s2++)) + { + if (*s1++ == '\0') + { + return 0; + } + } + + return *(unsigned char *)s1 - *(unsigned char *)(s2 - 1); +} + + +EXP_FUNC int STDCALL getdomainname(char *buf, int buf_size) +{ + HKEY hKey; + unsigned long datatype; + unsigned long bufferlength = buf_size; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, + TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), + 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) + return -1; + + RegQueryValueEx(hKey, "Domain", NULL, &datatype, buf, &bufferlength); + RegCloseKey(hKey); + return 0; +} +#endif + +#undef malloc +#undef realloc +#undef calloc + +static const char * out_of_mem_str = "out of memory"; +static const char * file_open_str = "Could not open file \"%s\""; + +/* + * Some functions that call display some error trace and then call abort(). + * This just makes life much easier on embedded systems, since we're + * suffering major trauma... + */ +EXP_FUNC void * STDCALL ax_malloc(size_t s) +{ + void *x; + + if ((x = malloc(s)) == NULL) + exit_now(out_of_mem_str); + + return x; +} + +EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s) +{ + void *x; + + if ((x = realloc(y, s)) == NULL) + exit_now(out_of_mem_str); + + return x; +} + +EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s) +{ + void *x; + + if ((x = calloc(n, s)) == NULL) + exit_now(out_of_mem_str); + + return x; +} + +EXP_FUNC int STDCALL ax_open(const char *pathname, int flags) +{ + int x; + + if ((x = open(pathname, flags)) < 0) + exit_now(file_open_str, pathname); + + return x; +} + +/** + * This is a call which will deliberately exit an application, but will + * display some information before dying. + */ +void exit_now(const char *format, ...) +{ + va_list argp; + + va_start(argp, format); + vfprintf(stderr, format, argp); + va_end(argp); + abort(); +} + diff --git a/ssl/os_port.h b/ssl/os_port.h new file mode 100644 index 000000000..d63a48ddc --- /dev/null +++ b/ssl/os_port.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file os_port.h + * + * Some stuff to minimise the differences between windows and linux/unix + */ + +#ifndef HEADER_OS_PORT_H +#define HEADER_OS_PORT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "os_int.h" +#include + + + + +#ifdef WIN32 +#define STDCALL __stdcall +#define EXP_FUNC __declspec(dllexport) +#else +#define STDCALL +#define EXP_FUNC +#endif + +#if defined(_WIN32_WCE) +#undef WIN32 +#define WIN32 +#endif + +#if defined(ESP8266) + + + + +#elif defined(WIN32) + +/* Windows CE stuff */ +#if defined(_WIN32_WCE) +#include +#define abort() exit(1) +#else +#include +#include +#include +#include +#endif /* _WIN32_WCE */ + +#include +#include +#undef getpid +#undef open +#undef close +#undef sleep +#undef gettimeofday +#undef dup2 +#undef unlink + +#define SOCKET_READ(A,B,C) recv(A,B,C,0) +#define SOCKET_WRITE(A,B,C) send(A,B,C,0) +#define SOCKET_CLOSE(A) closesocket(A) +#define srandom(A) srand(A) +#define random() rand() +#define getpid() _getpid() +#define snprintf _snprintf +#define open(A,B) _open(A,B) +#define dup2(A,B) _dup2(A,B) +#define unlink(A) _unlink(A) +#define close(A) _close(A) +#define read(A,B,C) _read(A,B,C) +#define write(A,B,C) _write(A,B,C) +#define sleep(A) Sleep(A*1000) +#define usleep(A) Sleep(A/1000) +#define strdup(A) _strdup(A) +#define chroot(A) _chdir(A) +#define chdir(A) _chdir(A) +#define alloca(A) _alloca(A) +#ifndef lseek +#define lseek(A,B,C) _lseek(A,B,C) +#endif + +/* This fix gets around a problem where a win32 application on a cygwin xterm + doesn't display regular output (until a certain buffer limit) - but it works + fine under a normal DOS window. This is a hack to get around the issue - + see http://www.khngai.com/emacs/tty.php */ +#define TTY_FLUSH() if (!_isatty(_fileno(stdout))) fflush(stdout); + +/* + * automatically build some library dependencies. + */ +#pragma comment(lib, "WS2_32.lib") +#pragma comment(lib, "AdvAPI32.lib") + +typedef int socklen_t; + +EXP_FUNC void STDCALL gettimeofday(struct timeval* t,void* timezone); +EXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2); +EXP_FUNC int STDCALL getdomainname(char *buf, int buf_size); + +#else /* Not Win32 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SOCKET_READ(A,B,C) read(A,B,C) +#define SOCKET_WRITE(A,B,C) write(A,B,C) +#define SOCKET_CLOSE(A) if (A >= 0) close(A) +#define TTY_FLUSH() + +#endif /* Not Win32 */ + +/* some functions to mutate the way these work */ +#define malloc(A) ax_malloc(A) +#ifndef realloc +#define realloc(A,B) ax_realloc(A,B) +#endif +#define calloc(A,B) ax_calloc(A,B) + +EXP_FUNC void * STDCALL ax_malloc(size_t s); +EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s); +EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s); +EXP_FUNC int STDCALL ax_open(const char *pathname, int flags); + +#ifdef CONFIG_PLATFORM_LINUX +void exit_now(const char *format, ...) __attribute((noreturn)); +#else +void exit_now(const char *format, ...); +#endif + +/* Mutexing definitions */ +#if defined(CONFIG_SSL_CTX_MUTEXING) +#if defined(WIN32) +#define SSL_CTX_MUTEX_TYPE HANDLE +#define SSL_CTX_MUTEX_INIT(A) A=CreateMutex(0, FALSE, 0) +#define SSL_CTX_MUTEX_DESTROY(A) CloseHandle(A) +#define SSL_CTX_LOCK(A) WaitForSingleObject(A, INFINITE) +#define SSL_CTX_UNLOCK(A) ReleaseMutex(A) +#else +#include +#define SSL_CTX_MUTEX_TYPE pthread_mutex_t +#define SSL_CTX_MUTEX_INIT(A) pthread_mutex_init(&A, NULL) +#define SSL_CTX_MUTEX_DESTROY(A) pthread_mutex_destroy(&A) +#define SSL_CTX_LOCK(A) pthread_mutex_lock(&A) +#define SSL_CTX_UNLOCK(A) pthread_mutex_unlock(&A) +#endif +#else /* no mutexing */ +#define SSL_CTX_MUTEX_INIT(A) +#define SSL_CTX_MUTEX_DESTROY(A) +#define SSL_CTX_LOCK(A) +#define SSL_CTX_UNLOCK(A) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ssl/os_port.o b/ssl/os_port.o new file mode 100644 index 0000000000000000000000000000000000000000..6c20927b3dc431d559f8956458439137b6d48b39 GIT binary patch literal 13424 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 +#include +#include +#include "os_port.h" +#include "ssl.h" + +/* all commented out if not used */ +#ifdef CONFIG_SSL_USE_PKCS12 + +#define BLOCK_SIZE 64 +#define PKCS12_KEY_ID 1 +#define PKCS12_IV_ID 2 +#define PKCS12_MAC_ID 3 + +static char *make_uni_pass(const char *password, int *uni_pass_len); +static int p8_decrypt(const char *uni_pass, int uni_pass_len, + const uint8_t *salt, int iter, + uint8_t *priv_key, int priv_key_len, int id); +static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key); +static int get_pbe_params(uint8_t *buf, int *offset, + const uint8_t **salt, int *iterations); + +/* + * Take a raw pkcs8 block and then decrypt it and turn it into a normal key. + */ +int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password) +{ + uint8_t *buf = ssl_obj->buf; + int len, offset = 0; + int iterations; + int ret = SSL_NOT_OK; + uint8_t *version = NULL; + const uint8_t *salt; + uint8_t *priv_key; + int uni_pass_len; + char *uni_pass = make_uni_pass(password, &uni_pass_len); + + if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0) + { +#ifdef CONFIG_SSL_FULL_MODE + printf("Error: Invalid p8 ASN.1 file\n"); +#endif + goto error; + } + + /* unencrypted key? */ + if (asn1_get_int(buf, &offset, &version) > 0 && *version == 0) + { + ret = p8_add_key(ssl_ctx, buf); + goto error; + } + + if (get_pbe_params(buf, &offset, &salt, &iterations) < 0) + goto error; + + if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0) + goto error; + + priv_key = &buf[offset]; + + p8_decrypt(uni_pass, uni_pass_len, salt, + iterations, priv_key, len, PKCS12_KEY_ID); + ret = p8_add_key(ssl_ctx, priv_key); + +error: + free(version); + free(uni_pass); + return ret; +} + +/* + * Take the unencrypted pkcs8 and turn it into a private key + */ +static int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key) +{ + uint8_t *buf = priv_key; + int len, offset = 0; + int ret = SSL_NOT_OK; + + /* Skip the preamble and go straight to the private key. + We only support rsaEncryption (1.2.840.113549.1.1.1) */ + if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 || + asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0) + goto error; + + ret = asn1_get_private_key(&buf[offset], len, &ssl_ctx->rsa_ctx); + +error: + return ret; +} + +/* + * Create the unicode password + */ +static char *make_uni_pass(const char *password, int *uni_pass_len) +{ + int pass_len = 0, i; + char *uni_pass; + + if (password == NULL) + { + password = ""; + } + + uni_pass = (char *)malloc((strlen(password)+1)*2); + + /* modify the password into a unicode version */ + for (i = 0; i < (int)strlen(password); i++) + { + uni_pass[pass_len++] = 0; + uni_pass[pass_len++] = password[i]; + } + + uni_pass[pass_len++] = 0; /* null terminate */ + uni_pass[pass_len++] = 0; + *uni_pass_len = pass_len; + return uni_pass; +} + +/* + * Decrypt a pkcs8 block. + */ +static int p8_decrypt(const char *uni_pass, int uni_pass_len, + const uint8_t *salt, int iter, + uint8_t *priv_key, int priv_key_len, int id) +{ + uint8_t p[BLOCK_SIZE*2]; + uint8_t d[BLOCK_SIZE]; + uint8_t Ai[SHA1_SIZE]; + SHA1_CTX sha_ctx; + RC4_CTX rc4_ctx; + int i; + + for (i = 0; i < BLOCK_SIZE; i++) + { + p[i] = salt[i % SALT_SIZE]; + p[BLOCK_SIZE+i] = uni_pass[i % uni_pass_len]; + d[i] = id; + } + + /* get the key - no IV since we are using RC4 */ + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx, d, sizeof(d)); + SHA1_Update(&sha_ctx, p, sizeof(p)); + SHA1_Final(Ai, &sha_ctx); + + for (i = 1; i < iter; i++) + { + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx, Ai, SHA1_SIZE); + SHA1_Final(Ai, &sha_ctx); + } + + /* do the decryption */ + if (id == PKCS12_KEY_ID) + { + RC4_setup(&rc4_ctx, Ai, 16); + RC4_crypt(&rc4_ctx, priv_key, priv_key, priv_key_len); + } + else /* MAC */ + memcpy(priv_key, Ai, SHA1_SIZE); + + return 0; +} + +/* + * Take a raw pkcs12 block and the decrypt it and turn it into a certificate(s) + * and keys. + */ +int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password) +{ + uint8_t *buf = ssl_obj->buf; + int len, iterations, auth_safes_start, + auth_safes_end, auth_safes_len, key_offset, offset = 0; + int all_certs = 0; + uint8_t *version = NULL, *auth_safes = NULL, *cert, *orig_mac; + uint8_t key[SHA1_SIZE]; + uint8_t mac[SHA1_SIZE]; + const uint8_t *salt; + int uni_pass_len, ret = SSL_OK; + char *uni_pass = make_uni_pass(password, &uni_pass_len); + static const uint8_t pkcs_data[] = /* pkc7 data */ + { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 }; + static const uint8_t pkcs_encrypted[] = /* pkc7 encrypted */ + { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06 }; + static const uint8_t pkcs8_key_bag[] = /* 1.2.840.113549.1.12.10.1.2 */ + { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02 }; + + if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0) + { +#ifdef CONFIG_SSL_FULL_MODE + printf("Error: Invalid p12 ASN.1 file\n"); +#endif + goto error; + } + + if (asn1_get_int(buf, &offset, &version) < 0 || *version != 3) + { + ret = SSL_ERROR_INVALID_VERSION; + goto error; + } + + /* remove all the boring pcks7 bits */ + if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || + len != sizeof(pkcs_data) || + memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data))) + goto error; + + offset += len; + + if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || + asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0) + goto error; + + /* work out the MAC start/end points (done on AuthSafes) */ + auth_safes_start = offset; + auth_safes_end = offset; + if (asn1_skip_obj(buf, &auth_safes_end, ASN1_SEQUENCE) < 0) + goto error; + + auth_safes_len = auth_safes_end - auth_safes_start; + auth_safes = malloc(auth_safes_len); + + memcpy(auth_safes, &buf[auth_safes_start], auth_safes_len); + + if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || + (len != sizeof(pkcs_encrypted) || + memcmp(&buf[offset], pkcs_encrypted, sizeof(pkcs_encrypted)))) + goto error; + + offset += len; + + if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || + asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 || + asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || + len != sizeof(pkcs_data) || + memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data))) + goto error; + + offset += len; + + /* work out the salt for the certificate */ + if (get_pbe_params(buf, &offset, &salt, &iterations) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_IMPLICIT_TAG)) < 0) + goto error; + + /* decrypt the certificate */ + cert = &buf[offset]; + if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert, + len, PKCS12_KEY_ID)) < 0) + goto error; + + offset += len; + + /* load the certificate */ + key_offset = 0; + all_certs = asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE); + + /* keep going until all certs are loaded */ + while (key_offset < all_certs) + { + int cert_offset = key_offset; + + if (asn1_skip_obj(cert, &cert_offset, ASN1_SEQUENCE) < 0 || + asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 || + asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 || + asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 || + asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 || + asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 || + asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 || + (len = asn1_next_obj(cert, &key_offset, ASN1_OCTET_STRING)) < 0) + goto error; + + if ((ret = add_cert(ssl_ctx, &cert[key_offset], len)) < 0) + goto error; + + key_offset = cert_offset; + } + + if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || + len != sizeof(pkcs_data) || + memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data))) + goto error; + + offset += len; + + if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || + asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0 || + asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 || + (len != sizeof(pkcs8_key_bag)) || + memcmp(&buf[offset], pkcs8_key_bag, sizeof(pkcs8_key_bag))) + goto error; + + offset += len; + + /* work out the salt for the private key */ + if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 || + asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + get_pbe_params(buf, &offset, &salt, &iterations) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0) + goto error; + + /* decrypt the private key */ + cert = &buf[offset]; + if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert, + len, PKCS12_KEY_ID)) < 0) + goto error; + + offset += len; + + /* load the private key */ + if ((ret = p8_add_key(ssl_ctx, cert)) < 0) + goto error; + + /* miss out on friendly name, local key id etc */ + if (asn1_skip_obj(buf, &offset, ASN1_SET) < 0) + goto error; + + /* work out the MAC */ + if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || + len != SHA1_SIZE) + goto error; + + orig_mac = &buf[offset]; + offset += len; + + /* get the salt */ + if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || len != 8) + goto error; + + salt = &buf[offset]; + + /* work out what the mac should be */ + if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, + key, SHA1_SIZE, PKCS12_MAC_ID)) < 0) + goto error; + + hmac_sha1(auth_safes, auth_safes_len, key, SHA1_SIZE, mac); + + if (memcmp(mac, orig_mac, SHA1_SIZE)) + { + ret = SSL_ERROR_INVALID_HMAC; + goto error; + } + +error: + free(version); + free(uni_pass); + free(auth_safes); + return ret; +} + +/* + * Retrieve the salt/iteration details from a PBE block. + */ +static int get_pbe_params(uint8_t *buf, int *offset, + const uint8_t **salt, int *iterations) +{ + static const uint8_t pbeSH1RC4[] = /* pbeWithSHAAnd128BitRC4 */ + { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x01 }; + + int i, len; + uint8_t *iter = NULL; + int error_code = SSL_ERROR_NOT_SUPPORTED; + + /* Get the PBE type */ + if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, offset, ASN1_OID)) < 0) + goto error; + + /* we expect pbeWithSHAAnd128BitRC4 (1.2.840.113549.1.12.1.1) + which is the only algorithm we support */ + if (len != sizeof(pbeSH1RC4) || + memcmp(&buf[*offset], pbeSH1RC4, sizeof(pbeSH1RC4))) + { +#ifdef CONFIG_SSL_FULL_MODE + printf("Error: pkcs8/pkcs12 must use \"PBE-SHA1-RC4-128\"\n"); +#endif + goto error; + } + + *offset += len; + + if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 || + (len = asn1_next_obj(buf, offset, ASN1_OCTET_STRING)) < 0 || + len != 8) + goto error; + + *salt = &buf[*offset]; + *offset += len; + + if ((len = asn1_get_int(buf, offset, &iter)) < 0) + goto error; + + *iterations = 0; + for (i = 0; i < len; i++) + { + (*iterations) <<= 8; + (*iterations) += iter[i]; + } + + free(iter); + error_code = SSL_OK; /* got here - we are ok */ + +error: + return error_code; +} + +#endif diff --git a/ssl/p12.o b/ssl/p12.o new file mode 100644 index 0000000000000000000000000000000000000000..8b874f138a88cbbfd6df82735082b23f1b2297d1 GIT binary patch literal 1812 zcma)7K~EDw6rSz2wos`MR4~M3H7c06+m>Jg#2SHALTM}I?H)|`?+BlOo_qXv7v{knd*{A zSYVTEf`!0Y;b#pO*7%0ukq9uB$>s@VGWnlmj4L;VDSQ^e++7$moAbkjWeT}5ER`wb zUlNzieHA7@k(%#hjKT#BGp3CDrRkzsnk!AtAbgJ%i%;RAmV^alU8fn8F1r&D!!2lr zO=C2SU!@6*V#8P)f5##Bd!g5{s3q>d_mZ|zE_I<@x7ie-0^?uUUNdUp3X6f^j+d(o*_T`krJB~O{qA0L;Hm$0&SaB*3)4i~(I8Tet6nc<&A$OZwVK-upy?S$P zeQ$TWv0ra)Z|&FLu5IttD&uSGTea#qk{y0FNZb}|5~sGW5FH0|I&R`Jr^PvQVlQx= zj@LTwHGL{BvD<3J-pL5<#%|d2FeS~Vb5a=9nbVF20}mT>PDQVdD2HzTQ|6FIJG~lzf8|w?qiO?+dNBbhilgV3zR8q$fkwXo;)#ejadcxf zsG0-FK0zN4kfONP@D(PC-sUU;DT;dqUthO?*H7!vy7VDX>o$Sa96HAHCNwBJeS7*wzK4ELe;q3R)RMD%!;UHsNb^RnACYL0Y5>**_!uip&$XhIWn zq$A>~>!Fy8p6gIdRvbD&Cha)=%!tZ{EKlcP$WnB!3g6H$eUlA(01ykRa^^McX!x;) fpJNgyCnGo8Dq)d literal 0 HcmV?d00001 diff --git a/ssl/private_key.h b/ssl/private_key.h new file mode 100644 index 000000000..ce7985c5a --- /dev/null +++ b/ssl/private_key.h @@ -0,0 +1,54 @@ +unsigned char default_private_key[] = { + 0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xcd, + 0xfd, 0x89, 0x48, 0xbe, 0x36, 0xb9, 0x95, 0x76, 0xd4, 0x13, 0x30, 0x0e, + 0xbf, 0xb2, 0xed, 0x67, 0x0a, 0xc0, 0x16, 0x3f, 0x51, 0x09, 0x9d, 0x29, + 0x2f, 0xb2, 0x6d, 0x3f, 0x3e, 0x6c, 0x2f, 0x90, 0x80, 0xa1, 0x71, 0xdf, + 0xbe, 0x38, 0xc5, 0xcb, 0xa9, 0x9a, 0x40, 0x14, 0x90, 0x0a, 0xf9, 0xb7, + 0x07, 0x0b, 0xe1, 0xda, 0xe7, 0x09, 0xbf, 0x0d, 0x57, 0x41, 0x86, 0x60, + 0xa1, 0xc1, 0x27, 0x91, 0x5b, 0x0a, 0x98, 0x46, 0x1b, 0xf6, 0xa2, 0x84, + 0xf8, 0x65, 0xc7, 0xce, 0x2d, 0x96, 0x17, 0xaa, 0x91, 0xf8, 0x61, 0x04, + 0x50, 0x70, 0xeb, 0xb4, 0x43, 0xb7, 0xdc, 0x9a, 0xcc, 0x31, 0x01, 0x14, + 0xd4, 0xcd, 0xcc, 0xc2, 0x37, 0x6d, 0x69, 0x82, 0xd6, 0xc6, 0xc4, 0xbe, + 0xf2, 0x34, 0xa5, 0xc9, 0xa6, 0x19, 0x53, 0x32, 0x7a, 0x86, 0x0e, 0x91, + 0x82, 0x0f, 0xa1, 0x42, 0x54, 0xaa, 0x01, 0x02, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x81, 0x81, 0x00, 0x95, 0xaa, 0x6e, 0x11, 0xf5, 0x6a, 0x8b, 0xa2, + 0xc6, 0x48, 0xc6, 0x7c, 0x37, 0x6b, 0x1f, 0x55, 0x10, 0x76, 0x26, 0x24, + 0xc3, 0xf2, 0x5c, 0x5a, 0xdd, 0x2e, 0xf3, 0xa4, 0x1e, 0xbc, 0x7b, 0x1c, + 0x80, 0x10, 0x85, 0xbc, 0xd8, 0x45, 0x3c, 0xb8, 0xb2, 0x06, 0x53, 0xb5, + 0xd5, 0x7a, 0xe7, 0x0e, 0x92, 0xe6, 0x42, 0xc2, 0xe2, 0x2a, 0xd5, 0xd1, + 0x03, 0x9f, 0x6f, 0x53, 0x74, 0x68, 0x72, 0x8e, 0xbf, 0x03, 0xbb, 0xab, + 0xbd, 0xa1, 0xf9, 0x81, 0x7d, 0x12, 0xd4, 0x9d, 0xb6, 0xae, 0x4c, 0xad, + 0xca, 0xa8, 0xc9, 0x80, 0x8d, 0x0d, 0xd5, 0xd0, 0xa1, 0xbf, 0xec, 0x60, + 0x48, 0x49, 0xed, 0x97, 0x0f, 0x5e, 0xed, 0xfc, 0x39, 0x15, 0x96, 0x9e, + 0x5d, 0xe2, 0xb4, 0x5d, 0x2e, 0x04, 0xdc, 0x08, 0xa2, 0x65, 0x29, 0x2d, + 0x37, 0xfb, 0x62, 0x90, 0x1b, 0x7b, 0xe5, 0x3a, 0x58, 0x05, 0x55, 0xc1, + 0x02, 0x41, 0x00, 0xfc, 0x69, 0x28, 0xc9, 0xa8, 0xc4, 0x5c, 0xe3, 0xd0, + 0x5e, 0xaa, 0xda, 0xde, 0x87, 0x74, 0xdb, 0xcb, 0x40, 0x78, 0x8e, 0x1d, + 0x12, 0x96, 0x16, 0x61, 0x3f, 0xb3, 0x3e, 0xa3, 0x0d, 0xdc, 0x49, 0xa5, + 0x25, 0x87, 0xc5, 0x97, 0x85, 0x9d, 0xbb, 0xb4, 0xf0, 0x44, 0xfd, 0x6c, + 0xe8, 0xd2, 0x8c, 0xec, 0x33, 0x81, 0x46, 0x1e, 0x10, 0x12, 0x33, 0x16, + 0x95, 0x00, 0x4f, 0x75, 0xb4, 0xe5, 0x79, 0x02, 0x41, 0x00, 0xd0, 0xeb, + 0x65, 0x07, 0x10, 0x3b, 0xd9, 0x03, 0xeb, 0xdc, 0x6f, 0x4b, 0x8f, 0xc3, + 0x87, 0xce, 0x76, 0xd6, 0xc5, 0x14, 0x21, 0x4e, 0xe7, 0x4f, 0x1b, 0xe8, + 0x05, 0xf8, 0x84, 0x1a, 0xe0, 0xc5, 0xd6, 0xe3, 0x08, 0xb3, 0x54, 0x57, + 0x02, 0x1f, 0xd4, 0xd9, 0xfb, 0xff, 0x40, 0xb1, 0x56, 0x1c, 0x60, 0xf7, + 0xac, 0x91, 0xf3, 0xd3, 0xc6, 0x7f, 0x84, 0xfd, 0x84, 0x9d, 0xea, 0x26, + 0xee, 0xc9, 0x02, 0x41, 0x00, 0xa6, 0xcf, 0x1c, 0x6c, 0x81, 0x03, 0x1c, + 0x5c, 0x56, 0x05, 0x6a, 0x26, 0x70, 0xef, 0xd6, 0x13, 0xb7, 0x74, 0x28, + 0xf7, 0xca, 0x50, 0xd1, 0x2d, 0x83, 0x21, 0x64, 0xe4, 0xdd, 0x3f, 0x38, + 0xb8, 0xd6, 0xd2, 0x41, 0xb3, 0x1c, 0x9a, 0xea, 0x0d, 0xf5, 0xda, 0xdf, + 0xcd, 0x17, 0x9f, 0x9a, 0x1e, 0x15, 0xaf, 0x48, 0x1c, 0xbd, 0x9b, 0x63, + 0x5b, 0xad, 0xed, 0xd4, 0xa1, 0xae, 0xa9, 0x59, 0x09, 0x02, 0x40, 0x4e, + 0x08, 0xce, 0xa8, 0x8f, 0xc0, 0xba, 0xf3, 0x83, 0x02, 0xc8, 0x33, 0x62, + 0x14, 0x77, 0xc2, 0x7f, 0x93, 0x02, 0xf3, 0xdc, 0xe9, 0x1a, 0xee, 0xea, + 0x8e, 0x84, 0xc4, 0x69, 0x9b, 0x9c, 0x7f, 0x69, 0x1f, 0x4e, 0x1d, 0xa5, + 0x90, 0x06, 0x44, 0x1b, 0x7d, 0xfc, 0x69, 0x40, 0x21, 0xbc, 0xf7, 0x46, + 0xa4, 0xdc, 0x39, 0x7b, 0xe8, 0x8b, 0x49, 0x10, 0x44, 0x9d, 0x67, 0x5a, + 0x91, 0x86, 0x39, 0x02, 0x40, 0x41, 0x2c, 0x4e, 0xfe, 0xd9, 0x90, 0x89, + 0x00, 0x5c, 0x94, 0x0a, 0x4a, 0x7e, 0x1b, 0x1a, 0x80, 0x06, 0x01, 0x37, + 0xda, 0x50, 0x61, 0x9d, 0x9c, 0xfe, 0x25, 0x7f, 0xd8, 0xd4, 0xc4, 0x9e, + 0x81, 0xf2, 0x0c, 0x1e, 0x38, 0x21, 0x1e, 0x90, 0x3f, 0xd4, 0xba, 0x6c, + 0x53, 0xcb, 0xf0, 0x77, 0x79, 0x9b, 0xf1, 0xfa, 0x3f, 0x81, 0xdc, 0xf3, + 0x21, 0x02, 0x6d, 0xb7, 0x95, 0xc3, 0x2e, 0xce, 0xd5 +}; +unsigned int default_private_key_len = 609; diff --git a/ssl/ssl.h b/ssl/ssl.h new file mode 100644 index 000000000..198efc689 --- /dev/null +++ b/ssl/ssl.h @@ -0,0 +1,499 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @mainpage axTLS API + * + * @image html axolotl.jpg + * + * The axTLS library has features such as: + * - The TLSv1 SSL client/server protocol + * - No requirement to use any openssl libraries. + * - A choice between AES block (128/256 bit) and RC4 (128 bit) stream ciphers. + * - RSA encryption/decryption with variable sized keys (up to 4096 bits). + * - Certificate chaining and peer authentication. + * - Session resumption, session renegotiation. + * - ASN.1, X.509, PKCS#8, PKCS#12 keys/certificates with DER/PEM encoding. + * - Highly configurable compile time options. + * - Portable across many platforms (written in ANSI C), and has language + * bindings in C, C#, VB.NET, Java, Perl and Lua. + * - Partial openssl API compatibility (via a wrapper). + * - A very small footprint (around 50-60kB for the library in 'server-only' + * mode). + * - No dependencies on sockets - can use serial connections for example. + * - A very simple API - ~ 20 functions/methods. + * + * A list of these functions/methods are described below. + * + * @ref c_api + * + * @ref bigint_api + * + * @ref csharp_api + * + * @ref java_api + */ +#ifndef HEADER_SSL_H +#define HEADER_SSL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* need to predefine before ssl_lib.h gets to it */ +#define SSL_SESSION_ID_SIZE 32 + +#include "tls1.h" + +/* The optional parameters that can be given to the client/server SSL engine */ +#define SSL_CLIENT_AUTHENTICATION 0x00010000 +#define SSL_SERVER_VERIFY_LATER 0x00020000 +#define SSL_NO_DEFAULT_KEY 0x00040000 +#define SSL_DISPLAY_STATES 0x00080000 +#define SSL_DISPLAY_BYTES 0x00100000 +#define SSL_DISPLAY_CERTS 0x00200000 +#define SSL_DISPLAY_RSA 0x00400000 +#define SSL_CONNECT_IN_PARTS 0x00800000 + +/* errors that can be generated */ +#define SSL_OK 0 +#define SSL_NOT_OK -1 +#define SSL_ERROR_DEAD -2 +#define SSL_CLOSE_NOTIFY -3 +#define SSL_ERROR_CONN_LOST -256 +#define SSL_ERROR_SOCK_SETUP_FAILURE -258 +#define SSL_ERROR_INVALID_HANDSHAKE -260 +#define SSL_ERROR_INVALID_PROT_MSG -261 +#define SSL_ERROR_INVALID_HMAC -262 +#define SSL_ERROR_INVALID_VERSION -263 +#define SSL_ERROR_INVALID_SESSION -265 +#define SSL_ERROR_NO_CIPHER -266 +#define SSL_ERROR_BAD_CERTIFICATE -268 +#define SSL_ERROR_INVALID_KEY -269 +#define SSL_ERROR_FINISHED_INVALID -271 +#define SSL_ERROR_NO_CERT_DEFINED -272 +#define SSL_ERROR_NO_CLIENT_RENOG -273 +#define SSL_ERROR_NOT_SUPPORTED -274 +#define SSL_X509_OFFSET -512 +#define SSL_X509_ERROR(A) (SSL_X509_OFFSET+A) + +/* alert types that are recognized */ +#define SSL_ALERT_TYPE_WARNING 1 +#define SLL_ALERT_TYPE_FATAL 2 + +/* these are all the alerts that are recognized */ +#define SSL_ALERT_CLOSE_NOTIFY 0 +#define SSL_ALERT_UNEXPECTED_MESSAGE 10 +#define SSL_ALERT_BAD_RECORD_MAC 20 +#define SSL_ALERT_HANDSHAKE_FAILURE 40 +#define SSL_ALERT_BAD_CERTIFICATE 42 +#define SSL_ALERT_ILLEGAL_PARAMETER 47 +#define SSL_ALERT_DECODE_ERROR 50 +#define SSL_ALERT_DECRYPT_ERROR 51 +#define SSL_ALERT_INVALID_VERSION 70 +#define SSL_ALERT_NO_RENEGOTIATION 100 + +/* The ciphers that are supported */ +#define SSL_AES128_SHA 0x2f +#define SSL_AES256_SHA 0x35 +#define SSL_RC4_128_SHA 0x05 +#define SSL_RC4_128_MD5 0x04 + +/* build mode ids' */ +#define SSL_BUILD_SKELETON_MODE 0x01 +#define SSL_BUILD_SERVER_ONLY 0x02 +#define SSL_BUILD_ENABLE_VERIFICATION 0x03 +#define SSL_BUILD_ENABLE_CLIENT 0x04 +#define SSL_BUILD_FULL_MODE 0x05 + +/* offsets to retrieve configuration information */ +#define SSL_BUILD_MODE 0 +#define SSL_MAX_CERT_CFG_OFFSET 1 +#define SSL_MAX_CA_CERT_CFG_OFFSET 2 +#define SSL_HAS_PEM 3 + +/* default session sizes */ +#define SSL_DEFAULT_SVR_SESS 5 +#define SSL_DEFAULT_CLNT_SESS 1 + +/* X.509/X.520 distinguished name types */ +#define SSL_X509_CERT_COMMON_NAME 0 +#define SSL_X509_CERT_ORGANIZATION 1 +#define SSL_X509_CERT_ORGANIZATIONAL_NAME 2 +#define SSL_X509_CA_CERT_COMMON_NAME 3 +#define SSL_X509_CA_CERT_ORGANIZATION 4 +#define SSL_X509_CA_CERT_ORGANIZATIONAL_NAME 5 + +/* SSL object loader types */ +#define SSL_OBJ_X509_CERT 1 +#define SSL_OBJ_X509_CACERT 2 +#define SSL_OBJ_RSA_KEY 3 +#define SSL_OBJ_PKCS8 4 +#define SSL_OBJ_PKCS12 5 + +/** + * @defgroup c_api Standard C API + * @brief The standard interface in C. + * @{ + */ + +/** + * @brief Establish a new client/server context. + * + * This function is called before any client/server SSL connections are made. + * + * Each new connection will use the this context's private key and + * certificate chain. If a different certificate chain is required, then a + * different context needs to be be used. + * + * There are two threading models supported - a single thread with one + * SSL_CTX can support any number of SSL connections - and multiple threads can + * support one SSL_CTX object each (the default). But if a single SSL_CTX + * object uses many SSL objects in individual threads, then the + * CONFIG_SSL_CTX_MUTEXING option needs to be configured. + * + * @param options [in] Any particular options. At present the options + * supported are: + * - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if the server + * authentication fails. The certificate can be authenticated later with a + * call to ssl_verify_cert(). + * - SSL_CLIENT_AUTHENTICATION (server only): Enforce client authentication + * i.e. each handshake will include a "certificate request" message from the + * server. Only available if verification has been enabled. + * - SSL_DISPLAY_BYTES (full mode build only): Display the byte sequences + * during the handshake. + * - SSL_DISPLAY_STATES (full mode build only): Display the state changes + * during the handshake. + * - SSL_DISPLAY_CERTS (full mode build only): Display the certificates that + * are passed during a handshake. + * - SSL_DISPLAY_RSA (full mode build only): Display the RSA key details that + * are passed during a handshake. + * - SSL_CONNECT_IN_PARTS (client only): To use a non-blocking version of + * ssl_client_new(). + * @param num_sessions [in] The number of sessions to be used for session + * caching. If this value is 0, then there is no session caching. This option + * is not used in skeleton mode. + * @return A client/server context. + */ +EXP_FUNC SSL_CTX * STDCALL ssl_ctx_new(uint32_t options, int num_sessions); + +/** + * @brief Remove a client/server context. + * + * Frees any used resources used by this context. Each connection will be + * sent a "Close Notify" alert (if possible). + * @param ssl_ctx [in] The client/server context. + */ +EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx); + +/** + * @brief (server only) Establish a new SSL connection to an SSL client. + * + * It is up to the application to establish the logical connection (whether it + * is a socket, serial connection etc). + * @param ssl_ctx [in] The server context. + * @param client_fd [in] The client's file descriptor. + * @return An SSL object reference. + */ +EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd); + +/** + * @brief (client only) Establish a new SSL connection to an SSL server. + * + * It is up to the application to establish the initial logical connection + * (whether it is a socket, serial connection etc). + * + * This is a normally a blocking call - it will finish when the handshake is + * complete (or has failed). To use in non-blocking mode, set + * SSL_CONNECT_IN_PARTS in ssl_ctx_new(). + * @param ssl_ctx [in] The client context. + * @param client_fd [in] The client's file descriptor. + * @param session_id [in] A 32 byte session id for session resumption. This + * can be null if no session resumption is being used or required. This option + * is not used in skeleton mode. + * @param sess_id_size The size of the session id (max 32) + * @return An SSL object reference. Use ssl_handshake_status() to check + * if a handshake succeeded. + */ +EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const uint8_t *session_id, uint8_t sess_id_size); + +/** + * @brief Free any used resources on this connection. + + * A "Close Notify" message is sent on this connection (if possible). It is up + * to the application to close the socket or file descriptor. + * @param ssl [in] The ssl object reference. + */ +EXP_FUNC void STDCALL ssl_free(SSL *ssl); + +/** + * @brief Read the SSL data stream. + * If the socket is non-blocking and data is blocked then SSO_OK will be + * returned. + * @param ssl [in] An SSL object reference. + * @param in_data [out] If the read was successful, a pointer to the read + * buffer will be here. Do NOT ever free this memory as this buffer is used in + * sucessive calls. If the call was unsuccessful, this value will be null. + * @return The number of decrypted bytes: + * - if > 0, then the handshaking is complete and we are returning the number + * of decrypted bytes. + * - SSL_OK if the handshaking stage is successful (but not yet complete). + * - < 0 if an error. + * @see ssl.h for the error code list. + * @note Use in_data before doing any successive ssl calls. + */ +EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data); + +/** + * @brief Write to the SSL data stream. + * if the socket is non-blocking and data is blocked then a check is made + * to ensure that all data is sent (i.e. blocked mode is forced). + * @param ssl [in] An SSL obect reference. + * @param out_data [in] The data to be written + * @param out_len [in] The number of bytes to be written. + * @return The number of bytes sent, or if < 0 if an error. + * @see ssl.h for the error code list. + */ +EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len); + +/** + * @brief Find an ssl object based on a file descriptor. + * + * Goes through the list of SSL objects maintained in a client/server context + * to look for a file descriptor match. + * @param ssl_ctx [in] The client/server context. + * @param client_fd [in] The file descriptor. + * @return A reference to the SSL object. Returns null if the object could not + * be found. + */ +EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd); + +/** + * @brief Get the session id for a handshake. + * + * This will be a 32 byte sequence and is available after the first + * handshaking messages are sent. + * @param ssl [in] An SSL object reference. + * @return The session id as a 32 byte sequence. + * @note A SSLv23 handshake may have only 16 valid bytes. + */ +EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl); + +/** + * @brief Get the session id size for a handshake. + * + * This will normally be 32 but could be 0 (no session id) or something else. + * @param ssl [in] An SSL object reference. + * @return The size of the session id. + */ +EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl); + +/** + * @brief Return the cipher id (in the SSL form). + * @param ssl [in] An SSL object reference. + * @return The cipher id. This will be one of the following: + * - SSL_AES128_SHA (0x2f) + * - SSL_AES256_SHA (0x35) + * - SSL_RC4_128_SHA (0x05) + * - SSL_RC4_128_MD5 (0x04) + */ +EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl); + +/** + * @brief Return the status of the handshake. + * @param ssl [in] An SSL object reference. + * @return SSL_OK if the handshake is complete and ok. + * @see ssl.h for the error code list. + */ +EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl); + +/** + * @brief Retrieve various parameters about the axTLS engine. + * @param offset [in] The configuration offset. It will be one of the following: + * - SSL_BUILD_MODE The build mode. This will be one of the following: + * - SSL_BUILD_SERVER_ONLY (basic server mode) + * - SSL_BUILD_ENABLE_VERIFICATION (server can do client authentication) + * - SSL_BUILD_ENABLE_CLIENT (client/server capabilties) + * - SSL_BUILD_FULL_MODE (client/server with diagnostics) + * - SSL_BUILD_SKELETON_MODE (skeleton mode) + * - SSL_MAX_CERT_CFG_OFFSET The maximum number of certificates allowed. + * - SSL_MAX_CA_CERT_CFG_OFFSET The maximum number of CA certificates allowed. + * - SSL_HAS_PEM 1 if supported + * @return The value of the requested parameter. + */ +EXP_FUNC int STDCALL ssl_get_config(int offset); + +/** + * @brief Display why the handshake failed. + * + * This call is only useful in a 'full mode' build. The output is to stdout. + * @param error_code [in] An error code. + * @see ssl.h for the error code list. + */ +EXP_FUNC void STDCALL ssl_display_error(int error_code); + +/** + * @brief Authenticate a received certificate. + * + * This call is usually made by a client after a handshake is complete and the + * context is in SSL_SERVER_VERIFY_LATER mode. + * @param ssl [in] An SSL object reference. + * @return SSL_OK if the certificate is verified. + */ +EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl); + +/** + * @brief Retrieve an X.509 distinguished name component. + * + * When a handshake is complete and a certificate has been exchanged, then the + * details of the remote certificate can be retrieved. + * + * This will usually be used by a client to check that the server's common + * name matches the URL. + * + * @param ssl [in] An SSL object reference. + * @param component [in] one of: + * - SSL_X509_CERT_COMMON_NAME + * - SSL_X509_CERT_ORGANIZATION + * - SSL_X509_CERT_ORGANIZATIONAL_NAME + * - SSL_X509_CA_CERT_COMMON_NAME + * - SSL_X509_CA_CERT_ORGANIZATION + * - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME + * @return The appropriate string (or null if not defined) + * @note Verification build mode must be enabled. + */ +EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component); + +/** + * @brief Retrieve a Subject Alternative DNSName + * + * When a handshake is complete and a certificate has been exchanged, then the + * details of the remote certificate can be retrieved. + * + * This will usually be used by a client to check that the server's DNS + * name matches the URL. + * + * @param ssl [in] An SSL object reference. + * @param dnsindex [in] The index of the DNS name to retrieve. + * @return The appropriate string (or null if not defined) + * @note Verification build mode must be enabled. + */ +EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int dnsindex); + +/** + * @brief Force the client to perform its handshake again. + * + * For a client this involves sending another "client hello" message. + * For the server is means sending a "hello request" message. + * + * This is a blocking call on the client (until the handshake completes). + * + * @param ssl [in] An SSL object reference. + * @return SSL_OK if renegotiation instantiation was ok + */ +EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl); + +/** + * @brief Process a file that is in binary DER or ASCII PEM format. + * + * These are temporary objects that are used to load private keys, + * certificates etc into memory. + * @param ssl_ctx [in] The client/server context. + * @param obj_type [in] The format of the file. Can be one of: + * - SSL_OBJ_X509_CERT (no password required) + * - SSL_OBJ_X509_CACERT (no password required) + * - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported) + * - SSL_OBJ_PKCS8 (RC4-128 encrypted data supported) + * - SSL_OBJ_PKCS12 (RC4-128 encrypted data supported) + * + * PEM files are automatically detected (if supported). The object type is + * also detected, and so is not relevant for these types of files. + * @param filename [in] The location of a file in DER/PEM format. + * @param password [in] The password used. Can be null if not required. + * @return SSL_OK if all ok + * @note Not available in skeleton build mode. + */ +EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, const char *filename, const char *password); + +/** + * @brief Process binary data. + * + * These are temporary objects that are used to load private keys, + * certificates etc into memory. + * @param ssl_ctx [in] The client/server context. + * @param obj_type [in] The format of the memory data. + * @param data [in] The binary data to be loaded. + * @param len [in] The amount of data to be loaded. + * @param password [in] The password used. Can be null if not required. + * @return SSL_OK if all ok + * @see ssl_obj_load for more details on obj_type. + */ +EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int obj_type, const uint8_t *data, int len, const char *password); + +#ifdef CONFIG_SSL_GENERATE_X509_CERT +/** + * @brief Create an X.509 certificate. + * + * This certificate is a self-signed v1 cert with a fixed start/stop validity + * times. It is signed with an internal private key in ssl_ctx. + * + * @param ssl_ctx [in] The client/server context. + * @param options [in] Not used yet. + * @param dn [in] An array of distinguished name strings. The array is defined + * by: + * - SSL_X509_CERT_COMMON_NAME (0) + * - If SSL_X509_CERT_COMMON_NAME is empty or not defined, then the + * hostname will be used. + * - SSL_X509_CERT_ORGANIZATION (1) + * - If SSL_X509_CERT_ORGANIZATION is empty or not defined, then $USERNAME + * will be used. + * - SSL_X509_CERT_ORGANIZATIONAL_NAME (2) + * - SSL_X509_CERT_ORGANIZATIONAL_NAME is optional. + * @param cert_data [out] The certificate as a sequence of bytes. + * @return < 0 if an error, or the size of the certificate in bytes. + * @note cert_data must be freed when there is no more need for it. + */ +EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data); +#endif + +/** + * @brief Return the axTLS library version as a string. + */ +EXP_FUNC const char * STDCALL ssl_version(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ssl/tls1.c b/ssl/tls1.c new file mode 100644 index 000000000..428c9ea56 --- /dev/null +++ b/ssl/tls1.c @@ -0,0 +1,2191 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Common ssl/tlsv1 code to both the client and server implementations. + */ + +#include +#include +#include +#include +#include "os_port.h" +#include "ssl.h" + +/* The session expiry time */ +#define SSL_EXPIRY_TIME (CONFIG_SSL_EXPIRY_TIME*3600) + +static const uint8_t g_hello_request[] = { HS_HELLO_REQUEST, 0, 0, 0 }; +static const uint8_t g_chg_cipher_spec_pkt[] = { 1 }; +static const char * server_finished = "server finished"; +static const char * client_finished = "client finished"; + +static int do_handshake(SSL *ssl, uint8_t *buf, int read_len); +static int set_key_block(SSL *ssl, int is_write); +static int verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len); +static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt); +static int send_raw_packet(SSL *ssl, uint8_t protocol); + +/** + * The server will pick the cipher based on the order that the order that the + * ciphers are listed. This order is defined at compile time. + */ +#ifdef CONFIG_SSL_SKELETON_MODE +const uint8_t ssl_prot_prefs[NUM_PROTOCOLS] = +{ SSL_RC4_128_SHA }; +#else +static void session_free(SSL_SESSION *ssl_sessions[], int sess_index); + +const uint8_t ssl_prot_prefs[NUM_PROTOCOLS] = +#ifdef CONFIG_SSL_PROT_LOW /* low security, fast speed */ +{ SSL_RC4_128_SHA, SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_MD5 }; +#elif CONFIG_SSL_PROT_MEDIUM /* medium security, medium speed */ +{ SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5 }; +#else /* CONFIG_SSL_PROT_HIGH */ /* high security, low speed */ +{ SSL_AES256_SHA, SSL_AES128_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5 }; +#endif +#endif /* CONFIG_SSL_SKELETON_MODE */ + +/** + * The cipher map containing all the essentials for each cipher. + */ +#ifdef CONFIG_SSL_SKELETON_MODE +static const cipher_info_t cipher_info[NUM_PROTOCOLS] = +{ + { /* RC4-SHA */ + SSL_RC4_128_SHA, /* RC4-SHA */ + 16, /* key size */ + 0, /* iv size */ + 2*(SHA1_SIZE+16), /* key block size */ + 0, /* no padding */ + SHA1_SIZE, /* digest size */ + hmac_sha1, /* hmac algorithm */ + (crypt_func)RC4_crypt, /* encrypt */ + (crypt_func)RC4_crypt /* decrypt */ + }, +}; +#else +static const cipher_info_t cipher_info[NUM_PROTOCOLS] = +{ + { /* AES128-SHA */ + SSL_AES128_SHA, /* AES128-SHA */ + 16, /* key size */ + 16, /* iv size */ + 2*(SHA1_SIZE+16+16), /* key block size */ + 16, /* block padding size */ + SHA1_SIZE, /* digest size */ + hmac_sha1, /* hmac algorithm */ + (crypt_func)AES_cbc_encrypt, /* encrypt */ + (crypt_func)AES_cbc_decrypt /* decrypt */ + }, + { /* AES256-SHA */ + SSL_AES256_SHA, /* AES256-SHA */ + 32, /* key size */ + 16, /* iv size */ + 2*(SHA1_SIZE+32+16), /* key block size */ + 16, /* block padding size */ + SHA1_SIZE, /* digest size */ + hmac_sha1, /* hmac algorithm */ + (crypt_func)AES_cbc_encrypt, /* encrypt */ + (crypt_func)AES_cbc_decrypt /* decrypt */ + }, + { /* RC4-SHA */ + SSL_RC4_128_SHA, /* RC4-SHA */ + 16, /* key size */ + 0, /* iv size */ + 2*(SHA1_SIZE+16), /* key block size */ + 0, /* no padding */ + SHA1_SIZE, /* digest size */ + hmac_sha1, /* hmac algorithm */ + (crypt_func)RC4_crypt, /* encrypt */ + (crypt_func)RC4_crypt /* decrypt */ + }, + /* + * This protocol is from SSLv2 days and is unlikely to be used - but was + * useful for testing different possible digest algorithms. + */ + { /* RC4-MD5 */ + SSL_RC4_128_MD5, /* RC4-MD5 */ + 16, /* key size */ + 0, /* iv size */ + 2*(MD5_SIZE+16), /* key block size */ + 0, /* no padding */ + MD5_SIZE, /* digest size */ + hmac_md5, /* hmac algorithm */ + (crypt_func)RC4_crypt, /* encrypt */ + (crypt_func)RC4_crypt /* decrypt */ + }, +}; +#endif + +static void prf(const uint8_t *sec, int sec_len, uint8_t *seed, int seed_len, + uint8_t *out, int olen); +static const cipher_info_t *get_cipher_info(uint8_t cipher); +static void increment_read_sequence(SSL *ssl); +static void increment_write_sequence(SSL *ssl); +static void add_hmac_digest(SSL *ssl, int snd, uint8_t *hmac_header, + const uint8_t *buf, int buf_len, uint8_t *hmac_buf); + +/* win32 VC6.0 doesn't have variadic macros */ +#if defined(WIN32) && !defined(CONFIG_SSL_FULL_MODE) +void DISPLAY_BYTES(SSL *ssl, const char *format, + const uint8_t *data, int size, ...) {} +#endif + +/** + * Establish a new client/server context. + */ +EXP_FUNC SSL_CTX *STDCALL ssl_ctx_new(uint32_t options, int num_sessions) +{ + SSL_CTX *ssl_ctx = (SSL_CTX *)calloc(1, sizeof (SSL_CTX)); + ssl_ctx->options = options; + RNG_initialize(); + + if (load_key_certs(ssl_ctx) < 0) + { + free(ssl_ctx); /* can't load our key/certificate pair, so die */ + return NULL; + } + +#ifndef CONFIG_SSL_SKELETON_MODE + ssl_ctx->num_sessions = num_sessions; +#endif + + SSL_CTX_MUTEX_INIT(ssl_ctx->mutex); + +#ifndef CONFIG_SSL_SKELETON_MODE + if (num_sessions) + { + ssl_ctx->ssl_sessions = (SSL_SESSION **) + calloc(1, num_sessions*sizeof(SSL_SESSION *)); + } +#endif + + return ssl_ctx; +} + +/* + * Remove a client/server context. + */ +EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx) +{ + SSL *ssl; + int i; + + if (ssl_ctx == NULL) + return; + + ssl = ssl_ctx->head; + + /* clear out all the ssl entries */ + while (ssl) + { + SSL *next = ssl->next; + ssl_free(ssl); + ssl = next; + } + +#ifndef CONFIG_SSL_SKELETON_MODE + /* clear out all the sessions */ + for (i = 0; i < ssl_ctx->num_sessions; i++) + session_free(ssl_ctx->ssl_sessions, i); + + free(ssl_ctx->ssl_sessions); +#endif + + i = 0; + while (i < CONFIG_SSL_MAX_CERTS && ssl_ctx->certs[i].buf) + { + free(ssl_ctx->certs[i].buf); + ssl_ctx->certs[i++].buf = NULL; + } + +#ifdef CONFIG_SSL_CERT_VERIFICATION + remove_ca_certs(ssl_ctx->ca_cert_ctx); +#endif + ssl_ctx->chain_length = 0; + SSL_CTX_MUTEX_DESTROY(ssl_ctx->mutex); + RSA_free(ssl_ctx->rsa_ctx); + RNG_terminate(); + free(ssl_ctx); +} + +/* + * Free any used resources used by this connection. + */ +EXP_FUNC void STDCALL ssl_free(SSL *ssl) +{ + SSL_CTX *ssl_ctx; + + if (ssl == NULL) /* just ignore null pointers */ + return; + + /* only notify if we weren't notified first */ + /* spec says we must notify when we are dying */ + if (!IS_SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY)) + send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY); + + ssl_ctx = ssl->ssl_ctx; + + SSL_CTX_LOCK(ssl_ctx->mutex); + + /* adjust the server SSL list */ + if (ssl->prev) + ssl->prev->next = ssl->next; + else + ssl_ctx->head = ssl->next; + + if (ssl->next) + ssl->next->prev = ssl->prev; + else + ssl_ctx->tail = ssl->prev; + + SSL_CTX_UNLOCK(ssl_ctx->mutex); + + /* may already be free - but be sure */ + free(ssl->encrypt_ctx); + free(ssl->decrypt_ctx); + disposable_free(ssl); +#ifdef CONFIG_SSL_CERT_VERIFICATION + x509_free(ssl->x509_ctx); +#endif + + free(ssl); +} + +/* + * Read the SSL connection and send any alerts for various errors. + */ +EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data) +{ + int ret = basic_read(ssl, in_data); + + /* check for return code so we can send an alert */ + if (ret < SSL_OK && ret != SSL_CLOSE_NOTIFY) + { + if (ret != SSL_ERROR_CONN_LOST) + { + send_alert(ssl, ret); +#ifndef CONFIG_SSL_SKELETON_MODE + /* something nasty happened, so get rid of this session */ + kill_ssl_session(ssl->ssl_ctx->ssl_sessions, ssl); +#endif + } + } + + return ret; +} + +/* + * Write application data to the client + */ +EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len) +{ + int n = out_len, nw, i, tot = 0; + + /* maximum size of a TLS packet is around 16kB, so fragment */ + do + { + nw = n; + + if (nw > RT_MAX_PLAIN_LENGTH) /* fragment if necessary */ + nw = RT_MAX_PLAIN_LENGTH; + + if ((i = send_packet(ssl, PT_APP_PROTOCOL_DATA, + &out_data[tot], nw)) <= 0) + { + out_len = i; /* an error */ + break; + } + + tot += i; + n -= i; + } while (n > 0); + + return out_len; +} + +/** + * Add a certificate to the certificate chain. + */ +int add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len) +{ + int ret = SSL_ERROR_NO_CERT_DEFINED, i = 0; + SSL_CERT *ssl_cert; + X509_CTX *cert = NULL; + int offset; + + while (ssl_ctx->certs[i].buf && i < CONFIG_SSL_MAX_CERTS) + i++; + + if (i == CONFIG_SSL_MAX_CERTS) /* too many certs */ + { +#ifdef CONFIG_SSL_FULL_MODE + printf("Error: maximum number of certs added (%d) - change of " + "compile-time configuration required\n", + CONFIG_SSL_MAX_CERTS); +#endif + goto error; + } + + if ((ret = x509_new(buf, &offset, &cert))) + goto error; + +#if defined (CONFIG_SSL_FULL_MODE) + if (ssl_ctx->options & SSL_DISPLAY_CERTS) + x509_print(cert, NULL); +#endif + + ssl_cert = &ssl_ctx->certs[i]; + ssl_cert->size = len; + ssl_cert->buf = (uint8_t *)malloc(len); + memcpy(ssl_cert->buf, buf, len); + ssl_ctx->chain_length++; + len -= offset; + ret = SSL_OK; /* ok so far */ + + /* recurse? */ + if (len > 0) + { + ret = add_cert(ssl_ctx, &buf[offset], len); + } + +error: + x509_free(cert); /* don't need anymore */ + return ret; +} + +#ifdef CONFIG_SSL_CERT_VERIFICATION +/** + * Add a certificate authority. + */ +int add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len) +{ + int ret = SSL_OK; /* ignore errors for now */ + int i = 0; + CA_CERT_CTX *ca_cert_ctx; + + if (ssl_ctx->ca_cert_ctx == NULL) + ssl_ctx->ca_cert_ctx = (CA_CERT_CTX *)calloc(1, sizeof(CA_CERT_CTX)); + + ca_cert_ctx = ssl_ctx->ca_cert_ctx; + + while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) + i++; + + while (len > 0) + { + int offset; + if (i >= CONFIG_X509_MAX_CA_CERTS) + { +#ifdef CONFIG_SSL_FULL_MODE + printf("Error: maximum number of CA certs added (%d) - change of " + "compile-time configuration required\n", + CONFIG_X509_MAX_CA_CERTS); +#endif + break; + } + + + /* ignore the return code */ + if (x509_new(buf, &offset, &ca_cert_ctx->cert[i]) == X509_OK) + { +#if defined (CONFIG_SSL_FULL_MODE) + if (ssl_ctx->options & SSL_DISPLAY_CERTS) + x509_print(ca_cert_ctx->cert[i], NULL); +#endif + } + + i++; + len -= offset; + } + + return ret; +} + +/* + * Retrieve an X.509 distinguished name component + */ +EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component) +{ + if (ssl->x509_ctx == NULL) + return NULL; + + switch (component) + { + case SSL_X509_CERT_COMMON_NAME: + return ssl->x509_ctx->cert_dn[X509_COMMON_NAME]; + + case SSL_X509_CERT_ORGANIZATION: + return ssl->x509_ctx->cert_dn[X509_ORGANIZATION]; + + case SSL_X509_CERT_ORGANIZATIONAL_NAME: + return ssl->x509_ctx->cert_dn[X509_ORGANIZATIONAL_UNIT]; + + case SSL_X509_CA_CERT_COMMON_NAME: + return ssl->x509_ctx->ca_cert_dn[X509_COMMON_NAME]; + + case SSL_X509_CA_CERT_ORGANIZATION: + return ssl->x509_ctx->ca_cert_dn[X509_ORGANIZATION]; + + case SSL_X509_CA_CERT_ORGANIZATIONAL_NAME: + return ssl->x509_ctx->ca_cert_dn[X509_ORGANIZATIONAL_UNIT]; + + default: + return NULL; + } +} + +/* + * Retrieve a "Subject Alternative Name" from a v3 certificate + */ +EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, + int dnsindex) +{ + int i; + + if (ssl->x509_ctx == NULL || ssl->x509_ctx->subject_alt_dnsnames == NULL) + return NULL; + + for (i = 0; i < dnsindex; ++i) + { + if (ssl->x509_ctx->subject_alt_dnsnames[i] == NULL) + return NULL; + } + + return ssl->x509_ctx->subject_alt_dnsnames[dnsindex]; +} + +#endif /* CONFIG_SSL_CERT_VERIFICATION */ + +/* + * Find an ssl object based on the client's file descriptor. + */ +EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd) +{ + SSL *ssl; + + SSL_CTX_LOCK(ssl_ctx->mutex); + ssl = ssl_ctx->head; + + /* search through all the ssl entries */ + while (ssl) + { + if (ssl->client_fd == client_fd) + { + SSL_CTX_UNLOCK(ssl_ctx->mutex); + return ssl; + } + + ssl = ssl->next; + } + + SSL_CTX_UNLOCK(ssl_ctx->mutex); + return NULL; +} + +/* + * Force the client to perform its handshake again. + */ +EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl) +{ + int ret = SSL_OK; + + disposable_new(ssl); +#ifdef CONFIG_SSL_ENABLE_CLIENT + if (IS_SET_SSL_FLAG(SSL_IS_CLIENT)) + { + ret = do_client_connect(ssl); + } + else +#endif + { + send_packet(ssl, PT_HANDSHAKE_PROTOCOL, + g_hello_request, sizeof(g_hello_request)); + SET_SSL_FLAG(SSL_NEED_RECORD); + } + + return ret; +} + +/** + * @brief Get what we need for key info. + * @param cipher [in] The cipher information we are after + * @param key_size [out] The key size for the cipher + * @param iv_size [out] The iv size for the cipher + * @return The amount of key information we need. + */ +static const cipher_info_t *get_cipher_info(uint8_t cipher) +{ + int i; + + for (i = 0; i < NUM_PROTOCOLS; i++) + { + if (cipher_info[i].cipher == cipher) + { + return &cipher_info[i]; + } + } + + return NULL; /* error */ +} + +/* + * Get a new ssl context for a new connection. + */ +SSL *ssl_new(SSL_CTX *ssl_ctx, int client_fd) +{ + SSL *ssl = (SSL *)calloc(1, sizeof(SSL)); + ssl->ssl_ctx = ssl_ctx; + ssl->need_bytes = SSL_RECORD_SIZE; /* need a record */ + ssl->client_fd = client_fd; + ssl->flag = SSL_NEED_RECORD; + ssl->bm_data = ssl->bm_all_data+BM_RECORD_OFFSET; /* space at the start */ + ssl->hs_status = SSL_NOT_OK; /* not connected */ +#ifdef CONFIG_ENABLE_VERIFICATION + ssl->ca_cert_ctx = ssl_ctx->ca_cert_ctx; +#endif + disposable_new(ssl); + + /* a bit hacky but saves a few bytes of memory */ + ssl->flag |= ssl_ctx->options; + SSL_CTX_LOCK(ssl_ctx->mutex); + + if (ssl_ctx->head == NULL) + { + ssl_ctx->head = ssl; + ssl_ctx->tail = ssl; + } + else + { + ssl->prev = ssl_ctx->tail; + ssl_ctx->tail->next = ssl; + ssl_ctx->tail = ssl; + } + + SSL_CTX_UNLOCK(ssl_ctx->mutex); + return ssl; +} + +/* + * Add a private key to a context. + */ +int add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj) +{ + int ret = SSL_OK; + + /* get the private key details */ + if (asn1_get_private_key(ssl_obj->buf, ssl_obj->len, &ssl_ctx->rsa_ctx)) + { + ret = SSL_ERROR_INVALID_KEY; + goto error; + } + +error: + return ret; +} + +/** + * Increment the read sequence number (as a 64 bit endian indepenent #) + */ +static void increment_read_sequence(SSL *ssl) +{ + int i; + + for (i = 7; i >= 0; i--) + { + if (++ssl->read_sequence[i]) + break; + } +} + +/** + * Increment the read sequence number (as a 64 bit endian indepenent #) + */ +static void increment_write_sequence(SSL *ssl) +{ + int i; + + for (i = 7; i >= 0; i--) + { + if (++ssl->write_sequence[i]) + break; + } +} + +/** + * Work out the HMAC digest in a packet. + */ +static void add_hmac_digest(SSL *ssl, int mode, uint8_t *hmac_header, + const uint8_t *buf, int buf_len, uint8_t *hmac_buf) +{ + int hmac_len = buf_len + 8 + SSL_RECORD_SIZE; + uint8_t *t_buf = (uint8_t *)alloca(hmac_len+10); + + memcpy(t_buf, (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE) ? + ssl->write_sequence : ssl->read_sequence, 8); + memcpy(&t_buf[8], hmac_header, SSL_RECORD_SIZE); + memcpy(&t_buf[8+SSL_RECORD_SIZE], buf, buf_len); + + ssl->cipher_info->hmac(t_buf, hmac_len, + (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ) ? + ssl->server_mac : ssl->client_mac, + ssl->cipher_info->digest_size, hmac_buf); + +#if 0 + print_blob("record", hmac_header, SSL_RECORD_SIZE); + print_blob("buf", buf, buf_len); + if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE) + { + print_blob("write seq", ssl->write_sequence, 8); + } + else + { + print_blob("read seq", ssl->read_sequence, 8); + } + + if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ) + { + print_blob("server mac", + ssl->server_mac, ssl->cipher_info->digest_size); + } + else + { + print_blob("client mac", + ssl->client_mac, ssl->cipher_info->digest_size); + } + print_blob("hmac", hmac_buf, SHA1_SIZE); +#endif +} + +/** + * Verify that the digest of a packet is correct. + */ +static int verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len) +{ + uint8_t hmac_buf[SHA1_SIZE]; + int hmac_offset; + + if (ssl->cipher_info->padding_size) + { + int last_blk_size = buf[read_len-1], i; + hmac_offset = read_len-last_blk_size-ssl->cipher_info->digest_size-1; + + /* guard against a timing attack - make sure we do the digest */ + if (hmac_offset < 0) + { + hmac_offset = 0; + } + else + { + /* already looked at last byte */ + for (i = 1; i < last_blk_size; i++) + { + if (buf[read_len-i] != last_blk_size) + { + hmac_offset = 0; + break; + } + } + } + } + else /* stream cipher */ + { + hmac_offset = read_len - ssl->cipher_info->digest_size; + + if (hmac_offset < 0) + { + hmac_offset = 0; + } + } + + /* sanity check the offset */ + ssl->hmac_header[3] = hmac_offset >> 8; /* insert size */ + ssl->hmac_header[4] = hmac_offset & 0xff; + add_hmac_digest(ssl, mode, ssl->hmac_header, buf, hmac_offset, hmac_buf); + + if (memcmp(hmac_buf, &buf[hmac_offset], ssl->cipher_info->digest_size)) + { + return SSL_ERROR_INVALID_HMAC; + } + + return hmac_offset; +} + +/** + * Add a packet to the end of our sent and received packets, so that we may use + * it to calculate the hash at the end. + */ +void add_packet(SSL *ssl, const uint8_t *pkt, int len) +{ + MD5_Update(&ssl->dc->md5_ctx, pkt, len); + SHA1_Update(&ssl->dc->sha1_ctx, pkt, len); +} + +/** + * Work out the MD5 PRF. + */ +static void p_hash_md5(const uint8_t *sec, int sec_len, + uint8_t *seed, int seed_len, uint8_t *out, int olen) +{ + uint8_t a1[128]; + + /* A(1) */ + hmac_md5(seed, seed_len, sec, sec_len, a1); + memcpy(&a1[MD5_SIZE], seed, seed_len); + hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out); + + while (olen > MD5_SIZE) + { + uint8_t a2[MD5_SIZE]; + out += MD5_SIZE; + olen -= MD5_SIZE; + + /* A(N) */ + hmac_md5(a1, MD5_SIZE, sec, sec_len, a2); + memcpy(a1, a2, MD5_SIZE); + + /* work out the actual hash */ + hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out); + } +} + +/** + * Work out the SHA1 PRF. + */ +static void p_hash_sha1(const uint8_t *sec, int sec_len, + uint8_t *seed, int seed_len, uint8_t *out, int olen) +{ + uint8_t a1[128]; + + /* A(1) */ + hmac_sha1(seed, seed_len, sec, sec_len, a1); + memcpy(&a1[SHA1_SIZE], seed, seed_len); + hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out); + + while (olen > SHA1_SIZE) + { + uint8_t a2[SHA1_SIZE]; + out += SHA1_SIZE; + olen -= SHA1_SIZE; + + /* A(N) */ + hmac_sha1(a1, SHA1_SIZE, sec, sec_len, a2); + memcpy(a1, a2, SHA1_SIZE); + + /* work out the actual hash */ + hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out); + } +} + +/** + * Work out the PRF. + */ +static void prf(const uint8_t *sec, int sec_len, uint8_t *seed, int seed_len, + uint8_t *out, int olen) +{ + int len, i; + const uint8_t *S1, *S2; + uint8_t xbuf[256]; /* needs to be > the amount of key data */ + uint8_t ybuf[256]; /* needs to be > the amount of key data */ + + len = sec_len/2; + S1 = sec; + S2 = &sec[len]; + len += (sec_len & 1); /* add for odd, make longer */ + + p_hash_md5(S1, len, seed, seed_len, xbuf, olen); + p_hash_sha1(S2, len, seed, seed_len, ybuf, olen); + + for (i = 0; i < olen; i++) + out[i] = xbuf[i] ^ ybuf[i]; +} + +/** + * Generate a master secret based on the client/server random data and the + * premaster secret. + */ +void generate_master_secret(SSL *ssl, const uint8_t *premaster_secret) +{ + uint8_t buf[128]; /* needs to be > 13+32+32 in size */ + strcpy((char *)buf, "master secret"); + memcpy(&buf[13], ssl->dc->client_random, SSL_RANDOM_SIZE); + memcpy(&buf[45], ssl->dc->server_random, SSL_RANDOM_SIZE); + prf(premaster_secret, SSL_SECRET_SIZE, buf, 77, ssl->dc->master_secret, + SSL_SECRET_SIZE); +} + +/** + * Generate a 'random' blob of data used for the generation of keys. + */ +static void generate_key_block(uint8_t *client_random, uint8_t *server_random, + uint8_t *master_secret, uint8_t *key_block, int key_block_size) +{ + uint8_t buf[128]; + strcpy((char *)buf, "key expansion"); + memcpy(&buf[13], server_random, SSL_RANDOM_SIZE); + memcpy(&buf[45], client_random, SSL_RANDOM_SIZE); + prf(master_secret, SSL_SECRET_SIZE, buf, 77, key_block, key_block_size); +} + +/** + * Calculate the digest used in the finished message. This function also + * doubles up as a certificate verify function. + */ +void finished_digest(SSL *ssl, const char *label, uint8_t *digest) +{ + uint8_t mac_buf[128]; + uint8_t *q = mac_buf; + MD5_CTX md5_ctx = ssl->dc->md5_ctx; + SHA1_CTX sha1_ctx = ssl->dc->sha1_ctx; + + if (label) + { + strcpy((char *)q, label); + q += strlen(label); + } + + MD5_Final(q, &md5_ctx); + q += MD5_SIZE; + + SHA1_Final(q, &sha1_ctx); + q += SHA1_SIZE; + + if (label) + { + prf(ssl->dc->master_secret, SSL_SECRET_SIZE, mac_buf, (int)(q-mac_buf), + digest, SSL_FINISHED_HASH_SIZE); + } + else /* for use in a certificate verify */ + { + memcpy(digest, mac_buf, MD5_SIZE + SHA1_SIZE); + } + +#if 0 + printf("label: %s\n", label); + print_blob("master secret", ssl->dc->master_secret, 48); + print_blob("mac_buf", mac_buf, q-mac_buf); + print_blob("finished digest", digest, SSL_FINISHED_HASH_SIZE); +#endif +} + +/** + * Retrieve (and initialise) the context of a cipher. + */ +static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt) +{ + switch (ssl->cipher) + { +#ifndef CONFIG_SSL_SKELETON_MODE + case SSL_AES128_SHA: + { + AES_CTX *aes_ctx = (AES_CTX *)malloc(sizeof(AES_CTX)); + AES_set_key(aes_ctx, key, iv, AES_MODE_128); + + if (is_decrypt) + { + AES_convert_key(aes_ctx); + } + + return (void *)aes_ctx; + } + + case SSL_AES256_SHA: + { + AES_CTX *aes_ctx = (AES_CTX *)malloc(sizeof(AES_CTX)); + AES_set_key(aes_ctx, key, iv, AES_MODE_256); + + if (is_decrypt) + { + AES_convert_key(aes_ctx); + } + + return (void *)aes_ctx; + } + + case SSL_RC4_128_MD5: +#endif + case SSL_RC4_128_SHA: + { + RC4_CTX *rc4_ctx = (RC4_CTX *)malloc(sizeof(RC4_CTX)); + RC4_setup(rc4_ctx, key, 16); + return (void *)rc4_ctx; + } + } + + return NULL; /* its all gone wrong */ +} + +/** + * Send a packet over the socket. + */ +static int send_raw_packet(SSL *ssl, uint8_t protocol) +{ + uint8_t *rec_buf = ssl->bm_all_data; + int pkt_size = SSL_RECORD_SIZE+ssl->bm_index; + int sent = 0; + int ret = SSL_OK; + + rec_buf[0] = protocol; + rec_buf[1] = 0x03; /* version = 3.1 or higher */ + rec_buf[2] = ssl->version & 0x0f; + rec_buf[3] = ssl->bm_index >> 8; + rec_buf[4] = ssl->bm_index & 0xff; + + DISPLAY_BYTES(ssl, "sending %d bytes", ssl->bm_all_data, + pkt_size, pkt_size); + + while (sent < pkt_size) + { + ret = SOCKET_WRITE(ssl->client_fd, + &ssl->bm_all_data[sent], pkt_size-sent); + + if (ret >= 0) + sent += ret; + else + { + +#ifdef WIN32 + if (GetLastError() != WSAEWOULDBLOCK) +#else + if (errno != EAGAIN && errno != EWOULDBLOCK) +#endif + return SSL_ERROR_CONN_LOST; + } + + /* keep going until the write buffer has some space */ + if (sent != pkt_size) + { + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(ssl->client_fd, &wfds); + + /* block and wait for it */ + if (select(ssl->client_fd + 1, NULL, &wfds, NULL, NULL) < 0) + return SSL_ERROR_CONN_LOST; + } + } + + SET_SSL_FLAG(SSL_NEED_RECORD); /* reset for next time */ + ssl->bm_index = 0; + + if (protocol != PT_APP_PROTOCOL_DATA) + { + /* always return SSL_OK during handshake */ + ret = SSL_OK; + } + + return ret; +} + +/** + * Send an encrypted packet with padding bytes if necessary. + */ +int send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length) +{ + int ret, msg_length = 0; + + /* if our state is bad, don't bother */ + if (ssl->hs_status == SSL_ERROR_DEAD) + return SSL_ERROR_CONN_LOST; + + if (in) /* has the buffer already been initialised? */ + { + memcpy(ssl->bm_data, in, length); + } + + msg_length += length; + + if (IS_SET_SSL_FLAG(SSL_TX_ENCRYPTED)) + { + int mode = IS_SET_SSL_FLAG(SSL_IS_CLIENT) ? + SSL_CLIENT_WRITE : SSL_SERVER_WRITE; + uint8_t hmac_header[SSL_RECORD_SIZE] = + { + protocol, + 0x03, /* version = 3.1 or higher */ + ssl->version & 0x0f, + msg_length >> 8, + msg_length & 0xff + }; + + if (protocol == PT_HANDSHAKE_PROTOCOL) + { + DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0); + + if (ssl->bm_data[0] != HS_HELLO_REQUEST) + { + add_packet(ssl, ssl->bm_data, msg_length); + } + } + + /* add the packet digest */ + add_hmac_digest(ssl, mode, hmac_header, ssl->bm_data, msg_length, + &ssl->bm_data[msg_length]); + msg_length += ssl->cipher_info->digest_size; + + /* add padding? */ + if (ssl->cipher_info->padding_size) + { + int last_blk_size = msg_length%ssl->cipher_info->padding_size; + int pad_bytes = ssl->cipher_info->padding_size - last_blk_size; + + /* ensure we always have at least 1 padding byte */ + if (pad_bytes == 0) + pad_bytes += ssl->cipher_info->padding_size; + + memset(&ssl->bm_data[msg_length], pad_bytes-1, pad_bytes); + msg_length += pad_bytes; + } + + DISPLAY_BYTES(ssl, "unencrypted write", ssl->bm_data, msg_length); + increment_write_sequence(ssl); + + /* add the explicit IV for TLS1.1 */ + if (ssl->version >= SSL_PROTOCOL_VERSION1_1 && + ssl->cipher_info->iv_size) + { + uint8_t iv_size = ssl->cipher_info->iv_size; + uint8_t *t_buf = alloca(msg_length + iv_size); + memcpy(t_buf + iv_size, ssl->bm_data, msg_length); + get_random(iv_size, t_buf); + msg_length += iv_size; + memcpy(ssl->bm_data, t_buf, msg_length); + } + + /* now encrypt the packet */ + ssl->cipher_info->encrypt(ssl->encrypt_ctx, ssl->bm_data, + ssl->bm_data, msg_length); + } + else if (protocol == PT_HANDSHAKE_PROTOCOL) + { + DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0); + + if (ssl->bm_data[0] != HS_HELLO_REQUEST) + { + add_packet(ssl, ssl->bm_data, length); + } + } + + ssl->bm_index = msg_length; + if ((ret = send_raw_packet(ssl, protocol)) <= 0) + return ret; + + return length; /* just return what we wanted to send */ +} + +/** + * Work out the cipher keys we are going to use for this session based on the + * master secret. + */ +static int set_key_block(SSL *ssl, int is_write) +{ + const cipher_info_t *ciph_info = get_cipher_info(ssl->cipher); + uint8_t *q; + uint8_t client_key[32], server_key[32]; /* big enough for AES256 */ + uint8_t client_iv[16], server_iv[16]; /* big enough for AES128/256 */ + int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); + + if (ciph_info == NULL) + return -1; + + /* only do once in a handshake */ + if (ssl->dc->key_block == NULL) + { + ssl->dc->key_block = (uint8_t *)malloc(ciph_info->key_block_size); + +#if 0 + print_blob("client", ssl->dc->client_random, 32); + print_blob("server", ssl->dc->server_random, 32); + print_blob("master", ssl->dc->master_secret, SSL_SECRET_SIZE); +#endif + generate_key_block(ssl->dc->client_random, ssl->dc->server_random, + ssl->dc->master_secret, ssl->dc->key_block, + ciph_info->key_block_size); +#if 0 + print_blob("keyblock", ssl->dc->key_block, ciph_info->key_block_size); +#endif + } + + q = ssl->dc->key_block; + + if ((is_client && is_write) || (!is_client && !is_write)) + { + memcpy(ssl->client_mac, q, ciph_info->digest_size); + } + + q += ciph_info->digest_size; + + if ((!is_client && is_write) || (is_client && !is_write)) + { + memcpy(ssl->server_mac, q, ciph_info->digest_size); + } + + q += ciph_info->digest_size; + memcpy(client_key, q, ciph_info->key_size); + q += ciph_info->key_size; + memcpy(server_key, q, ciph_info->key_size); + q += ciph_info->key_size; + +#ifndef CONFIG_SSL_SKELETON_MODE + if (ciph_info->iv_size) /* RC4 has no IV, AES does */ + { + memcpy(client_iv, q, ciph_info->iv_size); + q += ciph_info->iv_size; + memcpy(server_iv, q, ciph_info->iv_size); + q += ciph_info->iv_size; + } +#endif + + free(is_write ? ssl->encrypt_ctx : ssl->decrypt_ctx); + + /* now initialise the ciphers */ + if (is_client) + { + finished_digest(ssl, server_finished, ssl->dc->final_finish_mac); + + if (is_write) + ssl->encrypt_ctx = crypt_new(ssl, client_key, client_iv, 0); + else + ssl->decrypt_ctx = crypt_new(ssl, server_key, server_iv, 1); + } + else + { + finished_digest(ssl, client_finished, ssl->dc->final_finish_mac); + + if (is_write) + ssl->encrypt_ctx = crypt_new(ssl, server_key, server_iv, 0); + else + ssl->decrypt_ctx = crypt_new(ssl, client_key, client_iv, 1); + } + + ssl->cipher_info = ciph_info; + return 0; +} + +/** + * Read the SSL connection. + */ +int basic_read(SSL *ssl, uint8_t **in_data) +{ + int ret = SSL_OK; + int read_len, is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); + uint8_t *buf = ssl->bm_data; + + read_len = SOCKET_READ(ssl->client_fd, &buf[ssl->bm_read_index], + ssl->need_bytes-ssl->got_bytes); + + if (read_len < 0) + { +#ifdef WIN32 + if (GetLastError() == WSAEWOULDBLOCK) +#else + if (errno == EAGAIN || errno == EWOULDBLOCK) +#endif + return 0; + } + + /* connection has gone, so die */ + if (read_len <= 0) + { + ret = SSL_ERROR_CONN_LOST; + ssl->hs_status = SSL_ERROR_DEAD; /* make sure it stays dead */ + goto error; + } + + DISPLAY_BYTES(ssl, "received %d bytes", + &ssl->bm_data[ssl->bm_read_index], read_len, read_len); + + ssl->got_bytes += read_len; + ssl->bm_read_index += read_len; + + /* haven't quite got what we want, so try again later */ + if (ssl->got_bytes < ssl->need_bytes) + return SSL_OK; + + read_len = ssl->got_bytes; + ssl->got_bytes = 0; + + if (IS_SET_SSL_FLAG(SSL_NEED_RECORD)) + { + /* check for sslv2 "client hello" */ + if (buf[0] & 0x80 && buf[2] == 1) + { +#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE + uint8_t version = (buf[3] << 4) + buf[4]; + DISPLAY_BYTES(ssl, "ssl2 record", buf, 5); + + /* should be v3.1 (TLSv1) or better */ + ssl->version = ssl->client_version = version; + + if (version > SSL_PROTOCOL_VERSION_MAX) + { + /* use client's version */ + ssl->version = SSL_PROTOCOL_VERSION_MAX; + } + else if (version < SSL_PROTOCOL_MIN_VERSION) + { + ret = SSL_ERROR_INVALID_VERSION; + ssl_display_error(ret); + return ret; + } + + add_packet(ssl, &buf[2], 3); + ret = process_sslv23_client_hello(ssl); +#else + printf("Error: no SSLv23 handshaking allowed\n"); TTY_FLUSH(); + ret = SSL_ERROR_NOT_SUPPORTED; +#endif + goto error; /* not an error - just get out of here */ + } + + ssl->need_bytes = (buf[3] << 8) + buf[4]; + + /* do we violate the spec with the message size? */ + if (ssl->need_bytes > RT_MAX_PLAIN_LENGTH+RT_EXTRA-BM_RECORD_OFFSET) + { + ret = SSL_ERROR_INVALID_PROT_MSG; + goto error; + } + + CLR_SSL_FLAG(SSL_NEED_RECORD); + memcpy(ssl->hmac_header, buf, 3); /* store for hmac */ + ssl->record_type = buf[0]; + goto error; /* no error, we're done */ + } + + /* for next time - just do it now in case of an error */ + SET_SSL_FLAG(SSL_NEED_RECORD); + ssl->need_bytes = SSL_RECORD_SIZE; + + /* decrypt if we need to */ + if (IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED)) + { + ssl->cipher_info->decrypt(ssl->decrypt_ctx, buf, buf, read_len); + + if (ssl->version >= SSL_PROTOCOL_VERSION1_1 && + ssl->cipher_info->iv_size) + { + buf += ssl->cipher_info->iv_size; + read_len -= ssl->cipher_info->iv_size; + } + + read_len = verify_digest(ssl, + is_client ? SSL_CLIENT_READ : SSL_SERVER_READ, buf, read_len); + + /* does the hmac work? */ + if (read_len < 0) + { + ret = read_len; + goto error; + } + + DISPLAY_BYTES(ssl, "decrypted", buf, read_len); + increment_read_sequence(ssl); + } + + /* The main part of the SSL packet */ + switch (ssl->record_type) + { + case PT_HANDSHAKE_PROTOCOL: + if (ssl->dc != NULL) + { + ssl->dc->bm_proc_index = 0; + ret = do_handshake(ssl, buf, read_len); + } + else /* no client renegotiation allowed */ + { + ret = SSL_ERROR_NO_CLIENT_RENOG; + goto error; + } + break; + + case PT_CHANGE_CIPHER_SPEC: + if (ssl->next_state != HS_FINISHED) + { + ret = SSL_ERROR_INVALID_HANDSHAKE; + goto error; + } + + /* all encrypted from now on */ + SET_SSL_FLAG(SSL_RX_ENCRYPTED); + if (set_key_block(ssl, 0) < 0) + { + ret = SSL_ERROR_INVALID_HANDSHAKE; + goto error; + } + + memset(ssl->read_sequence, 0, 8); + break; + + case PT_APP_PROTOCOL_DATA: + if (in_data) + { + *in_data = buf; /* point to the work buffer */ + (*in_data)[read_len] = 0; /* null terminate just in case */ + } + + ret = read_len; + break; + + case PT_ALERT_PROTOCOL: + /* return the alert # with alert bit set */ + if(buf[0] == SSL_ALERT_TYPE_WARNING && + buf[1] == SSL_ALERT_CLOSE_NOTIFY) + { + ret = SSL_CLOSE_NOTIFY; + send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY); + SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY); + } + else + { + ret = -buf[1]; + DISPLAY_ALERT(ssl, buf[1]); + } + + break; + + default: + ret = SSL_ERROR_INVALID_PROT_MSG; + break; + } + +error: + ssl->bm_read_index = 0; /* reset to go again */ + + if (ret < SSL_OK && in_data)/* if all wrong, then clear this buffer ptr */ + *in_data = NULL; + + return ret; +} + +/** + * Do some basic checking of data and then perform the appropriate handshaking. + */ +static int do_handshake(SSL *ssl, uint8_t *buf, int read_len) +{ + int hs_len = (buf[2]<<8) + buf[3]; + uint8_t handshake_type = buf[0]; + int ret = SSL_OK; + int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); + + /* some integrity checking on the handshake */ + PARANOIA_CHECK(read_len-SSL_HS_HDR_SIZE, hs_len); + + if (handshake_type != ssl->next_state) + { + /* handle a special case on the client */ + if (!is_client || handshake_type != HS_CERT_REQ || + ssl->next_state != HS_SERVER_HELLO_DONE) + { + ret = SSL_ERROR_INVALID_HANDSHAKE; + goto error; + } + } + + hs_len += SSL_HS_HDR_SIZE; /* adjust for when adding packets */ + ssl->bm_index = hs_len; /* store the size and check later */ + DISPLAY_STATE(ssl, 0, handshake_type, 0); + + if (handshake_type != HS_CERT_VERIFY && handshake_type != HS_HELLO_REQUEST) + add_packet(ssl, buf, hs_len); + +#if defined(CONFIG_SSL_ENABLE_CLIENT) + ret = is_client ? + do_clnt_handshake(ssl, handshake_type, buf, hs_len) : + do_svr_handshake(ssl, handshake_type, buf, hs_len); +#else + ret = do_svr_handshake(ssl, handshake_type, buf, hs_len); +#endif + + /* just use recursion to get the rest */ + if (hs_len < read_len && ret == SSL_OK) + ret = do_handshake(ssl, &buf[hs_len], read_len-hs_len); + +error: + return ret; +} + +/** + * Sends the change cipher spec message. We have just read a finished message + * from the client. + */ +int send_change_cipher_spec(SSL *ssl) +{ + int ret = send_packet(ssl, PT_CHANGE_CIPHER_SPEC, + g_chg_cipher_spec_pkt, sizeof(g_chg_cipher_spec_pkt)); + SET_SSL_FLAG(SSL_TX_ENCRYPTED); + + if (ret >= 0 && set_key_block(ssl, 1) < 0) + ret = SSL_ERROR_INVALID_HANDSHAKE; + + memset(ssl->write_sequence, 0, 8); + return ret; +} + +/** + * Send a "finished" message + */ +int send_finished(SSL *ssl) +{ + uint8_t buf[SSL_FINISHED_HASH_SIZE+4] = { + HS_FINISHED, 0, 0, SSL_FINISHED_HASH_SIZE }; + + /* now add the finished digest mac (12 bytes) */ + finished_digest(ssl, + IS_SET_SSL_FLAG(SSL_IS_CLIENT) ? + client_finished : server_finished, &buf[4]); + +#ifndef CONFIG_SSL_SKELETON_MODE + /* store in the session cache */ + if (!IS_SET_SSL_FLAG(SSL_SESSION_RESUME) && ssl->ssl_ctx->num_sessions) + { + memcpy(ssl->session->master_secret, + ssl->dc->master_secret, SSL_SECRET_SIZE); + } +#endif + + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, + buf, SSL_FINISHED_HASH_SIZE+4); +} + +/** + * Send an alert message. + * Return 1 if the alert was an "error". + */ +int send_alert(SSL *ssl, int error_code) +{ + int alert_num = 0; + int is_warning = 0; + uint8_t buf[2]; + + /* Don't bother we're already dead */ + if (ssl->hs_status == SSL_ERROR_DEAD) + { + return SSL_ERROR_CONN_LOST; + } + +#ifdef CONFIG_SSL_FULL_MODE + if (IS_SET_SSL_FLAG(SSL_DISPLAY_STATES)) + ssl_display_error(error_code); +#endif + + switch (error_code) + { + case SSL_ALERT_CLOSE_NOTIFY: + is_warning = 1; + alert_num = SSL_ALERT_CLOSE_NOTIFY; + break; + + case SSL_ERROR_CONN_LOST: /* don't send alert just yet */ + is_warning = 1; + break; + + case SSL_ERROR_INVALID_HANDSHAKE: + case SSL_ERROR_INVALID_PROT_MSG: + alert_num = SSL_ALERT_HANDSHAKE_FAILURE; + break; + + case SSL_ERROR_INVALID_HMAC: + case SSL_ERROR_FINISHED_INVALID: + alert_num = SSL_ALERT_BAD_RECORD_MAC; + break; + + case SSL_ERROR_INVALID_VERSION: + alert_num = SSL_ALERT_INVALID_VERSION; + break; + + case SSL_ERROR_INVALID_SESSION: + case SSL_ERROR_NO_CIPHER: + case SSL_ERROR_INVALID_KEY: + alert_num = SSL_ALERT_ILLEGAL_PARAMETER; + break; + + case SSL_ERROR_BAD_CERTIFICATE: + alert_num = SSL_ALERT_BAD_CERTIFICATE; + break; + + case SSL_ERROR_NO_CLIENT_RENOG: + alert_num = SSL_ALERT_NO_RENEGOTIATION; + break; + + default: + /* a catch-all for any badly verified certificates */ + alert_num = (error_code <= SSL_X509_OFFSET) ? + SSL_ALERT_BAD_CERTIFICATE : SSL_ALERT_UNEXPECTED_MESSAGE; + break; + } + + buf[0] = is_warning ? 1 : 2; + buf[1] = alert_num; + send_packet(ssl, PT_ALERT_PROTOCOL, buf, sizeof(buf)); + DISPLAY_ALERT(ssl, alert_num); + return is_warning ? 0 : 1; +} + +/** + * Process a client finished message. + */ +int process_finished(SSL *ssl, uint8_t *buf, int hs_len) +{ + int ret = SSL_OK; + int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); + int resume = IS_SET_SSL_FLAG(SSL_SESSION_RESUME); + + PARANOIA_CHECK(ssl->bm_index, SSL_FINISHED_HASH_SIZE+4); + + /* check that we all work before we continue */ + if (memcmp(ssl->dc->final_finish_mac, &buf[4], SSL_FINISHED_HASH_SIZE)) + return SSL_ERROR_FINISHED_INVALID; + + if ((!is_client && !resume) || (is_client && resume)) + { + if ((ret = send_change_cipher_spec(ssl)) == SSL_OK) + ret = send_finished(ssl); + } + + /* if we ever renegotiate */ + ssl->next_state = is_client ? HS_HELLO_REQUEST : HS_CLIENT_HELLO; + ssl->hs_status = ret; /* set the final handshake status */ + +error: + return ret; +} + +/** + * Send a certificate. + */ +int send_certificate(SSL *ssl) +{ + int i = 0; + uint8_t *buf = ssl->bm_data; + int offset = 7; + int chain_length; + + buf[0] = HS_CERTIFICATE; + buf[1] = 0; + buf[4] = 0; + + while (i < ssl->ssl_ctx->chain_length) + { + SSL_CERT *cert = &ssl->ssl_ctx->certs[i]; + buf[offset++] = 0; + buf[offset++] = cert->size >> 8; /* cert 1 length */ + buf[offset++] = cert->size & 0xff; + memcpy(&buf[offset], cert->buf, cert->size); + offset += cert->size; + i++; + } + + chain_length = offset - 7; + buf[5] = chain_length >> 8; /* cert chain length */ + buf[6] = chain_length & 0xff; + chain_length += 3; + buf[2] = chain_length >> 8; /* handshake length */ + buf[3] = chain_length & 0xff; + ssl->bm_index = offset; + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset); +} + +/** + * Create a blob of memory that we'll get rid of once the handshake is + * complete. + */ +void disposable_new(SSL *ssl) +{ + if (ssl->dc == NULL) + { + ssl->dc = (DISPOSABLE_CTX *)calloc(1, sizeof(DISPOSABLE_CTX)); + MD5_Init(&ssl->dc->md5_ctx); + SHA1_Init(&ssl->dc->sha1_ctx); + } +} + +/** + * Remove the temporary blob of memory. + */ +void disposable_free(SSL *ssl) +{ + if (ssl->dc) + { + free(ssl->dc->key_block); + memset(ssl->dc, 0, sizeof(DISPOSABLE_CTX)); + free(ssl->dc); + ssl->dc = NULL; + } + +} + +#ifndef CONFIG_SSL_SKELETON_MODE /* no session resumption in this mode */ +/** + * Find if an existing session has the same session id. If so, use the + * master secret from this session for session resumption. + */ +SSL_SESSION *ssl_session_update(int max_sessions, SSL_SESSION *ssl_sessions[], + SSL *ssl, const uint8_t *session_id) +{ + time_t tm = time(NULL); + time_t oldest_sess_time = tm; + SSL_SESSION *oldest_sess = NULL; + int i; + + /* no sessions? Then bail */ + if (max_sessions == 0) + return NULL; + + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + if (session_id) + { + for (i = 0; i < max_sessions; i++) + { + if (ssl_sessions[i]) + { + /* kill off any expired sessions (including those in + the future) */ + if ((tm > ssl_sessions[i]->conn_time + SSL_EXPIRY_TIME) || + (tm < ssl_sessions[i]->conn_time)) + { + session_free(ssl_sessions, i); + continue; + } + + /* if the session id matches, it must still be less than + the expiry time */ + if (memcmp(ssl_sessions[i]->session_id, session_id, + SSL_SESSION_ID_SIZE) == 0) + { + ssl->session_index = i; + memcpy(ssl->dc->master_secret, + ssl_sessions[i]->master_secret, SSL_SECRET_SIZE); + SET_SSL_FLAG(SSL_SESSION_RESUME); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + return ssl_sessions[i]; /* a session was found */ + } + } + } + } + + /* If we've got here, no matching session was found - so create one */ + for (i = 0; i < max_sessions; i++) + { + if (ssl_sessions[i] == NULL) + { + /* perfect, this will do */ + ssl_sessions[i] = (SSL_SESSION *)calloc(1, sizeof(SSL_SESSION)); + ssl_sessions[i]->conn_time = tm; + ssl->session_index = i; + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + return ssl_sessions[i]; /* return the session object */ + } + else if (ssl_sessions[i]->conn_time <= oldest_sess_time) + { + /* find the oldest session */ + oldest_sess_time = ssl_sessions[i]->conn_time; + oldest_sess = ssl_sessions[i]; + ssl->session_index = i; + } + } + + /* ok, we've used up all of our sessions. So blow the oldest session away */ + oldest_sess->conn_time = tm; + memset(oldest_sess->session_id, 0, sizeof(SSL_SESSION_ID_SIZE)); + memset(oldest_sess->master_secret, 0, sizeof(SSL_SECRET_SIZE)); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + return oldest_sess; +} + +/** + * Free an existing session. + */ +static void session_free(SSL_SESSION *ssl_sessions[], int sess_index) +{ + if (ssl_sessions[sess_index]) + { + free(ssl_sessions[sess_index]); + ssl_sessions[sess_index] = NULL; + } +} + +/** + * This ssl object doesn't want this session anymore. + */ +void kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl) +{ + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + + if (ssl->ssl_ctx->num_sessions) + { + session_free(ssl_sessions, ssl->session_index); + ssl->session = NULL; + } + + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); +} +#endif /* CONFIG_SSL_SKELETON_MODE */ + +/* + * Get the session id for a handshake. This will be a 32 byte sequence. + */ +EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl) +{ + return ssl->session_id; +} + +/* + * Get the session id size for a handshake. + */ +EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl) +{ + return ssl->sess_id_size; +} + +/* + * Return the cipher id (in the SSL form). + */ +EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl) +{ + return ssl->cipher; +} + +/* + * Return the status of the handshake. + */ +EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl) +{ + return ssl->hs_status; +} + +/* + * Retrieve various parameters about the SSL engine. + */ +EXP_FUNC int STDCALL ssl_get_config(int offset) +{ + switch (offset) + { + /* return the appropriate build mode */ + case SSL_BUILD_MODE: +#if defined(CONFIG_SSL_FULL_MODE) + return SSL_BUILD_FULL_MODE; +#elif defined(CONFIG_SSL_ENABLE_CLIENT) + return SSL_BUILD_ENABLE_CLIENT; +#elif defined(CONFIG_ENABLE_VERIFICATION) + return SSL_BUILD_ENABLE_VERIFICATION; +#elif defined(CONFIG_SSL_SERVER_ONLY ) + return SSL_BUILD_SERVER_ONLY; +#else + return SSL_BUILD_SKELETON_MODE; +#endif + + case SSL_MAX_CERT_CFG_OFFSET: + return CONFIG_SSL_MAX_CERTS; + +#ifdef CONFIG_SSL_CERT_VERIFICATION + case SSL_MAX_CA_CERT_CFG_OFFSET: + return CONFIG_X509_MAX_CA_CERTS; +#endif +#ifdef CONFIG_SSL_HAS_PEM + case SSL_HAS_PEM: + return 1; +#endif + default: + return 0; + } +} + +#ifdef CONFIG_SSL_CERT_VERIFICATION +/** + * Authenticate a received certificate. + */ +EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl) +{ + int ret; + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + ret = x509_verify(ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + + if (ret) /* modify into an SSL error type */ + { + ret = SSL_X509_ERROR(ret); + } + + return ret; +} + +/** + * Process a certificate message. + */ +int process_certificate(SSL *ssl, X509_CTX **x509_ctx) +{ + int ret = SSL_OK; + uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index]; + int pkt_size = ssl->bm_index; + int cert_size, offset = 5; + int total_cert_size = (buf[offset]<<8) + buf[offset+1]; + int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); + X509_CTX **chain = x509_ctx; + offset += 2; + + PARANOIA_CHECK(total_cert_size, offset); + + while (offset < total_cert_size) + { + offset++; /* skip empty char */ + cert_size = (buf[offset]<<8) + buf[offset+1]; + offset += 2; + + if (x509_new(&buf[offset], NULL, chain)) + { + ret = SSL_ERROR_BAD_CERTIFICATE; + goto error; + } + + chain = &((*chain)->next); + offset += cert_size; + } + + PARANOIA_CHECK(pkt_size, offset); + + /* if we are client we can do the verify now or later */ + if (is_client && !IS_SET_SSL_FLAG(SSL_SERVER_VERIFY_LATER)) + { + ret = ssl_verify_cert(ssl); + } + + ssl->next_state = is_client ? HS_SERVER_HELLO_DONE : HS_CLIENT_KEY_XCHG; + ssl->dc->bm_proc_index += offset; +error: + return ret; +} + +#endif /* CONFIG_SSL_CERT_VERIFICATION */ + +/** + * Debugging routine to display SSL handshaking stuff. + */ +#ifdef CONFIG_SSL_FULL_MODE +/** + * Debugging routine to display SSL states. + */ +void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok) +{ + const char *str; + + if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES)) + return; + + printf(not_ok ? "Error - invalid State:\t" : "State:\t"); + printf(is_send ? "sending " : "receiving "); + + switch (state) + { + case HS_HELLO_REQUEST: + str = "Hello Request (0)"; + break; + + case HS_CLIENT_HELLO: + str = "Client Hello (1)"; + break; + + case HS_SERVER_HELLO: + str = "Server Hello (2)"; + break; + + case HS_CERTIFICATE: + str = "Certificate (11)"; + break; + + case HS_SERVER_KEY_XCHG: + str = "Certificate Request (12)"; + break; + + case HS_CERT_REQ: + str = "Certificate Request (13)"; + break; + + case HS_SERVER_HELLO_DONE: + str = "Server Hello Done (14)"; + break; + + case HS_CERT_VERIFY: + str = "Certificate Verify (15)"; + break; + + case HS_CLIENT_KEY_XCHG: + str = "Client Key Exchange (16)"; + break; + + case HS_FINISHED: + str = "Finished (16)"; + break; + + default: + str = "Error (Unknown)"; + + break; + } + + printf("%s\n", str); + TTY_FLUSH(); +} + +/** + * Debugging routine to display RSA objects + */ +void DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx) +{ + if (!IS_SET_SSL_FLAG(SSL_DISPLAY_RSA)) + return; + + RSA_print(rsa_ctx); + TTY_FLUSH(); +} + +/** + * Debugging routine to display SSL handshaking bytes. + */ +void DISPLAY_BYTES(SSL *ssl, const char *format, + const uint8_t *data, int size, ...) +{ + va_list(ap); + + if (!IS_SET_SSL_FLAG(SSL_DISPLAY_BYTES)) + return; + + va_start(ap, size); + print_blob(format, data, size, va_arg(ap, char *)); + va_end(ap); + TTY_FLUSH(); +} + +/** + * Debugging routine to display SSL handshaking errors. + */ +EXP_FUNC void STDCALL ssl_display_error(int error_code) +{ + if (error_code == SSL_OK) + return; + + printf("Error: "); + + /* X509 error? */ + if (error_code < SSL_X509_OFFSET) + { + printf("%s\n", x509_display_error(error_code - SSL_X509_OFFSET)); + return; + } + + /* SSL alert error code */ + if (error_code > SSL_ERROR_CONN_LOST) + { + printf("SSL error %d\n", -error_code); + return; + } + + switch (error_code) + { + case SSL_ERROR_DEAD: + printf("connection dead"); + break; + + case SSL_ERROR_INVALID_HANDSHAKE: + printf("invalid handshake"); + break; + + case SSL_ERROR_INVALID_PROT_MSG: + printf("invalid protocol message"); + break; + + case SSL_ERROR_INVALID_HMAC: + printf("invalid mac"); + break; + + case SSL_ERROR_INVALID_VERSION: + printf("invalid version"); + break; + + case SSL_ERROR_INVALID_SESSION: + printf("invalid session"); + break; + + case SSL_ERROR_NO_CIPHER: + printf("no cipher"); + break; + + case SSL_ERROR_CONN_LOST: + printf("connection lost"); + break; + + case SSL_ERROR_BAD_CERTIFICATE: + printf("bad certificate"); + break; + + case SSL_ERROR_INVALID_KEY: + printf("invalid key"); + break; + + case SSL_ERROR_FINISHED_INVALID: + printf("finished invalid"); + break; + + case SSL_ERROR_NO_CERT_DEFINED: + printf("no certificate defined"); + break; + + case SSL_ERROR_NO_CLIENT_RENOG: + printf("client renegotiation not supported"); + break; + + case SSL_ERROR_NOT_SUPPORTED: + printf("Option not supported"); + break; + + default: + printf("undefined as yet - %d", error_code); + break; + } + + printf("\n"); + TTY_FLUSH(); +} + +/** + * Debugging routine to display alerts. + */ +void DISPLAY_ALERT(SSL *ssl, int alert) +{ + if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES)) + return; + + printf("Alert: "); + + switch (alert) + { + case SSL_ALERT_CLOSE_NOTIFY: + printf("close notify"); + break; + + case SSL_ALERT_INVALID_VERSION: + printf("invalid version"); + break; + + case SSL_ALERT_BAD_CERTIFICATE: + printf("bad certificate"); + break; + + case SSL_ALERT_UNEXPECTED_MESSAGE: + printf("unexpected message"); + break; + + case SSL_ALERT_BAD_RECORD_MAC: + printf("bad record mac"); + break; + + case SSL_ALERT_HANDSHAKE_FAILURE: + printf("handshake failure"); + break; + + case SSL_ALERT_ILLEGAL_PARAMETER: + printf("illegal parameter"); + break; + + case SSL_ALERT_DECODE_ERROR: + printf("decode error"); + break; + + case SSL_ALERT_DECRYPT_ERROR: + printf("decrypt error"); + break; + + case SSL_ALERT_NO_RENEGOTIATION: + printf("no renegotiation"); + break; + + default: + printf("alert - (unknown %d)", alert); + break; + } + + printf("\n"); + TTY_FLUSH(); +} + +#endif /* CONFIG_SSL_FULL_MODE */ + +/** + * Return the version of this library. + */ +EXP_FUNC const char * STDCALL ssl_version() +{ + static const char * axtls_version = AXTLS_VERSION; + return axtls_version; +} + +/** + * Enable the various language bindings to work regardless of the + * configuration - they just return an error statement and a bad return code. + */ +#if !defined(CONFIG_SSL_FULL_MODE) +EXP_FUNC void STDCALL ssl_display_error(int error_code) {} +#endif + +#ifdef CONFIG_BINDINGS +#if !defined(CONFIG_SSL_ENABLE_CLIENT) +EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const + uint8_t *session_id, uint8_t sess_id_size) +{ + printf(unsupported_str); + return NULL; +} +#endif + +#if !defined(CONFIG_SSL_CERT_VERIFICATION) +EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl) +{ + printf(unsupported_str); + return -1; +} + + +EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component) +{ + printf(unsupported_str); + return NULL; +} + +EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int index) +{ + printf(unsupported_str); + return NULL; +} + +#endif /* CONFIG_SSL_CERT_VERIFICATION */ + +#endif /* CONFIG_BINDINGS */ + diff --git a/ssl/tls1.h b/ssl/tls1.h new file mode 100644 index 000000000..414a17343 --- /dev/null +++ b/ssl/tls1.h @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file tls1.h + * + * @brief The definitions for the TLS library. + */ +#ifndef HEADER_SSL_LIB_H +#define HEADER_SSL_LIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "version.h" +#include "config.h" +#include "os_int.h" +#include "crypto.h" +#include "crypto_misc.h" + +#define SSL_PROTOCOL_MIN_VERSION 0x31 /* TLS v1.0 */ +#define SSL_PROTOCOL_MINOR_VERSION 0x02 /* TLS v1.1 */ +#define SSL_PROTOCOL_VERSION_MAX 0x32 /* TLS v1.1 */ +#define SSL_PROTOCOL_VERSION1_1 0x32 /* TLS v1.1 */ +#define SSL_RANDOM_SIZE 32 +#define SSL_SECRET_SIZE 48 +#define SSL_FINISHED_HASH_SIZE 12 +#define SSL_RECORD_SIZE 5 +#define SSL_SERVER_READ 0 +#define SSL_SERVER_WRITE 1 +#define SSL_CLIENT_READ 2 +#define SSL_CLIENT_WRITE 3 +#define SSL_HS_HDR_SIZE 4 + +/* the flags we use while establishing a connection */ +#define SSL_NEED_RECORD 0x0001 +#define SSL_TX_ENCRYPTED 0x0002 +#define SSL_RX_ENCRYPTED 0x0004 +#define SSL_SESSION_RESUME 0x0008 +#define SSL_IS_CLIENT 0x0010 +#define SSL_HAS_CERT_REQ 0x0020 +#define SSL_SENT_CLOSE_NOTIFY 0x0040 + +/* some macros to muck around with flag bits */ +#define SET_SSL_FLAG(A) (ssl->flag |= A) +#define CLR_SSL_FLAG(A) (ssl->flag &= ~A) +#define IS_SET_SSL_FLAG(A) (ssl->flag & A) + +#define MAX_KEY_BYTE_SIZE 512 /* for a 4096 bit key */ +#define RT_MAX_PLAIN_LENGTH 16384 +#define RT_EXTRA 1024 +#define BM_RECORD_OFFSET 5 + +#ifdef CONFIG_SSL_SKELETON_MODE +#define NUM_PROTOCOLS 1 +#else +#define NUM_PROTOCOLS 4 +#endif + +#define PARANOIA_CHECK(A, B) if (A < B) { \ + ret = SSL_ERROR_INVALID_HANDSHAKE; goto error; } + +/* protocol types */ +enum +{ + PT_CHANGE_CIPHER_SPEC = 20, + PT_ALERT_PROTOCOL, + PT_HANDSHAKE_PROTOCOL, + PT_APP_PROTOCOL_DATA +}; + +/* handshaking types */ +enum +{ + HS_HELLO_REQUEST, + HS_CLIENT_HELLO, + HS_SERVER_HELLO, + HS_CERTIFICATE = 11, + HS_SERVER_KEY_XCHG, + HS_CERT_REQ, + HS_SERVER_HELLO_DONE, + HS_CERT_VERIFY, + HS_CLIENT_KEY_XCHG, + HS_FINISHED = 20 +}; + +typedef struct +{ + uint8_t cipher; + uint8_t key_size; + uint8_t iv_size; + uint8_t key_block_size; + uint8_t padding_size; + uint8_t digest_size; + hmac_func hmac; + crypt_func encrypt; + crypt_func decrypt; +} cipher_info_t; + +struct _SSLObjLoader +{ + uint8_t *buf; + int len; +}; + +typedef struct _SSLObjLoader SSLObjLoader; + +typedef struct +{ + time_t conn_time; + uint8_t session_id[SSL_SESSION_ID_SIZE]; + uint8_t master_secret[SSL_SECRET_SIZE]; +} SSL_SESSION; + +typedef struct +{ + uint8_t *buf; + int size; +} SSL_CERT; + +typedef struct +{ + MD5_CTX md5_ctx; + SHA1_CTX sha1_ctx; + uint8_t final_finish_mac[SSL_FINISHED_HASH_SIZE]; + uint8_t *key_block; + uint8_t master_secret[SSL_SECRET_SIZE]; + uint8_t client_random[SSL_RANDOM_SIZE]; /* client's random sequence */ + uint8_t server_random[SSL_RANDOM_SIZE]; /* server's random sequence */ + uint16_t bm_proc_index; +} DISPOSABLE_CTX; + +struct _SSL +{ + uint32_t flag; + uint16_t need_bytes; + uint16_t got_bytes; + uint8_t record_type; + uint8_t cipher; + uint8_t sess_id_size; + uint8_t version; + uint8_t client_version; + int16_t next_state; + int16_t hs_status; + DISPOSABLE_CTX *dc; /* temporary data which we'll get rid of soon */ + int client_fd; + const cipher_info_t *cipher_info; + void *encrypt_ctx; + void *decrypt_ctx; + uint8_t bm_all_data[RT_MAX_PLAIN_LENGTH+RT_EXTRA]; + uint8_t *bm_data; + uint16_t bm_index; + uint16_t bm_read_index; + struct _SSL *next; /* doubly linked list */ + struct _SSL *prev; + struct _SSL_CTX *ssl_ctx; /* back reference to a clnt/svr ctx */ +#ifndef CONFIG_SSL_SKELETON_MODE + uint16_t session_index; + SSL_SESSION *session; +#endif +#ifdef CONFIG_SSL_CERT_VERIFICATION + X509_CTX *x509_ctx; +#endif + + uint8_t session_id[SSL_SESSION_ID_SIZE]; + uint8_t client_mac[SHA1_SIZE]; /* for HMAC verification */ + uint8_t server_mac[SHA1_SIZE]; /* for HMAC verification */ + uint8_t read_sequence[8]; /* 64 bit sequence number */ + uint8_t write_sequence[8]; /* 64 bit sequence number */ + uint8_t hmac_header[SSL_RECORD_SIZE]; /* rx hmac */ +}; + +typedef struct _SSL SSL; + +struct _SSL_CTX +{ + uint32_t options; + uint8_t chain_length; + RSA_CTX *rsa_ctx; +#ifdef CONFIG_SSL_CERT_VERIFICATION + CA_CERT_CTX *ca_cert_ctx; +#endif + SSL *head; + SSL *tail; + SSL_CERT certs[CONFIG_SSL_MAX_CERTS]; +#ifndef CONFIG_SSL_SKELETON_MODE + uint16_t num_sessions; + SSL_SESSION **ssl_sessions; +#endif +#ifdef CONFIG_SSL_CTX_MUTEXING + SSL_CTX_MUTEX_TYPE mutex; +#endif +#ifdef CONFIG_OPENSSL_COMPATIBLE + void *bonus_attr; +#endif +}; + +typedef struct _SSL_CTX SSL_CTX; + +/* backwards compatibility */ +typedef struct _SSL_CTX SSLCTX; + +extern const uint8_t ssl_prot_prefs[NUM_PROTOCOLS]; + +SSL *ssl_new(SSL_CTX *ssl_ctx, int client_fd); +void disposable_new(SSL *ssl); +void disposable_free(SSL *ssl); +int send_packet(SSL *ssl, uint8_t protocol, + const uint8_t *in, int length); +int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len); +int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len); +int process_finished(SSL *ssl, uint8_t *buf, int hs_len); +int process_sslv23_client_hello(SSL *ssl); +int send_alert(SSL *ssl, int error_code); +int send_finished(SSL *ssl); +int send_certificate(SSL *ssl); +int basic_read(SSL *ssl, uint8_t **in_data); +int send_change_cipher_spec(SSL *ssl); +void finished_digest(SSL *ssl, const char *label, uint8_t *digest); +void generate_master_secret(SSL *ssl, const uint8_t *premaster_secret); +void add_packet(SSL *ssl, const uint8_t *pkt, int len); +int add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len); +int add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj); +void ssl_obj_free(SSLObjLoader *ssl_obj); +int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password); +int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password); +int load_key_certs(SSL_CTX *ssl_ctx); +#ifdef CONFIG_SSL_CERT_VERIFICATION +int add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len); +void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx); +#endif +#ifdef CONFIG_SSL_ENABLE_CLIENT +int do_client_connect(SSL *ssl); +#endif + +#ifdef CONFIG_SSL_FULL_MODE +void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok); +void DISPLAY_BYTES(SSL *ssl, const char *format, + const uint8_t *data, int size, ...); +void DISPLAY_CERT(SSL *ssl, const X509_CTX *x509_ctx); +void DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx); +void DISPLAY_ALERT(SSL *ssl, int alert); +#else +#define DISPLAY_STATE(A,B,C,D) +#define DISPLAY_CERT(A,B) +#define DISPLAY_RSA(A,B) +#define DISPLAY_ALERT(A, B) +#ifdef WIN32 +void DISPLAY_BYTES(SSL *ssl, const char *format,/* win32 has no variadic macros */ + const uint8_t *data, int size, ...); +#else +#define DISPLAY_BYTES(A,B,C,D,...) +#endif +#endif + +#ifdef CONFIG_SSL_CERT_VERIFICATION +int process_certificate(SSL *ssl, X509_CTX **x509_ctx); +#endif + +SSL_SESSION *ssl_session_update(int max_sessions, + SSL_SESSION *ssl_sessions[], SSL *ssl, + const uint8_t *session_id); +void kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ssl/tls1_clnt.c b/ssl/tls1_clnt.c new file mode 100644 index 000000000..196b40ed3 --- /dev/null +++ b/ssl/tls1_clnt.c @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include "os_port.h" +#include "ssl.h" + +#ifdef CONFIG_SSL_ENABLE_CLIENT /* all commented out if no client */ + +static int send_client_hello(SSL *ssl); +static int process_server_hello(SSL *ssl); +static int process_server_hello_done(SSL *ssl); +static int send_client_key_xchg(SSL *ssl); +static int process_cert_req(SSL *ssl); +static int send_cert_verify(SSL *ssl); + +/* + * Establish a new SSL connection to an SSL server. + */ +EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const + uint8_t *session_id, uint8_t sess_id_size) +{ + SSL *ssl = ssl_new(ssl_ctx, client_fd); + ssl->version = SSL_PROTOCOL_VERSION_MAX; /* try top version first */ + + if (session_id && ssl_ctx->num_sessions) + { + if (sess_id_size > SSL_SESSION_ID_SIZE) /* validity check */ + { + ssl_free(ssl); + return NULL; + } + + memcpy(ssl->session_id, session_id, sess_id_size); + ssl->sess_id_size = sess_id_size; + SET_SSL_FLAG(SSL_SESSION_RESUME); /* just flag for later */ + } + + SET_SSL_FLAG(SSL_IS_CLIENT); + do_client_connect(ssl); + return ssl; +} + +/* + * Process the handshake record. + */ +int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len) +{ + int ret; + + /* To get here the state must be valid */ + switch (handshake_type) + { + case HS_SERVER_HELLO: + ret = process_server_hello(ssl); + break; + + case HS_CERTIFICATE: + ret = process_certificate(ssl, &ssl->x509_ctx); + break; + + case HS_SERVER_HELLO_DONE: + if ((ret = process_server_hello_done(ssl)) == SSL_OK) + { + if (IS_SET_SSL_FLAG(SSL_HAS_CERT_REQ)) + { + if ((ret = send_certificate(ssl)) == SSL_OK && + (ret = send_client_key_xchg(ssl)) == SSL_OK) + { + send_cert_verify(ssl); + } + } + else + { + ret = send_client_key_xchg(ssl); + } + + if (ret == SSL_OK && + (ret = send_change_cipher_spec(ssl)) == SSL_OK) + { + ret = send_finished(ssl); + } + } + break; + + case HS_CERT_REQ: + ret = process_cert_req(ssl); + break; + + case HS_FINISHED: + ret = process_finished(ssl, buf, hs_len); + disposable_free(ssl); /* free up some memory */ + /* note: client renegotiation is not allowed after this */ + break; + + case HS_HELLO_REQUEST: + disposable_new(ssl); + ret = do_client_connect(ssl); + break; + + default: + ret = SSL_ERROR_INVALID_HANDSHAKE; + break; + } + + return ret; +} + +/* + * Do the handshaking from the beginning. + */ +int do_client_connect(SSL *ssl) +{ + int ret = SSL_OK; + + send_client_hello(ssl); /* send the client hello */ + ssl->bm_read_index = 0; + ssl->next_state = HS_SERVER_HELLO; + ssl->hs_status = SSL_NOT_OK; /* not connected */ + + /* sit in a loop until it all looks good */ + if (!IS_SET_SSL_FLAG(SSL_CONNECT_IN_PARTS)) + { + while (ssl->hs_status != SSL_OK) + { + ret = ssl_read(ssl, NULL); + + if (ret < SSL_OK) + break; + } + + ssl->hs_status = ret; /* connected? */ + } + + return ret; +} + +/* + * Send the initial client hello. + */ +static int send_client_hello(SSL *ssl) +{ + uint8_t *buf = ssl->bm_data; + time_t tm = time(NULL); + uint8_t *tm_ptr = &buf[6]; /* time will go here */ + int i, offset; + + buf[0] = HS_CLIENT_HELLO; + buf[1] = 0; + buf[2] = 0; + /* byte 3 is calculated later */ + buf[4] = 0x03; + buf[5] = ssl->version & 0x0f; + + /* client random value - spec says that 1st 4 bytes are big endian time */ + *tm_ptr++ = (uint8_t)(((long)tm & 0xff000000) >> 24); + *tm_ptr++ = (uint8_t)(((long)tm & 0x00ff0000) >> 16); + *tm_ptr++ = (uint8_t)(((long)tm & 0x0000ff00) >> 8); + *tm_ptr++ = (uint8_t)(((long)tm & 0x000000ff)); + get_random(SSL_RANDOM_SIZE-4, &buf[10]); + memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE); + offset = 6 + SSL_RANDOM_SIZE; + + /* give session resumption a go */ + if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) /* set initially by user */ + { + buf[offset++] = ssl->sess_id_size; + memcpy(&buf[offset], ssl->session_id, ssl->sess_id_size); + offset += ssl->sess_id_size; + CLR_SSL_FLAG(SSL_SESSION_RESUME); /* clear so we can set later */ + } + else + { + /* no session id - because no session resumption just yet */ + buf[offset++] = 0; + } + + buf[offset++] = 0; /* number of ciphers */ + buf[offset++] = NUM_PROTOCOLS*2;/* number of ciphers */ + + /* put all our supported protocols in our request */ + for (i = 0; i < NUM_PROTOCOLS; i++) + { + buf[offset++] = 0; /* cipher we are using */ + buf[offset++] = ssl_prot_prefs[i]; + } + + buf[offset++] = 1; /* no compression */ + buf[offset++] = 0; + buf[3] = offset - 4; /* handshake size */ + + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset); +} + +/* + * Process the server hello. + */ +static int process_server_hello(SSL *ssl) +{ + uint8_t *buf = ssl->bm_data; + int pkt_size = ssl->bm_index; + int num_sessions = ssl->ssl_ctx->num_sessions; + uint8_t sess_id_size; + int offset, ret = SSL_OK; + + /* check that we are talking to a TLSv1 server */ + uint8_t version = (buf[4] << 4) + buf[5]; + if (version > SSL_PROTOCOL_VERSION_MAX) + { + version = SSL_PROTOCOL_VERSION_MAX; + } + else if (ssl->version < SSL_PROTOCOL_MIN_VERSION) + { + ret = SSL_ERROR_INVALID_VERSION; + ssl_display_error(ret); + goto error; + } + + ssl->version = version; + + /* get the server random value */ + memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE); + offset = 6 + SSL_RANDOM_SIZE; /* skip of session id size */ + sess_id_size = buf[offset++]; + + if (sess_id_size > SSL_SESSION_ID_SIZE) + { + ret = SSL_ERROR_INVALID_SESSION; + goto error; + } + + if (num_sessions) + { + ssl->session = ssl_session_update(num_sessions, + ssl->ssl_ctx->ssl_sessions, ssl, &buf[offset]); + memcpy(ssl->session->session_id, &buf[offset], sess_id_size); + + /* pad the rest with 0's */ + if (sess_id_size < SSL_SESSION_ID_SIZE) + { + memset(&ssl->session->session_id[sess_id_size], 0, + SSL_SESSION_ID_SIZE-sess_id_size); + } + } + + memcpy(ssl->session_id, &buf[offset], sess_id_size); + ssl->sess_id_size = sess_id_size; + offset += sess_id_size; + + /* get the real cipher we are using */ + ssl->cipher = buf[++offset]; + ssl->next_state = IS_SET_SSL_FLAG(SSL_SESSION_RESUME) ? + HS_FINISHED : HS_CERTIFICATE; + + offset++; // skip the compr + PARANOIA_CHECK(pkt_size, offset); + ssl->dc->bm_proc_index = offset+1; + +error: + return ret; +} + +/** + * Process the server hello done message. + */ +static int process_server_hello_done(SSL *ssl) +{ + ssl->next_state = HS_FINISHED; + return SSL_OK; +} + +/* + * Send a client key exchange message. + */ +static int send_client_key_xchg(SSL *ssl) +{ + uint8_t *buf = ssl->bm_data; + uint8_t premaster_secret[SSL_SECRET_SIZE]; + int enc_secret_size = -1; + + buf[0] = HS_CLIENT_KEY_XCHG; + buf[1] = 0; + + premaster_secret[0] = 0x03; /* encode the version number */ + premaster_secret[1] = SSL_PROTOCOL_MINOR_VERSION; /* must be TLS 1.1 */ + get_random(SSL_SECRET_SIZE-2, &premaster_secret[2]); + DISPLAY_RSA(ssl, ssl->x509_ctx->rsa_ctx); + + /* rsa_ctx->bi_ctx is not thread-safe */ + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + enc_secret_size = RSA_encrypt(ssl->x509_ctx->rsa_ctx, premaster_secret, + SSL_SECRET_SIZE, &buf[6], 0); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + + buf[2] = (enc_secret_size + 2) >> 8; + buf[3] = (enc_secret_size + 2) & 0xff; + buf[4] = enc_secret_size >> 8; + buf[5] = enc_secret_size & 0xff; + + generate_master_secret(ssl, premaster_secret); + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, enc_secret_size+6); +} + +/* + * Process the certificate request. + */ +static int process_cert_req(SSL *ssl) +{ + uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index]; + int ret = SSL_OK; + int offset = (buf[2] << 4) + buf[3]; + int pkt_size = ssl->bm_index; + + /* don't do any processing - we will send back an RSA certificate anyway */ + ssl->next_state = HS_SERVER_HELLO_DONE; + SET_SSL_FLAG(SSL_HAS_CERT_REQ); + ssl->dc->bm_proc_index += offset; + PARANOIA_CHECK(pkt_size, offset); +error: + return ret; +} + +/* + * Send a certificate verify message. + */ +static int send_cert_verify(SSL *ssl) +{ + uint8_t *buf = ssl->bm_data; + uint8_t dgst[MD5_SIZE+SHA1_SIZE]; + RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx; + int n = 0, ret; + + DISPLAY_RSA(ssl, rsa_ctx); + + buf[0] = HS_CERT_VERIFY; + buf[1] = 0; + + finished_digest(ssl, NULL, dgst); /* calculate the digest */ + + /* rsa_ctx->bi_ctx is not thread-safe */ + if (rsa_ctx) + { + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + n = RSA_encrypt(rsa_ctx, dgst, sizeof(dgst), &buf[6], 1); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + + if (n == 0) + { + ret = SSL_ERROR_INVALID_KEY; + goto error; + } + } + + buf[4] = n >> 8; /* add the RSA size (not officially documented) */ + buf[5] = n & 0xff; + n += 2; + buf[2] = n >> 8; + buf[3] = n & 0xff; + ret = send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, n+4); + +error: + return ret; +} + +#endif /* CONFIG_SSL_ENABLE_CLIENT */ diff --git a/ssl/tls1_svr.c b/ssl/tls1_svr.c new file mode 100644 index 000000000..51c9d76e8 --- /dev/null +++ b/ssl/tls1_svr.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include "os_port.h" +#include "ssl.h" + +static const uint8_t g_hello_done[] = { HS_SERVER_HELLO_DONE, 0, 0, 0 }; + +static int process_client_hello(SSL *ssl); +static int send_server_hello_sequence(SSL *ssl); +static int send_server_hello(SSL *ssl); +static int send_server_hello_done(SSL *ssl); +static int process_client_key_xchg(SSL *ssl); +#ifdef CONFIG_SSL_CERT_VERIFICATION +static int send_certificate_request(SSL *ssl); +static int process_cert_verify(SSL *ssl); +#endif + +/* + * Establish a new SSL connection to an SSL client. + */ +EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd) +{ + SSL *ssl; + + ssl = ssl_new(ssl_ctx, client_fd); + ssl->next_state = HS_CLIENT_HELLO; + +#ifdef CONFIG_SSL_FULL_MODE + if (ssl_ctx->chain_length == 0) + printf("Warning - no server certificate defined\n"); TTY_FLUSH(); +#endif + + return ssl; +} + +/* + * Process the handshake record. + */ +int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len) +{ + int ret = SSL_OK; + ssl->hs_status = SSL_NOT_OK; /* not connected */ + + /* To get here the state must be valid */ + switch (handshake_type) + { + case HS_CLIENT_HELLO: + if ((ret = process_client_hello(ssl)) == SSL_OK) + ret = send_server_hello_sequence(ssl); + break; + +#ifdef CONFIG_SSL_CERT_VERIFICATION + case HS_CERTIFICATE:/* the client sends its cert */ + ret = process_certificate(ssl, &ssl->x509_ctx); + + if (ret == SSL_OK) /* verify the cert */ + { + int cert_res; + cert_res = x509_verify( + ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx); + ret = (cert_res == 0) ? SSL_OK : SSL_X509_ERROR(cert_res); + } + break; + + case HS_CERT_VERIFY: + ret = process_cert_verify(ssl); + add_packet(ssl, buf, hs_len); /* needs to be done after */ + break; +#endif + case HS_CLIENT_KEY_XCHG: + ret = process_client_key_xchg(ssl); + break; + + case HS_FINISHED: + ret = process_finished(ssl, buf, hs_len); + disposable_free(ssl); /* free up some memory */ + break; + } + + return ret; +} + +/* + * Process a client hello message. + */ +static int process_client_hello(SSL *ssl) +{ + uint8_t *buf = ssl->bm_data; + uint8_t *record_buf = ssl->hmac_header; + int pkt_size = ssl->bm_index; + int i, j, cs_len, id_len, offset = 6 + SSL_RANDOM_SIZE; + int ret = SSL_OK; + + uint8_t version = (buf[4] << 4) + buf[5]; + ssl->version = ssl->client_version = version; + + if (version > SSL_PROTOCOL_VERSION_MAX) + { + /* use client's version instead */ + ssl->version = SSL_PROTOCOL_VERSION_MAX; + } + else if (version < SSL_PROTOCOL_MIN_VERSION) /* old version supported? */ + { + ret = SSL_ERROR_INVALID_VERSION; + ssl_display_error(ret); + goto error; + } + + memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE); + + /* process the session id */ + id_len = buf[offset++]; + if (id_len > SSL_SESSION_ID_SIZE) + { + return SSL_ERROR_INVALID_SESSION; + } + +#ifndef CONFIG_SSL_SKELETON_MODE + ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions, + ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL); +#endif + + offset += id_len; + cs_len = (buf[offset]<<8) + buf[offset+1]; + offset += 3; /* add 1 due to all cipher suites being 8 bit */ + + PARANOIA_CHECK(pkt_size, offset); + + /* work out what cipher suite we are going to use - client defines + the preference */ + for (i = 0; i < cs_len; i += 2) + { + for (j = 0; j < NUM_PROTOCOLS; j++) + { + if (ssl_prot_prefs[j] == buf[offset+i]) /* got a match? */ + { + ssl->cipher = ssl_prot_prefs[j]; + goto do_state; + } + } + } + + /* ouch! protocol is not supported */ + ret = SSL_ERROR_NO_CIPHER; + +do_state: +error: + return ret; +} + +#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE +/* + * Some browsers use a hybrid SSLv2 "client hello" + */ +int process_sslv23_client_hello(SSL *ssl) +{ + uint8_t *buf = ssl->bm_data; + int bytes_needed = ((buf[0] & 0x7f) << 8) + buf[1]; + int ret = SSL_OK; + + /* we have already read 3 extra bytes so far */ + int read_len = SOCKET_READ(ssl->client_fd, buf, bytes_needed-3); + int cs_len = buf[1]; + int id_len = buf[3]; + int ch_len = buf[5]; + int i, j, offset = 8; /* start at first cipher */ + int random_offset = 0; + + DISPLAY_BYTES(ssl, "received %d bytes", buf, read_len, read_len); + + add_packet(ssl, buf, read_len); + + /* connection has gone, so die */ + if (bytes_needed < 0) + { + return SSL_ERROR_CONN_LOST; + } + + /* now work out what cipher suite we are going to use */ + for (j = 0; j < NUM_PROTOCOLS; j++) + { + for (i = 0; i < cs_len; i += 3) + { + if (ssl_prot_prefs[j] == buf[offset+i]) + { + ssl->cipher = ssl_prot_prefs[j]; + goto server_hello; + } + } + } + + /* ouch! protocol is not supported */ + ret = SSL_ERROR_NO_CIPHER; + goto error; + +server_hello: + /* get the session id */ + offset += cs_len - 2; /* we've gone 2 bytes past the end */ +#ifndef CONFIG_SSL_SKELETON_MODE + ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions, + ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL); +#endif + + /* get the client random data */ + offset += id_len; + + /* random can be anywhere between 16 and 32 bytes long - so it is padded + * with 0's to the left */ + if (ch_len == 0x10) + { + random_offset += 0x10; + } + + memcpy(&ssl->dc->client_random[random_offset], &buf[offset], ch_len); + ret = send_server_hello_sequence(ssl); + +error: + return ret; +} +#endif + +/* + * Send the entire server hello sequence + */ +static int send_server_hello_sequence(SSL *ssl) +{ + int ret; + + if ((ret = send_server_hello(ssl)) == SSL_OK) + { +#ifndef CONFIG_SSL_SKELETON_MODE + /* resume handshake? */ + if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) + { + if ((ret = send_change_cipher_spec(ssl)) == SSL_OK) + { + ret = send_finished(ssl); + ssl->next_state = HS_FINISHED; + } + } + else +#endif + if ((ret = send_certificate(ssl)) == SSL_OK) + { +#ifdef CONFIG_SSL_CERT_VERIFICATION + /* ask the client for its certificate */ + if (IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION)) + { + if ((ret = send_certificate_request(ssl)) == SSL_OK) + { + ret = send_server_hello_done(ssl); + ssl->next_state = HS_CERTIFICATE; + } + } + else +#endif + { + ret = send_server_hello_done(ssl); + ssl->next_state = HS_CLIENT_KEY_XCHG; + } + } + } + + return ret; +} + +/* + * Send a server hello message. + */ +static int send_server_hello(SSL *ssl) +{ + uint8_t *buf = ssl->bm_data; + int offset = 0; + + buf[0] = HS_SERVER_HELLO; + buf[1] = 0; + buf[2] = 0; + /* byte 3 is calculated later */ + buf[4] = 0x03; + buf[5] = ssl->version & 0x0f; + + /* server random value */ + get_random(SSL_RANDOM_SIZE, &buf[6]); + memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE); + offset = 6 + SSL_RANDOM_SIZE; + +#ifndef CONFIG_SSL_SKELETON_MODE + if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) + { + /* retrieve id from session cache */ + buf[offset++] = SSL_SESSION_ID_SIZE; + memcpy(&buf[offset], ssl->session->session_id, SSL_SESSION_ID_SIZE); + memcpy(ssl->session_id, ssl->session->session_id, SSL_SESSION_ID_SIZE); + ssl->sess_id_size = SSL_SESSION_ID_SIZE; + offset += SSL_SESSION_ID_SIZE; + } + else /* generate our own session id */ +#endif + { +#ifndef CONFIG_SSL_SKELETON_MODE + buf[offset++] = SSL_SESSION_ID_SIZE; + get_random(SSL_SESSION_ID_SIZE, &buf[offset]); + memcpy(ssl->session_id, &buf[offset], SSL_SESSION_ID_SIZE); + ssl->sess_id_size = SSL_SESSION_ID_SIZE; + + /* store id in session cache */ + if (ssl->ssl_ctx->num_sessions) + { + memcpy(ssl->session->session_id, + ssl->session_id, SSL_SESSION_ID_SIZE); + } + + offset += SSL_SESSION_ID_SIZE; +#else + buf[offset++] = 0; /* don't bother with session id in skelton mode */ +#endif + } + + buf[offset++] = 0; /* cipher we are using */ + buf[offset++] = ssl->cipher; + buf[offset++] = 0; /* no compression */ + buf[3] = offset - 4; /* handshake size */ + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset); +} + +/* + * Send the server hello done message. + */ +static int send_server_hello_done(SSL *ssl) +{ + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, + g_hello_done, sizeof(g_hello_done)); +} + +/* + * Pull apart a client key exchange message. Decrypt the pre-master key (using + * our RSA private key) and then work out the master key. Initialise the + * ciphers. + */ +static int process_client_key_xchg(SSL *ssl) +{ + uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index]; + int pkt_size = ssl->bm_index; + int premaster_size, secret_length = (buf[2] << 8) + buf[3]; + uint8_t premaster_secret[MAX_KEY_BYTE_SIZE]; + RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx; + int offset = 4; + int ret = SSL_OK; + + if (rsa_ctx == NULL) + { + ret = SSL_ERROR_NO_CERT_DEFINED; + goto error; + } + + /* is there an extra size field? */ + if ((secret_length - 2) == rsa_ctx->num_octets) + offset += 2; + + PARANOIA_CHECK(pkt_size, rsa_ctx->num_octets+offset); + + /* rsa_ctx->bi_ctx is not thread-safe */ + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + premaster_size = RSA_decrypt(rsa_ctx, &buf[offset], premaster_secret, 1); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + + if (premaster_size != SSL_SECRET_SIZE || + premaster_secret[0] != 0x03 || /* must be the same as client + offered version */ + premaster_secret[1] != (ssl->client_version & 0x0f)) + { + /* guard against a Bleichenbacher attack */ + get_random(SSL_SECRET_SIZE, premaster_secret); + /* and continue - will die eventually when checking the mac */ + } + +#if 0 + print_blob("pre-master", premaster_secret, SSL_SECRET_SIZE); +#endif + + generate_master_secret(ssl, premaster_secret); + +#ifdef CONFIG_SSL_CERT_VERIFICATION + ssl->next_state = IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION) ? + HS_CERT_VERIFY : HS_FINISHED; +#else + ssl->next_state = HS_FINISHED; +#endif + + ssl->dc->bm_proc_index += rsa_ctx->num_octets+offset; +error: + return ret; +} + +#ifdef CONFIG_SSL_CERT_VERIFICATION +static const uint8_t g_cert_request[] = { HS_CERT_REQ, 0, 0, 4, 1, 0, 0, 0 }; + +/* + * Send the certificate request message. + */ +static int send_certificate_request(SSL *ssl) +{ + return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, + g_cert_request, sizeof(g_cert_request)); +} + +/* + * Ensure the client has the private key by first decrypting the packet and + * then checking the packet digests. + */ +static int process_cert_verify(SSL *ssl) +{ + uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index]; + int pkt_size = ssl->bm_index; + uint8_t dgst_buf[MAX_KEY_BYTE_SIZE]; + uint8_t dgst[MD5_SIZE+SHA1_SIZE]; + X509_CTX *x509_ctx = ssl->x509_ctx; + int ret = SSL_OK; + int n; + + PARANOIA_CHECK(pkt_size, x509_ctx->rsa_ctx->num_octets+6); + DISPLAY_RSA(ssl, x509_ctx->rsa_ctx); + + /* rsa_ctx->bi_ctx is not thread-safe */ + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + n = RSA_decrypt(x509_ctx->rsa_ctx, &buf[6], dgst_buf, 0); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + + if (n != SHA1_SIZE + MD5_SIZE) + { + ret = SSL_ERROR_INVALID_KEY; + goto end_cert_vfy; + } + + finished_digest(ssl, NULL, dgst); /* calculate the digest */ + if (memcmp(dgst_buf, dgst, MD5_SIZE + SHA1_SIZE)) + { + ret = SSL_ERROR_INVALID_KEY; + } + +end_cert_vfy: + ssl->next_state = HS_FINISHED; +error: + return ret; +} + +#endif diff --git a/ssl/version.h b/ssl/version.h new file mode 100644 index 000000000..e8158cc0d --- /dev/null +++ b/ssl/version.h @@ -0,0 +1 @@ +#define AXTLS_VERSION "1.4.9" diff --git a/ssl/x509.c b/ssl/x509.c new file mode 100644 index 000000000..cb007fbbc --- /dev/null +++ b/ssl/x509.c @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file x509.c + * + * Certificate processing. + */ + +#include +#include +#include +#include +#include "os_port.h" +#include "crypto_misc.h" + +#ifdef CONFIG_SSL_CERT_VERIFICATION +/** + * Retrieve the signature from a certificate. + */ +static const uint8_t *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 + +/** + * 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 (SHA1/MD5/MD2) */ + if (x509_ctx->sig_type == SIG_TYPE_MD5) + { + MD5_CTX md5_ctx; + uint8_t md5_dgst[MD5_SIZE]; + MD5_Init(&md5_ctx); + MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + MD5_Final(md5_dgst, &md5_ctx); + 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]; + SHA1_Init(&sha_ctx); + SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + SHA1_Final(sha_dgst, &sha_ctx); + x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE); + } + else if (x509_ctx->sig_type == SIG_TYPE_MD2) + { + MD2_CTX md2_ctx; + uint8_t md2_dgst[MD2_SIZE]; + MD2_Init(&md2_ctx); + MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs); + MD2_Final(md2_dgst, &md2_ctx); + x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE); + } + + if (cert[offset] == ASN1_V3_DATA) + { + int suboffset; + + ++offset; + get_asn1_length(cert, &offset); + + if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0) + { + if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0) + { + int altlen; + + if ((altlen = asn1_next_obj(cert, + &suboffset, ASN1_SEQUENCE)) > 0) + { + int endalt = suboffset + altlen; + int totalnames = 0; + + while (suboffset < endalt) + { + int type = cert[suboffset++]; + int dnslen = get_asn1_length(cert, &suboffset); + + if (type == ASN1_CONTEXT_DNSNAME) + { + x509_ctx->subject_alt_dnsnames = (char**) + realloc(x509_ctx->subject_alt_dnsnames, + (totalnames + 2) * sizeof(char*)); + x509_ctx->subject_alt_dnsnames[totalnames] = + (char*)malloc(dnslen + 1); + x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL; + memcpy(x509_ctx->subject_alt_dnsnames[totalnames], + cert + suboffset, dnslen); + x509_ctx->subject_alt_dnsnames[ + totalnames][dnslen] = 0; + ++totalnames; + } + + suboffset += dnslen; + } + } + } + } + } + + offset = end_tbs; /* skip the rest of v3 data */ + if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || + asn1_signature(cert, &offset, x509_ctx)) + goto end_cert; +#endif + ret = X509_OK; +end_cert: + if (len) + { + *len = cert_size; + } + + if (ret) + { +#ifdef CONFIG_SSL_FULL_MODE + printf("Error: Invalid X509 ASN.1 file (%s)\n", + x509_display_error(ret)); +#endif + x509_free(x509_ctx); + *ctx = NULL; + } + + 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); + } + + if (x509_ctx->subject_alt_dnsnames) + { + for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i) + free(x509_ctx->subject_alt_dnsnames[i]); + + free(x509_ctx->subject_alt_dnsnames); + } +#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 +/** + * Take a signature and decrypt it. + */ +static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, + bigint *modulus, bigint *pub_exp) +{ + int i, size; + bigint *decrypted_bi, *dat_bi; + bigint *bir = NULL; + uint8_t *block = (uint8_t *)alloca(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 = get_signature(&block[i], &len); + + if (sig_ptr) + { + bir = bi_import(ctx, sig_ptr, len); + } + } + + /* save a few bytes of memory */ + bi_clear_cache(ctx); + return bir; +} + +/** + * Do some basic checks on the certificate chain. + * + * Certificate verification consists of a number of checks: + * - The date of the certificate is after the start date. + * - The date of the certificate is before the finish date. + * - A root certificate exists in the certificate store. + * - That the certificate(s) are not self-signed. + * - The certificate chain is valid. + * - 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 = NULL; + bigint *mod = NULL, *expn = NULL; + int match_ca_cert = 0; + struct timeval tv; + uint8_t is_self_signed = 0; + + if (cert == NULL) + { + ret = X509_VFY_ERROR_NO_TRUSTED_CERT; + goto end_verify; + } + + /* a self-signed certificate that is not in the CA store - use this + to check the signature */ + if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0) + { + is_self_signed = 1; + ctx = cert->rsa_ctx->bi_ctx; + mod = cert->rsa_ctx->m; + expn = cert->rsa_ctx->e; + } + + 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; + } + + next_cert = cert->next; + + /* last cert in the chain - look for a trusted cert */ + if (next_cert == NULL) + { + if (ca_cert_ctx != NULL) + { + /* go thu the CA store */ + 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) + { + /* use this CA certificate for signature verification */ + match_ca_cert = 1; + ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx; + mod = ca_cert_ctx->cert[i]->rsa_ctx->m; + expn = ca_cert_ctx->cert[i]->rsa_ctx->e; + break; + } + + i++; + } + } + + /* couldn't find a trusted cert (& let self-signed errors + be returned) */ + if (!match_ca_cert && !is_self_signed) + { + ret = X509_VFY_ERROR_NO_TRUSTED_CERT; + goto end_verify; + } + } + else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0) + { + /* check the chain */ + ret = X509_VFY_ERROR_INVALID_CHAIN; + goto end_verify; + } + else /* use the next certificate in the chain for signature verify */ + { + ctx = next_cert->rsa_ctx->bi_ctx; + mod = next_cert->rsa_ctx->m; + expn = next_cert->rsa_ctx->e; + } + + /* cert is self signed */ + if (!match_ca_cert && is_self_signed) + { + ret = X509_VFY_ERROR_SELF_SIGNED; + goto end_verify; + } + + /* check the signature */ + cert_sig = sig_verify(ctx, cert->signature, cert->sig_len, + bi_clone(ctx, mod), bi_clone(ctx, expn)); + + if (cert_sig && cert->digest) + { + if (bi_compare(cert_sig, cert->digest) != 0) + ret = X509_VFY_ERROR_BAD_SIGNATURE; + + + bi_free(ctx, cert_sig); + } + else + { + ret = X509_VFY_ERROR_BAD_SIGNATURE; + } + + if (ret) + goto end_verify; + + /* go down the certificate chain using recursion. */ + if (next_cert != NULL) + { + ret = x509_verify(ca_cert_ctx, next_cert); + } + +end_verify: + return ret; +} +#endif + +#if defined (CONFIG_SSL_FULL_MODE) +/** + * Used for diagnostics. + */ +static const char *not_part_of_cert = ""; +void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx) +{ + if (cert == NULL) + return; + + printf("=== CERTIFICATE ISSUED TO ===\n"); + printf("Common Name (CN):\t\t"); + printf("%s\n", cert->cert_dn[X509_COMMON_NAME] ? + cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert); + + printf("Organization (O):\t\t"); + printf("%s\n", cert->cert_dn[X509_ORGANIZATION] ? + cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert); + + printf("Organizational Unit (OU):\t"); + printf("%s\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ? + cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert); + + printf("=== CERTIFICATE ISSUED BY ===\n"); + printf("Common Name (CN):\t\t"); + printf("%s\n", cert->ca_cert_dn[X509_COMMON_NAME] ? + cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert); + + printf("Organization (O):\t\t"); + printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATION] ? + cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert); + + printf("Organizational Unit (OU):\t"); + printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ? + cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert); + + printf("Not Before:\t\t\t%s", ctime(&cert->not_before)); + printf("Not After:\t\t\t%s", ctime(&cert->not_after)); + printf("RSA bitsize:\t\t\t%d\n", cert->rsa_ctx->num_octets*8); + printf("Sig Type:\t\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; + } + + if (ca_cert_ctx) + { + printf("Verify:\t\t\t\t%s\n", + x509_display_error(x509_verify(ca_cert_ctx, cert))); + } + +#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(cert->next, ca_cert_ctx); + } + + TTY_FLUSH(); +} + +const char * x509_display_error(int error) +{ + switch (error) + { + case X509_OK: + return "Certificate verify successful"; + + case X509_NOT_OK: + return "X509 not ok"; + + case X509_VFY_ERROR_NO_TRUSTED_CERT: + return "No trusted cert is available"; + + case X509_VFY_ERROR_BAD_SIGNATURE: + return "Bad signature"; + + case X509_VFY_ERROR_NOT_YET_VALID: + return "Cert is not yet valid"; + + case X509_VFY_ERROR_EXPIRED: + return "Cert has expired"; + + case X509_VFY_ERROR_SELF_SIGNED: + return "Cert is self-signed"; + + case X509_VFY_ERROR_INVALID_CHAIN: + return "Chain is invalid (check order of certs)"; + + case X509_VFY_ERROR_UNSUPPORTED_DIGEST: + return "Unsupported digest"; + + case X509_INVALID_PRIV_KEY: + return "Invalid private key"; + + default: + return "Unknown"; + } +} +#endif /* CONFIG_SSL_FULL_MODE */ +