diff options
Diffstat (limited to 'tool/mbed/mbed-sdk/libraries/net/https/axTLS')
32 files changed, 11786 insertions, 0 deletions
diff --git a/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/aes.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/aes.c new file mode 100644 index 000000000..2ab1e86d4 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/aes.c @@ -0,0 +1,460 @@ +/* + * 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 <string.h> +//#include "os_port.h" +#include "crypto.h" +#include <lwip/def.h> + +/* all commented out in skeleton mode */ +#ifndef CONFIG_SSL_SKELETON_MODE + +#define rot1(x) (((x) << 24) | ((x) >> 8)) +#define rot2(x) (((x) << 16) | ((x) >> 16)) +#define rot3(x) (((x) <<  8) | ((x) >> 24)) + +/*  + * This cute trick does 4 'mul by two' at once.  Stolen from + * Dr B. R. Gladman <brg@gladman.uk.net> but I'm sure the u-(u>>7) is + * a standard graphics trick + * The key to this is that we need to xor with 0x1b if the top bit is set. + * a 1xxx xxxx   0xxx 0xxx First we mask the 7bit, + * b 1000 0000   0000 0000 then we shift right by 7 putting the 7bit in 0bit, + * c 0000 0001   0000 0000 we then subtract (c) from (b) + * d 0111 1111   0000 0000 and now we and with our mask + * e 0001 1011   0000 0000 + */ +#define mt  0x80808080 +#define ml  0x7f7f7f7f +#define mh  0xfefefefe +#define mm  0x1b1b1b1b +#define mul2(x,t)    ((t)=((x)&mt), \ +            ((((x)+(x))&mh)^(((t)-((t)>>7))&mm))) + +#define inv_mix_col(x,f2,f4,f8,f9) (\ +            (f2)=mul2(x,f2), \ +            (f4)=mul2(f2,f4), \ +            (f8)=mul2(f4,f8), \ +            (f9)=(x)^(f8), \ +            (f8)=((f2)^(f4)^(f8)), \ +            (f2)^=(f9), \ +            (f4)^=(f9), \ +            (f8)^=rot3(f2), \ +            (f8)^=rot2(f4), \ +            (f8)^rot1(f9)) + +/* + * 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<ii; i++) +    { +        tmp = W[i-1]; + +        if ((i % words) == 0) +        { +            tmp2 =(uint32_t)aes_sbox[(tmp    )&0xff]<< 8; +            tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<<16; +            tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<24; +            tmp2|=(uint32_t)aes_sbox[(tmp>>24)     ]; +            tmp=tmp2^(((unsigned int)*ip)<<24); +            ip++; +        } + +        if ((words == 8) && ((i % words) == 4)) +        { +            tmp2 =(uint32_t)aes_sbox[(tmp    )&0xff]    ; +            tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<< 8; +            tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<16; +            tmp2|=(uint32_t)aes_sbox[(tmp>>24)     ]<<24; +            tmp=tmp2; +        } + +        W[i]=W[i-words]^tmp; +    } + +    /* copy the iv across */ +    memcpy(ctx->iv, iv, 16); +} + +/** + * Change a key for decryption. + */ +void AES_convert_key(AES_CTX *ctx) +{ +    int i; +    uint32_t *k,w,t1,t2,t3,t4; + +    k = ctx->ks; +    k += 4; + +    for (i= ctx->rounds*4; i > 4; i--) +    { +        w= *k; +        w = inv_mix_col(w,t1,t2,t3,t4); +        *k++ =w; +    } +} + +/** + * Encrypt a byte sequence (with a block size 16) using the AES cipher. + */ +void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length) +{ +    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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint.c new file mode 100644 index 000000000..7275ed1fc --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint.c @@ -0,0 +1,1515 @@ +/* + * 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. + */ + +/** + * @defgroup bigint_api Big Integer API + * @brief The bigint implementation as used by the axTLS project. + * + * The bigint library is for RSA encryption/decryption as well as signing. + * This code tries to minimise use of malloc/free by maintaining a small  + * cache. A bigint context may maintain state by being made "permanent".  + * It be be later released with a bi_depermanent() and bi_free() call. + * + * It supports the following reduction techniques: + * - Classical + * - Barrett + * - Montgomery + * + * It also implements the following: + * - Karatsuba multiplication + * - Squaring + * - Sliding window exponentiation + * - Chinese Remainder Theorem (implemented in rsa.c). + * + * All the algorithms used are pretty standard, and designed for different + * data bus sizes. Negative numbers are not dealt with at all, so a subtraction + * may need to be tested for negativity. + * + * This library steals some ideas from Jef Poskanzer + * <http://cs.marlboro.edu/term/cs-fall02/algorithms/crypto/RSA/bigint> + * and GMP <http://www.swox.com/gmp>. It gets most of its implementation + * detail from "The Handbook of Applied Cryptography" + * <http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf> + * @{ + */ + +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <time.h> +#include "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<<COMP_BIT_SIZE) + biR->comps[i]; +        biR->comps[i] = (comp)(r / denom); +        r %= denom; +    } while (--i >= 0); + +    return trim(biR); +} + +#ifdef CONFIG_BIGINT_MONTGOMERY +/** + * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1,  + * where B^-1(B-1) mod N=1. Actually, only the least significant part of  + * N' is needed, hence the definition N0'=N' mod b. We reproduce below the  + * simple algorithm from an article by Dusse and Kaliski to efficiently  + * find N0' from N0 and b */ +static comp modular_inverse(bigint *bim) +{ +    int i; +    comp t = 1; +    comp two_2_i_minus_1 = 2;   /* 2^(i-1) */ +    long_comp two_2_i = 4;      /* 2^i */ +    comp N = bim->comps[0]; + +    for (i = 2; i <= COMP_BIT_SIZE; i++) +    { +        if ((long_comp)N*t%two_2_i >= two_2_i_minus_1) +        { +            t += two_2_i_minus_1; +        } + +        two_2_i_minus_1 <<= 1; +        two_2_i <<= 1; +    } + +    return (comp)(COMP_RADIX-t); +} +#endif + +#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \ +    defined(CONFIG_BIGINT_MONTGOMERY) +/** + * Take each component and shift down (in terms of components)  + */ +static bigint *comp_right_shift(bigint *biR, int num_shifts) +{ +    int i = biR->size-num_shifts; +    comp *x = biR->comps; +    comp *y = &biR->comps[num_shifts]; + +    check(biR); + +    if (i <= 0)     /* have we completely right shifted? */ +    { +        biR->comps[0] = 0;  /* return 0 */ +        biR->size = 1; +        return biR; +    } + +    do +    { +        *x++ = *y++; +    } while (--i > 0); + +    biR->size -= num_shifts; +    return biR; +} + +/** + * Take each component and shift it up (in terms of components)  + */ +static bigint *comp_left_shift(bigint *biR, int num_shifts) +{ +    int i = biR->size-1; +    comp *x, *y; + +    check(biR); + +    if (num_shifts <= 0) +    { +        return biR; +    } + +    more_comps(biR, biR->size + num_shifts); + +    x = &biR->comps[i+num_shifts]; +    y = &biR->comps[i]; + +    do +    { +        *x-- = *y--; +    } while (i--); + +    memset(biR->comps, 0, num_shifts*COMP_BYTE_SIZE); /* zero LS comps */ +    return biR; +} +#endif + +/** + * @brief Allow a binary sequence to be imported as a bigint. + * @param ctx [in]  The bigint session context. + * @param data [in] The data to be converted. + * @param size [in] The number of bytes of data. + * @return A bigint representing this data. + */ +bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size) +{ +    bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE); +    int i, j = 0, offset = 0; + +    memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE); + +    for (i = size-1; i >= 0; i--) +    { +        biR->comps[offset] += data[i] << (j*8); + +        if (++j == COMP_BYTE_SIZE) +        { +            j = 0; +            offset ++; +        } +    } + +    return trim(biR); +} + +#ifdef CONFIG_SSL_FULL_MODE +/** + * @brief The testharness uses this code to import text hex-streams and  + * convert them into bigints. + * @param ctx [in]  The bigint session context. + * @param data [in] A string consisting of hex characters. The characters must + * be in upper case. + * @return A bigint representing this data. + */ +bigint *bi_str_import(BI_CTX *ctx, const char *data) +{ +    int size = strlen(data); +    bigint *biR = alloc(ctx, (size+COMP_NUM_NIBBLES-1)/COMP_NUM_NIBBLES); +    int i, j = 0, offset = 0; +    memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE); + +    for (i = size-1; i >= 0; i--) +    { +        int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10); +        biR->comps[offset] += num << (j*4); + +        if (++j == COMP_NUM_NIBBLES) +        { +            j = 0; +            offset ++; +        } +    } + +    return biR; +} + +void bi_print(const char *label, bigint *x) +{ +    int i, j; + +    if (x == NULL) +    { +        printf("%s: (null)\n", label); +        return; +    } + +    printf("%s: (size %d)\n", label, x->size); +    for (i = x->size-1; i >= 0; i--) +    { +        for (j = COMP_NUM_NIBBLES-1; j >= 0; j--) +        { +            comp mask = 0x0f << (j*4); +            comp num = (x->comps[i] & mask) >> (j*4); +            putc((num <= 9) ? (num + '0') : (num + 'A' - 10), stdout); +        } +    }   + +    printf("\r\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); +    } +    bigint* a = bi_clone(ctx, bi); +    q1 = comp_right_shift(a, 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 */ +            bigint* a = bi_multiply(ctx, biR, ctx->g[part_exp]); +            biR = bi_residue(ctx, a); +            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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint.h b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint.h new file mode 100644 index 000000000..2966a3edb --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint_impl.h b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint_impl.h new file mode 100644 index 000000000..b9fc2ae24 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/bigint_impl.h @@ -0,0 +1,133 @@ +/* + * 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. */ +#include <stdint.h> +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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto.h b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto.h new file mode 100644 index 000000000..3f32e6142 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto.h @@ -0,0 +1,229 @@ +/* + * 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 "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 +#define MAX_KEYBLOCK_SIZE 136 +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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto_misc.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto_misc.c new file mode 100644 index 000000000..0f9d3dcbf --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto_misc.c @@ -0,0 +1,375 @@ +/* + * 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 <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include "os_port.h" +#include <lwip/def.h> +#include "sockets.h" +#include "crypto_misc.h" +#include "config.h" + +#include <time.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 */ +    // XXX XXX XX X need to seed this properly +    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("\r\n"); +        column = 0; +    } + +    if (++hex_index >= hex_finish && column > 0) +    { +        printf("\r\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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/hmac.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/hmac.c new file mode 100644 index 000000000..24a04d77a --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/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 <string.h> +#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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/md2.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/md2.c new file mode 100644 index 000000000..0df38c9eb --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/md2.c @@ -0,0 +1,163 @@ +/* + * 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. + */ + +/* + *  RFC 1115/1319 compliant MD2 implementation + *  The MD2 algorithm was designed by Ron Rivest in 1989. + * + *  http://www.ietf.org/rfc/rfc1115.txt + *  http://www.ietf.org/rfc/rfc1319.txt + */ + +#include <string.h> +#include <stdio.h> +#include "os_port.h" +#include "crypto.h" +#include "config.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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/md5.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/md5.c new file mode 100644 index 000000000..7f5071300 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/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 <string.h> +#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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/os_int.h b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/os_int.h new file mode 100644 index 000000000..878856723 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/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 <inttypes.h> +#else +#include <stdint.h> +#endif /* Not Solaris */ + +#endif /* Not Win32 */ + +#ifdef __cplusplus +} +#endif + +#endif  diff --git a/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/rc4.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/rc4.c new file mode 100644 index 000000000..12a121151 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/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 <string.h> +#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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/rsa.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/rsa.c new file mode 100644 index 000000000..64282a262 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/rsa.c @@ -0,0 +1,270 @@ +/* + * 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 <stdio.h> +#include <string.h> +#include <time.h> +#include <stdlib.h> +#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) +{ +    printf("RSA private\n"); +#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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/sha1.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/sha1.c new file mode 100644 index 000000000..1082733e7 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/sha1.c @@ -0,0 +1,249 @@ +/* + * 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. + */ + +/** + * SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995. + * This code was originally taken from RFC3174 + */ + +#include <string.h> +#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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/asn1.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/asn1.c new file mode 100644 index 000000000..d95c9117c --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/asn1.c @@ -0,0 +1,565 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "os_port.h" +#include "crypto.h" +#include "crypto_misc.h" +#include "config.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)++; +    int tmp = get_asn1_length(buf, offset); +    return tmp; +} + +/** + * 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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/cert.h b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/cert.h new file mode 100644 index 000000000..48b901b04 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/cert.h @@ -0,0 +1,133 @@ +#ifndef CERT_H +#define CERT_H + +/* +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; +*/ +unsigned char default_certificate[] = { +  0x30, 0x82, 0x03, 0xb8, 0x30, 0x82, 0x03, 0x21, 0xa0, 0x03, 0x02, 0x01, +  0x02, 0x02, 0x09, 0x00, 0xe1, 0x40, 0xf0, 0x81, 0x55, 0x5d, 0xa4, 0x8f, +  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, +  0x05, 0x05, 0x00, 0x30, 0x81, 0x9a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, +  0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, 0x0d, 0x30, 0x0b, 0x06, +  0x03, 0x55, 0x04, 0x08, 0x13, 0x04, 0x54, 0x65, 0x73, 0x74, 0x31, 0x12, +  0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x54, 0x65, 0x73, +  0x74, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, +  0x55, 0x04, 0x0a, 0x13, 0x0e, 0x4e, 0x6f, 0x69, 0x73, 0x79, 0x20, 0x41, +  0x74, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, +  0x03, 0x55, 0x04, 0x0b, 0x14, 0x08, 0x53, 0x65, 0x63, 0x75, 0x69, 0x72, +  0x08, 0x08, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, +  0x0c, 0x41, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x20, 0x4d, 0x69, 0x6c, 0x6c, +  0x73, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, +  0x0d, 0x01, 0x09, 0x01, 0x16, 0x16, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79, +  0x40, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x6d, 0x69, 0x6c, 0x6c, 0x73, +  0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x35, +  0x31, 0x33, 0x31, 0x37, 0x35, 0x32, 0x34, 0x31, 0x5a, 0x17, 0x0d, 0x34, +  0x36, 0x30, 0x33, 0x32, 0x31, 0x31, 0x37, 0x35, 0x32, 0x34, 0x31, 0x5a, +  0x30, 0x81, 0x9a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, +  0x13, 0x02, 0x55, 0x4b, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, +  0x08, 0x13, 0x04, 0x54, 0x65, 0x73, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06, +  0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x54, 0x65, 0x73, 0x74, 0x76, 0x69, +  0x6c, 0x6c, 0x65, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, +  0x13, 0x0e, 0x4e, 0x6f, 0x69, 0x73, 0x79, 0x20, 0x41, 0x74, 0x6f, 0x6d, +  0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, +  0x0b, 0x14, 0x08, 0x53, 0x65, 0x63, 0x75, 0x69, 0x72, 0x08, 0x08, 0x31, +  0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0c, 0x41, 0x73, +  0x68, 0x6c, 0x65, 0x79, 0x20, 0x4d, 0x69, 0x6c, 0x6c, 0x73, 0x31, 0x25, +  0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, +  0x01, 0x16, 0x16, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x40, 0x61, 0x73, +  0x68, 0x6c, 0x65, 0x79, 0x6d, 0x69, 0x6c, 0x6c, 0x73, 0x2e, 0x63, 0x6f, +  0x6d, 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, 0xb1, 0xe0, 0x59, 0x6a, 0x19, 0x08, +  0x0d, 0x21, 0x98, 0x79, 0x96, 0x16, 0x2a, 0x5a, 0x5c, 0x20, 0xeb, 0x66, +  0x1e, 0x9e, 0x1e, 0xc4, 0xef, 0x83, 0x42, 0x15, 0xd8, 0x4b, 0x14, 0xd3, +  0xe7, 0xba, 0xc8, 0xf6, 0xb4, 0x52, 0xdf, 0x18, 0xa6, 0x6b, 0x8b, 0xca, +  0x84, 0xdc, 0x21, 0x26, 0xfd, 0x7c, 0xde, 0xbd, 0x2b, 0x64, 0x0d, 0xd3, +  0x20, 0x7c, 0xe7, 0x0c, 0xfc, 0x3c, 0xa9, 0x09, 0xc0, 0xa7, 0x78, 0x3d, +  0xe9, 0x48, 0x50, 0x90, 0xd7, 0x3e, 0x46, 0x78, 0x8f, 0xfc, 0xc8, 0xb6, +  0x89, 0x41, 0x49, 0x15, 0x47, 0x27, 0x4b, 0x46, 0xcb, 0x11, 0x82, 0xd8, +  0x7b, 0x68, 0xb7, 0xc5, 0x64, 0x70, 0xaf, 0xe6, 0x80, 0x63, 0xfe, 0x53, +  0x70, 0xee, 0xd2, 0xa9, 0x2c, 0x40, 0x96, 0x9c, 0xd4, 0xa1, 0xcf, 0xd4, +  0x51, 0x9d, 0xe1, 0xa7, 0xf0, 0xfb, 0xa6, 0x49, 0x4c, 0x00, 0x05, 0xff, +  0x8f, 0x61, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x02, 0x30, +  0x81, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, +  0x14, 0xf1, 0x67, 0xe6, 0xd7, 0x73, 0xe7, 0x12, 0x0a, 0xe1, 0xc3, 0x5f, +  0x34, 0x97, 0x23, 0x0d, 0xa0, 0xc6, 0x7e, 0x10, 0xe8, 0x30, 0x81, 0xcf, +  0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xc7, 0x30, 0x81, 0xc4, 0x80, +  0x14, 0xf1, 0x67, 0xe6, 0xd7, 0x73, 0xe7, 0x12, 0x0a, 0xe1, 0xc3, 0x5f, +  0x34, 0x97, 0x23, 0x0d, 0xa0, 0xc6, 0x7e, 0x10, 0xe8, 0xa1, 0x81, 0xa0, +  0xa4, 0x81, 0x9d, 0x30, 0x81, 0x9a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, +  0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, 0x0d, 0x30, 0x0b, 0x06, +  0x03, 0x55, 0x04, 0x08, 0x13, 0x04, 0x54, 0x65, 0x73, 0x74, 0x31, 0x12, +  0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x54, 0x65, 0x73, +  0x74, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, +  0x55, 0x04, 0x0a, 0x13, 0x0e, 0x4e, 0x6f, 0x69, 0x73, 0x79, 0x20, 0x41, +  0x74, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, +  0x03, 0x55, 0x04, 0x0b, 0x14, 0x08, 0x53, 0x65, 0x63, 0x75, 0x69, 0x72, +  0x08, 0x08, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, +  0x0c, 0x41, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x20, 0x4d, 0x69, 0x6c, 0x6c, +  0x73, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, +  0x0d, 0x01, 0x09, 0x01, 0x16, 0x16, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79, +  0x40, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x79, 0x6d, 0x69, 0x6c, 0x6c, 0x73, +  0x2e, 0x63, 0x6f, 0x6d, 0x82, 0x09, 0x00, 0xe1, 0x40, 0xf0, 0x81, 0x55, +  0x5d, 0xa4, 0x8f, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, +  0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, +  0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, +  0x89, 0x79, 0xf2, 0xa8, 0xd3, 0xc7, 0x02, 0x2d, 0x02, 0x68, 0x9a, 0xf1, +  0xa7, 0x10, 0xa2, 0x2c, 0x52, 0x12, 0xf2, 0x97, 0x39, 0x52, 0x83, 0x69, +  0xd7, 0xe7, 0x73, 0x1f, 0xf1, 0x02, 0x5e, 0xbe, 0x5f, 0xbe, 0x94, 0xa9, +  0x4d, 0x8f, 0xb7, 0x3c, 0x52, 0x35, 0x09, 0x0a, 0x69, 0xed, 0x5e, 0x12, +  0xc9, 0x4d, 0x59, 0xec, 0x47, 0xfa, 0x82, 0xe5, 0x79, 0xbc, 0x17, 0x9d, +  0xae, 0x02, 0x17, 0xb5, 0xfb, 0xca, 0xc7, 0x42, 0xf4, 0xb5, 0x48, 0x19, +  0x1c, 0xd4, 0xd6, 0xfb, 0x2a, 0x7b, 0x0e, 0x8b, 0x56, 0xcc, 0x8e, 0x7a, +  0xa8, 0xaf, 0x4e, 0x5a, 0xa1, 0xf1, 0x78, 0x37, 0x4d, 0x09, 0x03, 0x9a, +  0xde, 0x4c, 0x87, 0xbe, 0xb1, 0x93, 0x1a, 0x39, 0x9a, 0xbb, 0xa0, 0x5c, +  0xfe, 0x58, 0x71, 0x62, 0x20, 0x74, 0x04, 0xc5, 0x50, 0x6e, 0x7b, 0xad, +  0xbe, 0xb0, 0xaa, 0x64, 0xea, 0x48, 0xa7, 0x9f +}; +unsigned int default_certificate_len = 956; + +#endif diff --git a/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/config.h b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/config.h new file mode 100644 index 000000000..f4f4b1422 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/config.h @@ -0,0 +1,62 @@ +#ifndef CONFIG_H +#define CONFIG_H +#define CONFIG_DEBUG +#define CONFIG_STRIP_UNWANTED_SECTIONS 1 + +/* + * BigInt Options + */ +#define CONFIG_BIGINT_BARRETT 1 +#define CONFIG_BIGINT_CRT 1 +#define CONFIG_INTEGER_32BIT 1 + +/* + * SSL Library + */ +#define CONFIG_SSL_ENABLE_CLIENT 1 +//#define CONFIG_SSL_SKELETON_MODE +#define CONFIG_SSL_PROT_LOW 1 +//#undef CONFIG_SSL_PROT_MEDIUM +//#undef CONFIG_SSL_PROT_HIGH +#define CONFIG_SSL_USE_DEFAULT_KEY 1 +#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 +#undef CONFIG_SSL_HAS_PEM +#undef CONFIG_SSL_USE_PKCS12 +#define CONFIG_SSL_EXPIRY_TIME 24 +#define CONFIG_X509_MAX_CA_CERTS 1 +#define CONFIG_SSL_MAX_CERTS 1 +#undef CONFIG_SSL_CTX_MUTEXING +#undef CONFIG_USE_DEV_URANDOM +#undef CONFIG_WIN32_USE_CRYPTO_LIB +#undef CONFIG_OPENSSL_COMPATIBLE +#undef CONFIG_PERFORMANCE_TESTING +#undef CONFIG_SSL_TEST +#undef CONFIG_AXTLSWRAP +#undef CONFIG_AXHTTPD +#undef CONFIG_HTTP_STATIC_BUILD +#undef CONFIG_HTTP_HAS_CGI +#define CONFIG_HTTP_CGI_EXTENSIONS "" +#undef CONFIG_HTTP_ENABLE_LUA +#define CONFIG_HTTP_LUA_PREFIX "" +#undef CONFIG_HTTP_BUILD_LUA +#define CONFIG_HTTP_CGI_LAUNCHER "" +#undef CONFIG_HTTP_DIRECTORIES +#undef CONFIG_HTTP_HAS_AUTHORIZATION +#undef CONFIG_HTTP_HAS_IPV6 +#undef CONFIG_HTTP_ENABLE_DIFFERENT_USER +#define CONFIG_HTTP_USER "" +#undef CONFIG_HTTP_VERBOSE +#undef CONFIG_HTTP_IS_DAEMON +#define CONFIG_SSL_CERT_VERIFICATION +#define CONFIG_SSL_FULL_MODE + +#define MBED + +#endif diff --git a/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/crypto_misc.h b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/crypto_misc.h new file mode 100644 index 000000000..5c50a11b2 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/crypto_misc.h @@ -0,0 +1,176 @@ +/* + * 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" +#include "config.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 + +#include <time.h> + +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; +typedef struct  +{ +    X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS]; +} CA_CERT_CTX; +#ifdef CONFIG_SSL_CERT_VERIFICATION + +#endif + +int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx); +void x509_free(X509_CTX *x509_ctx); +int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert); + +#ifdef CONFIG_SSL_CERT_VERIFICATION +#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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/gen_cert.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/gen_cert.c new file mode 100644 index 000000000..c2fe381eb --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/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 <string.h> +#include <stdlib.h> +#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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/loader.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/loader.c new file mode 100644 index 000000000..8cc80d9c7 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/loader.c @@ -0,0 +1,480 @@ +/* + * 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 <stdlib.h> +#include <string.h> +#include <stdio.h> +#include "os_port.h" +#include "ssl.h" +#include "config.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.buf = data; +    ssl_obj.len = len; +    ret = do_obj(ssl_ctx, mem_type, &ssl_obj, password); +     +    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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/openssl.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/openssl.c new file mode 100644 index 000000000..6b5c4d8ee --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/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 <stdlib.h> +#include <string.h> +#include <stdarg.h> +#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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port.c new file mode 100644 index 000000000..a0627bf62 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port.c @@ -0,0 +1,280 @@ +/* + * 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 <time.h> +#include <stdlib.h> +#include <errno.h> +#include <stdarg.h> +#include "os_port.h" +#include <stdio.h> +#include "sockets.h" + +static int memory_buf[400]; +static char enable = 1; +static int nb_entries = 0; +static int nb_alloc = 0; + +void disable_memory_buf(void) +{ +    enable = 0; +} +void enable_memory_buf(void) +{ +    enable = 1; +} +void init_memory_buf(void) +{ +    for(int i = 0; i < 400; i += 2) +    { +        memory_buf[i] = -1; +        memory_buf[i+1] = 0; +    } +}    +void print_buf_stats(void) +{ +    if(enable) +    { +        int used = 0; +        for(int i = 1; i < 400; i += 2) +            used += memory_buf[i]; +        printf("%d\n", used); +    } +} + +void print_all_buf_stats(void) +{        +    int used = 0; +    for(int i = 1; i < 400; i += 2) +        used += memory_buf[i]; +    printf("used: %d bytes\n", used); +     +    for(int i = 0; i < 400; i += 2) +        if(memory_buf[i] != -1) +            printf("ptr:%X, size:%d\n", memory_buf[i], memory_buf[i+1]); +} + +static void add_entry(void *x, size_t s, const char* f, const int l) +{ +    nb_entries++; +    for(int i = 0; i < 400; i += 2) +    { +        if(memory_buf[i] == -1) +        { +            if(enable) +                printf("new ptr:%X, size:%d at %s:%d\n", x, s, f, l);  +            memory_buf[i] = (int)(x); +            memory_buf[i+1] = s; +            return; +        } +    } +    if(enable) +        printf("No space left in buffer\n");  +} + +static void remove_entry(void *x, const char* f, const int l) +{ +    nb_entries--; +    for(int i = 0; i < 400; i += 2) +    { +        if(memory_buf[i] == (int)(x)) +        { +            if(enable) +                printf("free ptr:%X, size:%d at %s:%d\n", memory_buf[i], memory_buf[i+1], f, l);  +            memory_buf[i] = -1; +            memory_buf[i+1] = 0; +            return; +        } +    } +    if(enable) +        printf("not found\n"); +} + +#ifdef MBED +/** + * gettimeofday() not in mbed  + */ +EXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone) +{        +    t->tv_sec = time(NULL); +    t->tv_usec = 0;                         /* 1sec precision only */  +} + +#endif + +#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 +#undef free + +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, const char* f, const int l) +{ +    if(enable)   +        printf("malloc\t"); + +    void *x; + +    if ((x = malloc(s)) == NULL) +        exit_now(out_of_mem_str); +    add_entry(x,s, f, l); +    print_buf_stats(); + +    return x; +} + +EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s, const char* f, const int l) +{ +    if(enable)   +        printf("realloc\t"); + +    void *x; + +    if ((x = realloc(y, s)) == NULL) +        exit_now(out_of_mem_str); +    remove_entry(y, f, l); +    add_entry(x,s, f, l); +    print_buf_stats(); +    return x; +} + +EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s, const char* f, const int l) +{ +    if(enable)   +        printf("calloc\t"); +    void *x; +   +    if ((x = calloc(n, s)) == NULL) { +        exit_now(out_of_mem_str); +    } + +    add_entry(x,n*s, f, l); +    print_buf_stats(); +    return x; +} + +EXP_FUNC void STDCALL ax_free(void *y, const char* f, const int l) +{ +    if(enable)   +        printf("free\t"); +         +    remove_entry(y, f, l); +    print_buf_stats(); +    free(y); +} +/* +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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port.h b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port.h new file mode 100644 index 000000000..3937261a7 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port.h @@ -0,0 +1,45 @@ +#ifndef HEADER_OS_PORT_H +#define HEADER_OS_PORT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "config.h" + +//#include <Thread.h> +#define SSL_CTX_MUTEX_TYPE          //Mutex +#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) + +#define malloc(A)       ax_malloc(A, __FILE__, __LINE__) +#ifndef realloc +#define realloc(A,B)    ax_realloc(A,B, __FILE__, __LINE__) +#endif +#define calloc(A,B)     ax_calloc(A,B, __FILE__, __LINE__) +#define free(A)         ax_free(A, __FILE__, __LINE__) + +#define STDCALL +#define EXP_FUNC +void init_memory_buf(void); +void disable_memory_buf(void); +void enable_memory_buf(void); +void print_buf_stats(void); +void print_all_buf_stats(void); + +EXP_FUNC void * STDCALL ax_malloc(size_t s, const char* f, const int l); +EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s, const char* f, const int l); +EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s, const char* f, const int l); +EXP_FUNC void   STDCALL ax_free(void *y, const char* f, const int l); + +//EXP_FUNC int STDCALL ax_open(const char *pathname, int flags);  + +#define SOCKET_READ(A,B,C)      lwip_read(A,B,C) +#define SOCKET_WRITE(A,B,C)     lwip_write(A,B,C) +#define SOCKET_CLOSE(A)         closesocket(A) +#define TTY_FLUSH() +#ifdef __cplusplus +} +#endif +#endif  diff --git a/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port_old.h b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port_old.h new file mode 100644 index 000000000..a9ac7393d --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/os_port_old.h @@ -0,0 +1,194 @@ +/* + * 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 <stdio.h> + +#if defined(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 + +#ifdef WIN32 + +/* Windows CE stuff */ +#if defined(_WIN32_WCE) +#include <basetsd.h> +#define abort()                 exit(1) +#else +#include <io.h> +#include <process.h> +#include <sys/timeb.h> +#include <fcntl.h> +#endif      /* _WIN32_WCE */ + +#include <winsock.h> +#include <direct.h> +#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 <unistd.h> +//#include <pwd.h> +//#include <netdb.h> +//#include <dirent.h> +//#include <fcntl.h> +#include <errno.h> +//#include <sys/stat.h> +#include <time.h> +#include <socket.h> +//#include <sys/wait.h> +#include <netinet/in.h> +#include <inet.h> + +#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 <pthread.h> +#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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/p12.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/p12.c new file mode 100644 index 000000000..2bafaf7ea --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/p12.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. + */ + +/** + * Process PKCS#8/PKCS#12 keys. + * + * The decoding of a PKCS#12 key is fairly specific - this code was tested on a + * key generated with: + * + * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem + * -keypbe PBE-SHA1-RC4-128 -certpbe PBE-SHA1-RC4-128  + * -name "p12_withoutCA" -out axTLS.withoutCA.p12 -password pass:abcd + * + * or with a certificate chain: + * + * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem + * -certfile axTLS.ca_x509.pem -keypbe PBE-SHA1-RC4-128 -certpbe + * PBE-SHA1-RC4-128 -name "p12_withCA" -out axTLS.withCA.p12 -password pass:abcd + * + * Note that the PBE has to be specified with PBE-SHA1-RC4-128. The + * private/public keys/certs have to use RSA encryption. Both the integrity + * and privacy passwords are the same. + * + * The PKCS#8 files were generated with something like: + * + * PEM format: + * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -v1 + * PBE-SHA1-RC4-128 -out axTLS.encrypted_pem.p8 + * + * DER format: + * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -outform DER + * -v1 PBE-SHA1-RC4-128 -out axTLS.encrypted.p8 + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/private_key.h b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/private_key.h new file mode 100644 index 000000000..ce7985c5a --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/ssl.h b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/ssl.h new file mode 100644 index 000000000..9625896d1 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/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 <time.h> + +/* 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(SSL_CTX *ssl_ctx, 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 *ssl, 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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1.c new file mode 100644 index 000000000..ab1e86d15 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1.c @@ -0,0 +1,2324 @@ +/* + * 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 <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> + + + +#include "lwip/sockets.h" +#include "os_port.h" +#include "ssl.h" +#include "arch.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(SSL_CTX *ssl_ctx, uint32_t options, int num_sessions) +{ +    ssl_ctx->options = options; +    RNG_initialize(); + +    if (load_key_certs(ssl_ctx) < 0) +    { +        printf("error loading key certs\r\n"); +        //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->ssl_ctx); +    //free(ssl); +} + +/* + * 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 = buf; +    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 *ssl, int client_fd) +{ +    SSL_CTX* ssl_ctx = ssl->ssl_ctx; +    ssl->need_bytes = SSL_RECORD_SIZE;      /* need a record */ +    ssl->client_fd = 0; +    ssl->flag = SSL_NEED_RECORD; +    ssl->bm_data = ssl->bm_all_data + BM_RECORD_OFFSET;  +    ssl->bm_read_index = 0; +    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->encrypt_ctx = NULL; +    ssl->decrypt_ctx = NULL; +     +    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\r\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 (lwip_select(FD_SETSIZE, NULL, &wfds, NULL, NULL) < 0) +                return SSL_ERROR_CONN_LOST; +             +        } +    } +    fd_set wfds; +    FD_ZERO(&wfds); +    FD_SET(ssl->client_fd, &wfds); +     +    /* block and wait for it */ +    if (lwip_select(FD_SETSIZE, 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; + +    uint8_t key_tmp[MAX_KEYBLOCK_SIZE] = {0}; +    /* only do once in a handshake */ +    if (memcmp(ssl->dc->key_block, key_tmp, MAX_KEYBLOCK_SIZE) == 0) +    { +#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 + +    if( (is_write ? ssl->encrypt_ctx : ssl->decrypt_ctx) != NULL) +        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; +} + +/**  +  * Blocking read  +  * data must be valid buffer of size length at least +  * length  +  */ +int basic_read2(SSL *ssl, uint8_t *data, uint32_t length) +{ +   // printf("basic_read2\n"); +    if(data == NULL) +        return -1; + +    int ret = 0; +     +    do +    { +        //printf("before_lwip_select\n"); +        fd_set rfds; +        FD_ZERO(&rfds); +        FD_SET(ssl->client_fd, &rfds); +         +        /* block and wait for it */ +        if (lwip_select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0) +            return SSL_ERROR_CONN_LOST; +      //  printf("after_lwip_select\n"); + +        int read_len = SOCKET_READ(ssl->client_fd, &data[ret], length-ret); +      //  printf("read_len = %d\n", read_len); + +        if (read_len < 0)  +        { +     +#ifdef WIN32 +            if (GetLastError() == WSAEWOULDBLOCK) +#else +            if (errno == EAGAIN || errno == EWOULDBLOCK) +#endif +                continue; +        } +     +        /* connection has gone, so die */ +        if (read_len <= 0) +        { +            printf("SSL_ERROR_CONN_LOST\n"); +            ssl->hs_status = SSL_ERROR_DEAD;  /* make sure it stays dead */ +            return SSL_ERROR_CONN_LOST; +        } +                 +        ret += read_len; + +    }while(ret < length); +    DISPLAY_BYTES(ssl, "received %d bytes", data, ret, ret); +    return ret; +} + +int read_record(SSL *ssl) +{ +    if(!IS_SET_SSL_FLAG(SSL_NEED_RECORD)) +        return 0; +    uint8_t record[SSL_RECORD_SIZE]; +    int ret = basic_read2(ssl, record, SSL_RECORD_SIZE); +    if(ret != SSL_RECORD_SIZE) +        return ret; + +       /* check for sslv2 "client hello" */ +    if (record[0] & 0x80 && record[2] == 1) +    { +#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE +        uint8_t version = (record[3] << 4) + record[4]; +        DISPLAY_BYTES(ssl, "ssl2 record", record, 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, &record[2], 3); +        ret = process_sslv23_client_hello(ssl);  +#else +        printf("Error: no SSLv23 handshaking allowed\n"); TTY_FLUSH(); +        ret = SSL_ERROR_NOT_SUPPORTED; +#endif +        return ret; +    } + +    ssl->need_bytes = (record[3] << 8) + record[4]; + + +    memcpy(ssl->hmac_header, record, 3);       /* store for hmac */ +    ssl->record_type = record[0]; +    CLR_SSL_FLAG(SSL_NEED_RECORD); +    return SSL_OK; +} + +int basic_decrypt(SSL *ssl, uint8_t *buf, int len) +{ +   if (IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED)) +    { +        ssl->cipher_info->decrypt(ssl->decrypt_ctx, buf, buf, len); + +        if (ssl->version >= SSL_PROTOCOL_VERSION1_1 && +                        ssl->cipher_info->iv_size) +        { +            buf += ssl->cipher_info->iv_size; +            ssl->need_bytes -= ssl->cipher_info->iv_size; +        } +        if(ssl->record_type != PT_APP_PROTOCOL_DATA) +            len = verify_digest(ssl,  +                    IS_SET_SSL_FLAG(SSL_IS_CLIENT) ? SSL_CLIENT_READ : SSL_SERVER_READ, buf, len); + +        /* does the hmac work? */ +        if (ssl->need_bytes < 0) +        { +            return ssl->need_bytes; +        } + +        DISPLAY_BYTES(ssl, "decrypted", buf, len); +        increment_read_sequence(ssl); +    } +    return len; +} + +int ssl_read(SSL *ssl, uint8_t *in_data, int len) +{ +    if(len <= 0 || in_data == NULL) +        return 0; +    +    if(IS_SET_SSL_FLAG(SSL_NEED_RECORD)) +    { +        read_record(ssl); +    } +    +    return process_data(ssl, in_data, len); +} + +int process_data(SSL* ssl, uint8_t *in_data, int len) +{ +    /* 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; +                int ret = do_handshake(ssl, NULL, 0); +                SET_SSL_FLAG(SSL_NEED_RECORD); +                return ret; +            } +            else /* no client renegotiation allowed */ +            { +                SET_SSL_FLAG(SSL_NEED_RECORD); +                return SSL_ERROR_NO_CLIENT_RENOG;               +            } + +        case PT_CHANGE_CIPHER_SPEC: +         +            if(basic_read2(ssl, ssl->bm_data, ssl->need_bytes) != ssl->need_bytes) +                return -1; +            ssl->need_bytes = basic_decrypt(ssl, ssl->bm_data, ssl->need_bytes); +            if(ssl->need_bytes < 0) +                return -1; + +            if (ssl->next_state != HS_FINISHED) +            { +                return SSL_ERROR_INVALID_HANDSHAKE; +            } + +            /* all encrypted from now on */ +            SET_SSL_FLAG(SSL_RX_ENCRYPTED); +            if (set_key_block(ssl, 0) < 0) +            { +                return SSL_ERROR_INVALID_HANDSHAKE; +            } +             +            memset(ssl->read_sequence, 0, 8); +            SET_SSL_FLAG(SSL_NEED_RECORD); +            break; + +        case PT_APP_PROTOCOL_DATA: +            if(len <= 0) +                return 0; +            if(ssl->need_bytes == 0) +                return 0; +            if (in_data) +            { +                uint16_t index = ssl->bm_index % 2048; +                if(ssl->bm_read_index == 0) +                { +                    int read_len = len; +                    if(read_len > 2048-index) +                        read_len = 2048-index; +                    if(read_len > ssl->need_bytes) +                        read_len = ssl->need_bytes; +                    read_len -= read_len % AES_BLOCKSIZE; + +                    if(read_len <= 0) +                        read_len = AES_BLOCKSIZE; +                    if(ssl->need_bytes < AES_BLOCKSIZE) +                        read_len = AES_BLOCKSIZE; +                    int ret = basic_read2(ssl, ssl->bm_all_data + index, read_len); +                    if(ret != read_len) +                        return 0; +                     +                    ssl->bm_read_index = basic_decrypt(ssl, ssl->bm_all_data + index, read_len); +                    ssl->need_bytes -= ssl->bm_read_index; +                    if(ssl->need_bytes == 0) +                    { +                        ssl->bm_read_index = 0; +                        SET_SSL_FLAG(SSL_NEED_RECORD); +                        return ssl_read(ssl, in_data, len); +                    } +                } +                if(len > ssl->bm_read_index) +                    len = ssl->bm_read_index; +                memcpy(in_data, ssl->bm_all_data+index, len); +                ssl->bm_index += len; +                ssl->bm_read_index -= len; +                 +                if(ssl->need_bytes == 0) +                    SET_SSL_FLAG(SSL_NEED_RECORD); +                if(ssl->bm_index >= 2048) +                    ssl->bm_index = 0; +                return len; +            } +            return 0; +             +        case PT_ALERT_PROTOCOL: +            if(basic_read2(ssl, ssl->bm_data, ssl->need_bytes) != ssl->need_bytes) +                return -1; +            ssl->need_bytes = basic_decrypt(ssl, ssl->bm_data, ssl->need_bytes); +            if(ssl->need_bytes < 0) +                return -1;  +             +            SET_SSL_FLAG(SSL_NEED_RECORD); + +            /* return the alert # with alert bit set */ +            if(ssl->bm_data[0] == SSL_ALERT_TYPE_WARNING && +               ssl->bm_data[1] == SSL_ALERT_CLOSE_NOTIFY) +            { +                send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY); +                SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY); +                return SSL_CLOSE_NOTIFY; +            } +            else  +            { +                int ret = -ssl->bm_data[1]; +                DISPLAY_ALERT(ssl, -ret); +                return ret; +            } + +        default: +            return SSL_ERROR_INVALID_PROT_MSG; + +    } +} + + +/** + * Do some basic checking of data and then perform the appropriate handshaking. + */ +static int do_handshake(SSL *ssl, uint8_t *buf, int read_len) +{ +    uint8_t hs_hdr[SSL_HS_HDR_SIZE]; +    if (IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED)) +    { +        if(basic_read2(ssl, ssl->bm_data, ssl->need_bytes) != ssl->need_bytes) +            return -1; +        ssl->need_bytes = basic_decrypt(ssl, ssl->bm_data, ssl->need_bytes); +        if(ssl->need_bytes < 0) +            return -1;  +        buf = ssl->bm_data; +    } +    else +    { +        if(basic_read2(ssl, hs_hdr, SSL_HS_HDR_SIZE) != SSL_HS_HDR_SIZE) +            return -1; +        buf = hs_hdr; +    } + +    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) +        { +            return SSL_ERROR_INVALID_HANDSHAKE; +        } +    } + +    //hs_len += SSL_HS_HDR_SIZE;  /* adjust for when adding packets */ +    ssl->bm_index = hs_len+SSL_HS_HDR_SIZE;     /* 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, SSL_HS_HDR_SIZE);  +    } +     +    if(!IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED)) +    { +        if(hs_len != 0 && handshake_type != HS_CERTIFICATE) +        { +            if(basic_read2(ssl, ssl->bm_data, hs_len) != hs_len) +                return -1; +            hs_len = basic_decrypt(ssl, ssl->bm_data, hs_len); +            if(hs_len < 0) +                return -1;  +             +            buf = ssl->bm_data; +            if (handshake_type != HS_CERT_VERIFY && handshake_type != HS_HELLO_REQUEST) +                add_packet(ssl, buf, hs_len); +        } +    } +    else if (handshake_type != HS_CERT_VERIFY && handshake_type != HS_HELLO_REQUEST) +        add_packet(ssl, ssl->bm_data+SSL_HS_HDR_SIZE, hs_len-SSL_HS_HDR_SIZE); + +#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); + +    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 is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); +    int ret = SSL_OK; +    int resume = IS_SET_SSL_FLAG(SSL_SESSION_RESUME); + +    PARANOIA_CHECK(ssl->bm_index, SSL_FINISHED_HASH_SIZE); + +    /* 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)); +        memset(ssl->dc->key_block, 0, MAX_KEYBLOCK_SIZE); +        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 cert_hdr[3]; +    if(basic_read2(ssl, cert_hdr, 3) != 3) +    { +        ret = SSL_NOT_OK; +        return ret; +    } + +    add_packet(ssl, cert_hdr, 3); +    int len = 5; +    int pkt_size = ssl->bm_index; +    int cert_size; +    int total_cert_size = (cert_hdr[1]<<8) + cert_hdr[2]; +    int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); +    X509_CTX **chain = x509_ctx; +    len += 2; +    PARANOIA_CHECK(total_cert_size, 3); + +    while (len < total_cert_size) +    { + +        if(basic_read2(ssl, cert_hdr, 3) != 3) +        { +            ret = SSL_NOT_OK; +            return ret; +        } + +        add_packet(ssl, cert_hdr, 3); + +        cert_size = (cert_hdr[1]<<8) + cert_hdr[2]; +        if(cert_size > RT_MAX_PLAIN_LENGTH) +        { +            ret = SSL_NOT_OK; +            return ret; +        } +         +        len += 3; + +        if(basic_read2(ssl, ssl->bm_data, cert_size) != cert_size) +        { +            return SSL_NOT_OK; +        } + +        add_packet(ssl, ssl->bm_data, cert_size); + +        if (x509_new(ssl->bm_data, NULL, chain)) +        { +            ret = SSL_ERROR_BAD_CERTIFICATE; +            goto error; +        } + +        chain = &((*chain)->next); +        len += cert_size; +    } +    PARANOIA_CHECK(pkt_size, len); + +    /* 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 += len; +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\r\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\r\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("\r\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("\r\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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1.h b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1.h new file mode 100644 index 000000000..4a4f453fe --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1.h @@ -0,0 +1,304 @@ +/* + * 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 "os_int.h" +#include "crypto.h" +#include "crypto_misc.h" + +#include "config.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         2048//16384 +#define RT_EXTRA                    512//1024 +#define BM_RECORD_OFFSET            5 +#define BM_ALL_DATA_SIZE            (RT_MAX_PLAIN_LENGTH+RT_EXTRA-BM_RECORD_OFFSET) + +#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[MAX_KEYBLOCK_SIZE]; +    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; +    void *connection; +    const cipher_info_t *cipher_info; +    void *encrypt_ctx; +    void *decrypt_ctx; +    uint8_t bm_all_data[RT_MAX_PLAIN_LENGTH]; +    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 *ssl, 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_read2(SSL *ssl, uint8_t *data, uint32_t length); +int read_record(SSL *ssl); +int basic_decrypt(SSL *ssl, uint8_t *buf, int len); +int process_data(SSL* ssl, uint8_t *in_data, int len); +int ssl_read(SSL *ssl, uint8_t *in_data, int len); +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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1_clnt.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1_clnt.c new file mode 100644 index 000000000..559571655 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1_clnt.c @@ -0,0 +1,414 @@ +/* + * 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 <stdlib.h> +#include <string.h> +#include <time.h> +#include <stdio.h> +#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 *ssl, int client_fd, const +        uint8_t *session_id, uint8_t sess_id_size) +{ +    SSL_CTX *ssl_ctx = ssl->ssl_ctx; +    ssl_new(ssl, 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 = read_record(ssl); +            if (ret < SSL_OK) +                break; +            ret = process_data(ssl, NULL, 0); +            if (ret < SSL_OK) +                break;     +        } +        ssl->hs_status = ret;            /* connected? */     +    } +    return ret; +} + +static int compute_size_send_client_hello(SSL *ssl) +{ +    int size = 6 + SSL_RANDOM_SIZE; +    size++; +    if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) +    { + +        size += ssl->sess_id_size; +    } +    size += 2; +    int i; +    for (i = 0; i < NUM_PROTOCOLS; i++) +        size += 2; +    size += 2; +    return size+BM_RECORD_OFFSET; +} + +/* + * 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[0] << 4) + buf[1]; +    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[2], SSL_RANDOM_SIZE); +    offset = 2 + 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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1_svr.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/tls1_svr.c new file mode 100644 index 000000000..51c9d76e8 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/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 <stdlib.h> +#include <string.h> +#include <stdio.h> +#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/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/version.h b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/version.h new file mode 100644 index 000000000..e8158cc0d --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/version.h @@ -0,0 +1 @@ +#define AXTLS_VERSION    "1.4.9" diff --git a/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/x509.c b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/x509.c new file mode 100644 index 000000000..4f88c8738 --- /dev/null +++ b/tool/mbed/mbed-sdk/libraries/net/https/axTLS/ssl/x509.c @@ -0,0 +1,556 @@ +/* + * 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 <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "os_port.h" +#include "crypto_misc.h" +#include "sockets.h" +#include "config.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) +    { +        printf("self signed cert\r\n"); +        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 = "<Not Part Of Certificate>"; +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\r\n", cert->cert_dn[X509_COMMON_NAME] ? +                    cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert); + +    printf("Organization (O):\t\t"); +    printf("%s\r\n", cert->cert_dn[X509_ORGANIZATION] ? +        cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert); + +    printf("Organizational Unit (OU):\t"); +    printf("%s\r\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ? +        cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert); + +    printf("=== CERTIFICATE ISSUED BY ===\r\n"); +    printf("Common Name (CN):\t\t"); +    printf("%s\r\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\r\n", cert->ca_cert_dn[X509_ORGANIZATION] ? +        cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert); + +    printf("Organizational Unit (OU):\t"); +    printf("%s\r\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\r\n", ctime(&cert->not_before)); +    printf("Not After:\t\t\t%s\r\n", ctime(&cert->not_after)); +    printf("RSA bitsize:\t\t\t%d\r\n", cert->rsa_ctx->num_octets*8); +    printf("Sig Type:\t\t\t"); +    switch (cert->sig_type) +    { +        case SIG_TYPE_MD5: +            printf("MD5\r\n"); +            break; +        case SIG_TYPE_SHA1: +            printf("SHA1\r\n"); +            break; +        case SIG_TYPE_MD2: +            printf("MD2\r\n"); +            break; +        default: +            printf("Unrecognized: %d\r\n", cert->sig_type); +            break; +    } + +    if (ca_cert_ctx) +    { +        printf("Verify:\t\t\t\t%s\r\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 */ +  | 
