diff options
author | Michał Cichoń <michcic@gmail.com> | 2012-05-06 01:46:56 +0200 |
---|---|---|
committer | Michał Cichoń <michcic@gmail.com> | 2012-05-06 01:46:56 +0200 |
commit | 81db488ebe397ddba4e51e04c0719023ef18cf70 (patch) | |
tree | 3667c7de1e4e446e354e87d14a3ddebae93bc5b2 /axTLS/src | |
parent | 30b6a77f86a35dab16b3bf9b815e089657fc6890 (diff) | |
download | pianobar-windows-build-81db488ebe397ddba4e51e04c0719023ef18cf70.tar.gz pianobar-windows-build-81db488ebe397ddba4e51e04c0719023ef18cf70.tar.bz2 pianobar-windows-build-81db488ebe397ddba4e51e04c0719023ef18cf70.zip |
Replace axTLS with PolarSSL as it does not handle secure connections well enough.
Diffstat (limited to 'axTLS/src')
31 files changed, 0 insertions, 18354 deletions
diff --git a/axTLS/src/README b/axTLS/src/README deleted file mode 100644 index c8926d9..0000000 --- a/axTLS/src/README +++ /dev/null @@ -1,3 +0,0 @@ - -See www/index.html for the README, CHANGELOG, LICENSE and other notes. - diff --git a/axTLS/src/crypto/aes.c b/axTLS/src/crypto/aes.c deleted file mode 100644 index 9b07e27..0000000 --- a/axTLS/src/crypto/aes.c +++ /dev/null @@ -1,457 +0,0 @@ -/* - * 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" - -/* 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/axTLS/src/crypto/bigint.c b/axTLS/src/crypto/bigint.c deleted file mode 100644 index e9ca04c..0000000 --- a/axTLS/src/crypto/bigint.c +++ /dev/null @@ -1,1512 +0,0 @@ -/* - * 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("\n"); -} -#endif - -/** - * @brief Take a bigint and convert it into a byte sequence. - * - * This is useful after a decrypt operation. - * @param ctx [in] The bigint session context. - * @param x [in] The bigint to be converted. - * @param data [out] The converted data as a byte stream. - * @param size [in] The maximum size of the byte stream. Unused bytes will be - * zeroed. - */ -void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size) -{ - int i, j, k = size-1; - - check(x); - memset(data, 0, size); /* ensure all leading 0's are cleared */ - - for (i = 0; i < x->size; i++) - { - for (j = 0; j < COMP_BYTE_SIZE; j++) - { - comp mask = 0xff << (j*8); - int num = (x->comps[i] & mask) >> (j*8); - data[k--] = num; - - if (k < 0) - { - goto buf_done; - } - } - } -buf_done: - - bi_free(ctx, x); -} - -/** - * @brief Pre-calculate some of the expensive steps in reduction. - * - * This function should only be called once (normally when a session starts). - * When the session is over, bi_free_mod() should be called. bi_mod_power() - * relies on this function being called. - * @param ctx [in] The bigint session context. - * @param bim [in] The bigint modulus that will be used. - * @param mod_offset [in] There are three moduluii that can be stored - the - * standard modulus, and its two primes p and q. This offset refers to which - * modulus we are referring to. - * @see bi_free_mod(), bi_mod_power(). - */ -void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset) -{ - int k = bim->size; - comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1)); -#ifdef CONFIG_BIGINT_MONTGOMERY - bigint *R, *R2; -#endif - - ctx->bi_mod[mod_offset] = bim; - bi_permanent(ctx->bi_mod[mod_offset]); - ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d); - bi_permanent(ctx->bi_normalised_mod[mod_offset]); - -#if defined(CONFIG_BIGINT_MONTGOMERY) - /* set montgomery variables */ - R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k-1); /* R */ - R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k*2-1); /* R^2 */ - ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2); /* R^2 mod m */ - ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R); /* R mod m */ - - bi_permanent(ctx->bi_RR_mod_m[mod_offset]); - bi_permanent(ctx->bi_R_mod_m[mod_offset]); - - ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]); - -#elif defined (CONFIG_BIGINT_BARRETT) - ctx->bi_mu[mod_offset] = - bi_divide(ctx, comp_left_shift( - bi_clone(ctx, ctx->bi_radix), k*2-1), ctx->bi_mod[mod_offset], 0); - bi_permanent(ctx->bi_mu[mod_offset]); -#endif -} - -/** - * @brief Used when cleaning various bigints at the end of a session. - * @param ctx [in] The bigint session context. - * @param mod_offset [in] The offset to use. - * @see bi_set_mod(). - */ -void bi_free_mod(BI_CTX *ctx, int mod_offset) -{ - bi_depermanent(ctx->bi_mod[mod_offset]); - bi_free(ctx, ctx->bi_mod[mod_offset]); -#if defined (CONFIG_BIGINT_MONTGOMERY) - bi_depermanent(ctx->bi_RR_mod_m[mod_offset]); - bi_depermanent(ctx->bi_R_mod_m[mod_offset]); - bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]); - bi_free(ctx, ctx->bi_R_mod_m[mod_offset]); -#elif defined(CONFIG_BIGINT_BARRETT) - bi_depermanent(ctx->bi_mu[mod_offset]); - bi_free(ctx, ctx->bi_mu[mod_offset]); -#endif - bi_depermanent(ctx->bi_normalised_mod[mod_offset]); - bi_free(ctx, ctx->bi_normalised_mod[mod_offset]); -} - -/** - * Perform a standard multiplication between two bigints. - * - * Barrett reduction has no need for some parts of the product, so ignore bits - * of the multiply. This routine gives Barrett its big performance - * improvements over Classical/Montgomery reduction methods. - */ -static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, - int inner_partial, int outer_partial) -{ - int i = 0, j; - int n = bia->size; - int t = bib->size; - bigint *biR = alloc(ctx, n + t); - comp *sr = biR->comps; - comp *sa = bia->comps; - comp *sb = bib->comps; - - check(bia); - check(bib); - - /* clear things to start with */ - memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE)); - - do - { - long_comp tmp; - comp carry = 0; - int r_index = i; - j = 0; - - if (outer_partial && outer_partial-i > 0 && outer_partial < n) - { - r_index = outer_partial-1; - j = outer_partial-i-1; - } - - do - { - if (inner_partial && r_index >= inner_partial) - { - break; - } - - tmp = sr[r_index] + ((long_comp)sa[j])*sb[i] + carry; - sr[r_index++] = (comp)tmp; /* downsize */ - carry = tmp >> COMP_BIT_SIZE; - } while (++j < n); - - sr[r_index] = carry; - } while (++i < t); - - bi_free(ctx, bia); - bi_free(ctx, bib); - return trim(biR); -} - -#ifdef CONFIG_BIGINT_KARATSUBA -/* - * Karatsuba improves on regular multiplication due to only 3 multiplications - * being done instead of 4. The additional additions/subtractions are O(N) - * rather than O(N^2) and so for big numbers it saves on a few operations - */ -static bigint *karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square) -{ - bigint *x0, *x1; - bigint *p0, *p1, *p2; - int m; - - if (is_square) - { - m = (bia->size + 1)/2; - } - else - { - m = (max(bia->size, bib->size) + 1)/2; - } - - x0 = bi_clone(ctx, bia); - x0->size = m; - x1 = bi_clone(ctx, bia); - comp_right_shift(x1, m); - bi_free(ctx, bia); - - /* work out the 3 partial products */ - if (is_square) - { - p0 = bi_square(ctx, bi_copy(x0)); - p2 = bi_square(ctx, bi_copy(x1)); - p1 = bi_square(ctx, bi_add(ctx, x0, x1)); - } - else /* normal multiply */ - { - bigint *y0, *y1; - y0 = bi_clone(ctx, bib); - y0->size = m; - y1 = bi_clone(ctx, bib); - comp_right_shift(y1, m); - bi_free(ctx, bib); - - p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0)); - p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1)); - p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1)); - } - - p1 = bi_subtract(ctx, - bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), NULL); - - comp_left_shift(p1, m); - comp_left_shift(p2, 2*m); - return bi_add(ctx, p1, bi_add(ctx, p0, p2)); -} -#endif - -/** - * @brief Perform a multiplication operation between two bigints. - * @param ctx [in] The bigint session context. - * @param bia [in] A bigint. - * @param bib [in] Another bigint. - * @return The result of the multiplication. - */ -bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib) -{ - check(bia); - check(bib); - -#ifdef CONFIG_BIGINT_KARATSUBA - if (min(bia->size, bib->size) < MUL_KARATSUBA_THRESH) - { - return regular_multiply(ctx, bia, bib, 0, 0); - } - - return karatsuba(ctx, bia, bib, 0); -#else - return regular_multiply(ctx, bia, bib, 0, 0); -#endif -} - -#ifdef CONFIG_BIGINT_SQUARE -/* - * Perform the actual square operion. It takes into account overflow. - */ -static bigint *regular_square(BI_CTX *ctx, bigint *bi) -{ - int t = bi->size; - int i = 0, j; - bigint *biR = alloc(ctx, t*2+1); - comp *w = biR->comps; - comp *x = bi->comps; - long_comp carry; - memset(w, 0, biR->size*COMP_BYTE_SIZE); - - do - { - long_comp tmp = w[2*i] + (long_comp)x[i]*x[i]; - w[2*i] = (comp)tmp; - carry = tmp >> COMP_BIT_SIZE; - - for (j = i+1; j < t; j++) - { - uint8_t c = 0; - long_comp xx = (long_comp)x[i]*x[j]; - if ((COMP_MAX-xx) < xx) - c = 1; - - tmp = (xx<<1); - - if ((COMP_MAX-tmp) < w[i+j]) - c = 1; - - tmp += w[i+j]; - - if ((COMP_MAX-tmp) < carry) - c = 1; - - tmp += carry; - w[i+j] = (comp)tmp; - carry = tmp >> COMP_BIT_SIZE; - - if (c) - carry += COMP_RADIX; - } - - tmp = w[i+t] + carry; - w[i+t] = (comp)tmp; - w[i+t+1] = tmp >> COMP_BIT_SIZE; - } while (++i < t); - - bi_free(ctx, bi); - return trim(biR); -} - -/** - * @brief Perform a square operation on a bigint. - * @param ctx [in] The bigint session context. - * @param bia [in] A bigint. - * @return The result of the multiplication. - */ -bigint *bi_square(BI_CTX *ctx, bigint *bia) -{ - check(bia); - -#ifdef CONFIG_BIGINT_KARATSUBA - if (bia->size < SQU_KARATSUBA_THRESH) - { - return regular_square(ctx, bia); - } - - return karatsuba(ctx, bia, NULL, 1); -#else - return regular_square(ctx, bia); -#endif -} -#endif - -/** - * @brief Compare two bigints. - * @param bia [in] A bigint. - * @param bib [in] Another bigint. - * @return -1 if smaller, 1 if larger and 0 if equal. - */ -int bi_compare(bigint *bia, bigint *bib) -{ - int r, i; - - check(bia); - check(bib); - - if (bia->size > bib->size) - r = 1; - else if (bia->size < bib->size) - r = -1; - else - { - comp *a = bia->comps; - comp *b = bib->comps; - - /* Same number of components. Compare starting from the high end - * and working down. */ - r = 0; - i = bia->size - 1; - - do - { - if (a[i] > b[i]) - { - r = 1; - break; - } - else if (a[i] < b[i]) - { - r = -1; - break; - } - } while (--i >= 0); - } - - return r; -} - -/* - * Allocate and zero more components. Does not consume bi. - */ -static void more_comps(bigint *bi, int n) -{ - if (n > bi->max_comps) - { - bi->max_comps = max(bi->max_comps * 2, n); - bi->comps = (comp*)realloc(bi->comps, bi->max_comps * COMP_BYTE_SIZE); - } - - if (n > bi->size) - { - memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE); - } - - bi->size = n; -} - -/* - * Make a new empty bigint. It may just use an old one if one is available. - * Otherwise get one off the heap. - */ -static bigint *alloc(BI_CTX *ctx, int size) -{ - bigint *biR; - - /* Can we recycle an old bigint? */ - if (ctx->free_list != NULL) - { - biR = ctx->free_list; - ctx->free_list = biR->next; - ctx->free_count--; - - if (biR->refs != 0) - { -#ifdef CONFIG_SSL_FULL_MODE - printf("alloc: refs was not 0\n"); -#endif - abort(); /* create a stack trace from a core dump */ - } - - more_comps(biR, size); - } - else - { - /* No free bigints available - create a new one. */ - biR = (bigint *)malloc(sizeof(bigint)); - biR->comps = (comp*)malloc(size * COMP_BYTE_SIZE); - biR->max_comps = size; /* give some space to spare */ - } - - biR->size = size; - biR->refs = 1; - biR->next = NULL; - ctx->active_count++; - return biR; -} - -/* - * Work out the highest '1' bit in an exponent. Used when doing sliding-window - * exponentiation. - */ -static int find_max_exp_index(bigint *biexp) -{ - int i = COMP_BIT_SIZE-1; - comp shift = COMP_RADIX/2; - comp test = biexp->comps[biexp->size-1]; /* assume no leading zeroes */ - - check(biexp); - - do - { - if (test & shift) - { - return i+(biexp->size-1)*COMP_BIT_SIZE; - } - - shift >>= 1; - } while (i-- != 0); - - return -1; /* error - must have been a leading 0 */ -} - -/* - * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window - * exponentiation. - */ -static int exp_bit_is_one(bigint *biexp, int offset) -{ - comp test = biexp->comps[offset / COMP_BIT_SIZE]; - int num_shifts = offset % COMP_BIT_SIZE; - comp shift = 1; - int i; - - check(biexp); - - for (i = 0; i < num_shifts; i++) - { - shift <<= 1; - } - - return (test & shift) != 0; -} - -#ifdef CONFIG_BIGINT_CHECK_ON -/* - * Perform a sanity check on bi. - */ -static void check(const bigint *bi) -{ - if (bi->refs <= 0) - { - printf("check: zero or negative refs in bigint\n"); - abort(); - } - - if (bi->next != NULL) - { - printf("check: attempt to use a bigint from " - "the free list\n"); - abort(); - } -} -#endif - -/* - * Delete any leading 0's (and allow for 0). - */ -static bigint *trim(bigint *bi) -{ - check(bi); - - while (bi->comps[bi->size-1] == 0 && bi->size > 1) - { - bi->size--; - } - - return bi; -} - -#if defined(CONFIG_BIGINT_MONTGOMERY) -/** - * @brief Perform a single montgomery reduction. - * @param ctx [in] The bigint session context. - * @param bixy [in] A bigint. - * @return The result of the montgomery reduction. - */ -bigint *bi_mont(BI_CTX *ctx, bigint *bixy) -{ - int i = 0, n; - uint8_t mod_offset = ctx->mod_offset; - bigint *bim = ctx->bi_mod[mod_offset]; - comp mod_inv = ctx->N0_dash[mod_offset]; - - check(bixy); - - if (ctx->use_classical) /* just use classical instead */ - { - return bi_mod(ctx, bixy); - } - - n = bim->size; - - do - { - bixy = bi_add(ctx, bixy, comp_left_shift( - bi_int_multiply(ctx, bim, bixy->comps[i]*mod_inv), i)); - } while (++i < n); - - comp_right_shift(bixy, n); - - if (bi_compare(bixy, bim) >= 0) - { - bixy = bi_subtract(ctx, bixy, bim, NULL); - } - - return bixy; -} - -#elif defined(CONFIG_BIGINT_BARRETT) -/* - * Stomp on the most significant components to give the illusion of a "mod base - * radix" operation - */ -static bigint *comp_mod(bigint *bi, int mod) -{ - check(bi); - - if (bi->size > mod) - { - bi->size = mod; - } - - return bi; -} - -/** - * @brief Perform a single Barrett reduction. - * @param ctx [in] The bigint session context. - * @param bi [in] A bigint. - * @return The result of the Barrett reduction. - */ -bigint *bi_barrett(BI_CTX *ctx, bigint *bi) -{ - bigint *q1, *q2, *q3, *r1, *r2, *r; - uint8_t mod_offset = ctx->mod_offset; - bigint *bim = ctx->bi_mod[mod_offset]; - int k = bim->size; - - check(bi); - check(bim); - - /* use Classical method instead - Barrett cannot help here */ - if (bi->size > k*2) - { - return bi_mod(ctx, bi); - } - - q1 = comp_right_shift(bi_clone(ctx, bi), k-1); - - /* do outer partial multiply */ - q2 = regular_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k-1); - q3 = comp_right_shift(q2, k+1); - r1 = comp_mod(bi, k+1); - - /* do inner partial multiply */ - r2 = comp_mod(regular_multiply(ctx, q3, bim, k+1, 0), k+1); - r = bi_subtract(ctx, r1, r2, NULL); - - /* if (r >= m) r = r - m; */ - if (bi_compare(r, bim) >= 0) - { - r = bi_subtract(ctx, r, bim, NULL); - } - - return r; -} -#endif /* CONFIG_BIGINT_BARRETT */ - -#ifdef CONFIG_BIGINT_SLIDING_WINDOW -/* - * Work out g1, g3, g5, g7... etc for the sliding-window algorithm - */ -static void precompute_slide_window(BI_CTX *ctx, int window, bigint *g1) -{ - int k = 1, i; - bigint *g2; - - for (i = 0; i < window-1; i++) /* compute 2^(window-1) */ - { - k <<= 1; - } - - ctx->g = (bigint **)malloc(k*sizeof(bigint *)); - ctx->g[0] = bi_clone(ctx, g1); - bi_permanent(ctx->g[0]); - g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0])); /* g^2 */ - - for (i = 1; i < k; i++) - { - ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i-1], bi_copy(g2))); - bi_permanent(ctx->g[i]); - } - - bi_free(ctx, g2); - ctx->window = k; -} -#endif - -/** - * @brief Perform a modular exponentiation. - * - * This function requires bi_set_mod() to have been called previously. This is - * one of the optimisations used for performance. - * @param ctx [in] The bigint session context. - * @param bi [in] The bigint on which to perform the mod power operation. - * @param biexp [in] The bigint exponent. - * @return The result of the mod exponentiation operation - * @see bi_set_mod(). - */ -bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) -{ - int i = find_max_exp_index(biexp), j, window_size = 1; - bigint *biR = int_to_bi(ctx, 1); - -#if defined(CONFIG_BIGINT_MONTGOMERY) - uint8_t mod_offset = ctx->mod_offset; - if (!ctx->use_classical) - { - /* preconvert */ - bi = bi_mont(ctx, - bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset])); /* x' */ - bi_free(ctx, biR); - biR = ctx->bi_R_mod_m[mod_offset]; /* A */ - } -#endif - - check(bi); - check(biexp); - -#ifdef CONFIG_BIGINT_SLIDING_WINDOW - for (j = i; j > 32; j /= 5) /* work out an optimum size */ - window_size++; - - /* work out the slide constants */ - precompute_slide_window(ctx, window_size, bi); -#else /* just one constant */ - ctx->g = (bigint **)malloc(sizeof(bigint *)); - ctx->g[0] = bi_clone(ctx, bi); - ctx->window = 1; - bi_permanent(ctx->g[0]); -#endif - - /* if sliding-window is off, then only one bit will be done at a time and - * will reduce to standard left-to-right exponentiation */ - do - { - if (exp_bit_is_one(biexp, i)) - { - int l = i-window_size+1; - int part_exp = 0; - - if (l < 0) /* LSB of exponent will always be 1 */ - l = 0; - else - { - while (exp_bit_is_one(biexp, l) == 0) - l++; /* go back up */ - } - - /* build up the section of the exponent */ - for (j = i; j >= l; j--) - { - biR = bi_residue(ctx, bi_square(ctx, biR)); - if (exp_bit_is_one(biexp, j)) - part_exp++; - - if (j != l) - part_exp <<= 1; - } - - part_exp = (part_exp-1)/2; /* adjust for array */ - biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp])); - i = l-1; - } - else /* square it */ - { - biR = bi_residue(ctx, bi_square(ctx, biR)); - i--; - } - } while (i >= 0); - - /* cleanup */ - for (i = 0; i < ctx->window; i++) - { - bi_depermanent(ctx->g[i]); - bi_free(ctx, ctx->g[i]); - } - - free(ctx->g); - bi_free(ctx, bi); - bi_free(ctx, biexp); -#if defined CONFIG_BIGINT_MONTGOMERY - return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */ -#else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */ - return biR; -#endif -} - -#ifdef CONFIG_SSL_CERT_VERIFICATION -/** - * @brief Perform a modular exponentiation using a temporary modulus. - * - * We need this function to check the signatures of certificates. The modulus - * of this function is temporary as it's just used for authentication. - * @param ctx [in] The bigint session context. - * @param bi [in] The bigint to perform the exp/mod. - * @param bim [in] The temporary modulus. - * @param biexp [in] The bigint exponent. - * @return The result of the mod exponentiation operation - * @see bi_set_mod(). - */ -bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp) -{ - bigint *biR, *tmp_biR; - - /* Set up a temporary bigint context and transfer what we need between - * them. We need to do this since we want to keep the original modulus - * which is already in this context. This operation is only called when - * doing peer verification, and so is not expensive :-) */ - BI_CTX *tmp_ctx = bi_initialize(); - bi_set_mod(tmp_ctx, bi_clone(tmp_ctx, bim), BIGINT_M_OFFSET); - tmp_biR = bi_mod_power(tmp_ctx, - bi_clone(tmp_ctx, bi), - bi_clone(tmp_ctx, biexp)); - biR = bi_clone(ctx, tmp_biR); - bi_free(tmp_ctx, tmp_biR); - bi_free_mod(tmp_ctx, BIGINT_M_OFFSET); - bi_terminate(tmp_ctx); - - bi_free(ctx, bi); - bi_free(ctx, bim); - bi_free(ctx, biexp); - return biR; -} -#endif - -#ifdef CONFIG_BIGINT_CRT -/** - * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts. - * - * @param ctx [in] The bigint session context. - * @param bi [in] The bigint to perform the exp/mod. - * @param dP [in] CRT's dP bigint - * @param dQ [in] CRT's dQ bigint - * @param p [in] CRT's p bigint - * @param q [in] CRT's q bigint - * @param qInv [in] CRT's qInv bigint - * @return The result of the CRT operation - */ -bigint *bi_crt(BI_CTX *ctx, bigint *bi, - bigint *dP, bigint *dQ, - bigint *p, bigint *q, bigint *qInv) -{ - bigint *m1, *m2, *h; - - /* Montgomery has a condition the 0 < x, y < m and these products violate - * that condition. So disable Montgomery when using CRT */ -#if defined(CONFIG_BIGINT_MONTGOMERY) - ctx->use_classical = 1; -#endif - ctx->mod_offset = BIGINT_P_OFFSET; - m1 = bi_mod_power(ctx, bi_copy(bi), dP); - - ctx->mod_offset = BIGINT_Q_OFFSET; - m2 = bi_mod_power(ctx, bi, dQ); - - h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL); - h = bi_multiply(ctx, h, qInv); - ctx->mod_offset = BIGINT_P_OFFSET; - h = bi_residue(ctx, h); -#if defined(CONFIG_BIGINT_MONTGOMERY) - ctx->use_classical = 0; /* reset for any further operation */ -#endif - return bi_add(ctx, m2, bi_multiply(ctx, q, h)); -} -#endif -/** @} */ diff --git a/axTLS/src/crypto/bigint.h b/axTLS/src/crypto/bigint.h deleted file mode 100644 index 2966a3e..0000000 --- a/axTLS/src/crypto/bigint.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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/axTLS/src/crypto/bigint_impl.h b/axTLS/src/crypto/bigint_impl.h deleted file mode 100644 index d6e70d2..0000000 --- a/axTLS/src/crypto/bigint_impl.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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 _MSC_VER -#define COMP_RADIX 4294967296i64 -#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64 -#else -#define COMP_RADIX 4294967296ULL /**< Max component + 1 */ -#define COMP_MAX 0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */ -#endif -#define COMP_BIT_SIZE 32 /**< Number of bits in a component. */ -#define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */ -#define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */ -typedef uint32_t comp; /**< A single precision component. */ -typedef uint64_t long_comp; /**< A double precision component. */ -typedef int64_t slong_comp; /**< A signed double precision component. */ -#endif - -/** - * @struct _bigint - * @brief A big integer basic object - */ -struct _bigint -{ - struct _bigint* next; /**< The next bigint in the cache. */ - short size; /**< The number of components in this bigint. */ - short max_comps; /**< The heapsize allocated for this bigint */ - int refs; /**< An internal reference count. */ - comp* comps; /**< A ptr to the actual component data */ -}; - -typedef struct _bigint bigint; /**< An alias for _bigint */ - -/** - * Maintains the state of the cache, and a number of variables used in - * reduction. - */ -typedef struct /**< A big integer "session" context. */ -{ - bigint *active_list; /**< Bigints currently used. */ - bigint *free_list; /**< Bigints not used. */ - bigint *bi_radix; /**< The radix used. */ - bigint *bi_mod[BIGINT_NUM_MODS]; /**< modulus */ - -#if defined(CONFIG_BIGINT_MONTGOMERY) - bigint *bi_RR_mod_m[BIGINT_NUM_MODS]; /**< R^2 mod m */ - bigint *bi_R_mod_m[BIGINT_NUM_MODS]; /**< R mod m */ - comp N0_dash[BIGINT_NUM_MODS]; -#elif defined(CONFIG_BIGINT_BARRETT) - bigint *bi_mu[BIGINT_NUM_MODS]; /**< Storage for mu */ -#endif - bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */ - bigint **g; /**< Used by sliding-window. */ - int window; /**< The size of the sliding window */ - int active_count; /**< Number of active bigints. */ - int free_count; /**< Number of free bigints. */ - -#ifdef CONFIG_BIGINT_MONTGOMERY - uint8_t use_classical; /**< Use classical reduction. */ -#endif - uint8_t mod_offset; /**< The mod offset we are using */ -} BI_CTX; - -#ifndef WIN32 -#define max(a,b) ((a)>(b)?(a):(b)) /**< Find the maximum of 2 numbers. */ -#define min(a,b) ((a)<(b)?(a):(b)) /**< Find the minimum of 2 numbers. */ -#endif - -#define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */ - -#endif diff --git a/axTLS/src/crypto/crypto.h b/axTLS/src/crypto/crypto.h deleted file mode 100644 index c6f186c..0000000 --- a/axTLS/src/crypto/crypto.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (c) 2007, Cameron Rich - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the axTLS project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file crypto.h - */ - -#ifndef HEADER_CRYPTO_H -#define HEADER_CRYPTO_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "config.h" -#include "bigint_impl.h" -#include "bigint.h" - -#ifndef STDCALL -#define STDCALL -#endif -#ifndef EXP_FUNC -#define EXP_FUNC -#endif - - -/* enable features based on a 'super-set' capbaility. */ -#if defined(CONFIG_SSL_FULL_MODE) -#define CONFIG_SSL_ENABLE_CLIENT -#define CONFIG_SSL_CERT_VERIFICATION -#elif defined(CONFIG_SSL_ENABLE_CLIENT) -#define CONFIG_SSL_CERT_VERIFICATION -#endif - -/************************************************************************** - * AES declarations - **************************************************************************/ - -#define AES_MAXROUNDS 14 -#define AES_BLOCKSIZE 16 -#define AES_IV_SIZE 16 - -typedef struct aes_key_st -{ - uint16_t rounds; - uint16_t key_size; - uint32_t ks[(AES_MAXROUNDS+1)*8]; - uint8_t iv[AES_IV_SIZE]; -} AES_CTX; - -typedef enum -{ - AES_MODE_128, - AES_MODE_256 -} AES_MODE; - -void AES_set_key(AES_CTX *ctx, const uint8_t *key, - const uint8_t *iv, AES_MODE mode); -void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, - uint8_t *out, int length); -void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length); -void AES_convert_key(AES_CTX *ctx); - -/************************************************************************** - * RC4 declarations - **************************************************************************/ - -typedef struct -{ - uint8_t x, y, m[256]; -} RC4_CTX; - -void RC4_setup(RC4_CTX *s, const uint8_t *key, int length); -void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length); - -/************************************************************************** - * SHA1 declarations - **************************************************************************/ - -#define SHA1_SIZE 20 - -/* - * This structure will hold context information for the SHA-1 - * hashing operation - */ -typedef struct -{ - uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */ - uint32_t Length_Low; /* Message length in bits */ - uint32_t Length_High; /* Message length in bits */ - uint16_t Message_Block_Index; /* Index into message block array */ - uint8_t Message_Block[64]; /* 512-bit message blocks */ -} SHA1_CTX; - -void SHA1_Init(SHA1_CTX *); -void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len); -void SHA1_Final(uint8_t *digest, SHA1_CTX *); - -/************************************************************************** - * MD2 declarations - **************************************************************************/ - -#define MD2_SIZE 16 - -typedef struct -{ - unsigned char cksum[16]; /* checksum of the data block */ - unsigned char state[48]; /* intermediate digest state */ - unsigned char buffer[16]; /* data block being processed */ - int left; /* amount of data in buffer */ -} MD2_CTX; - -EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx); -EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen); -EXP_FUNC void STDCALL MD2_Final(uint8_t *digest, MD2_CTX *ctx); - -/************************************************************************** - * MD5 declarations - **************************************************************************/ - -#define MD5_SIZE 16 - -typedef struct -{ - uint32_t state[4]; /* state (ABCD) */ - uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ - uint8_t buffer[64]; /* input buffer */ -} MD5_CTX; - -EXP_FUNC void STDCALL MD5_Init(MD5_CTX *); -EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len); -EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *); - -/************************************************************************** - * HMAC declarations - **************************************************************************/ -void hmac_md5(const uint8_t *msg, int length, const uint8_t *key, - int key_len, uint8_t *digest); -void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, - int key_len, uint8_t *digest); - -/************************************************************************** - * RSA declarations - **************************************************************************/ - -typedef struct -{ - bigint *m; /* modulus */ - bigint *e; /* public exponent */ - bigint *d; /* private exponent */ -#ifdef CONFIG_BIGINT_CRT - bigint *p; /* p as in m = pq */ - bigint *q; /* q as in m = pq */ - bigint *dP; /* d mod (p-1) */ - bigint *dQ; /* d mod (q-1) */ - bigint *qInv; /* q^-1 mod p */ -#endif - int num_octets; - BI_CTX *bi_ctx; -} RSA_CTX; - -void RSA_priv_key_new(RSA_CTX **rsa_ctx, - const uint8_t *modulus, int mod_len, - const uint8_t *pub_exp, int pub_len, - const uint8_t *priv_exp, int priv_len -#ifdef CONFIG_BIGINT_CRT - , const uint8_t *p, int p_len, - const uint8_t *q, int q_len, - const uint8_t *dP, int dP_len, - const uint8_t *dQ, int dQ_len, - const uint8_t *qInv, int qInv_len -#endif - ); -void RSA_pub_key_new(RSA_CTX **rsa_ctx, - const uint8_t *modulus, int mod_len, - const uint8_t *pub_exp, int pub_len); -void RSA_free(RSA_CTX *ctx); -int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, - int is_decryption); -bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg); -#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT) -bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, - bigint *modulus, bigint *pub_exp); -bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg); -int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, - uint8_t *out_data, int is_signing); -void RSA_print(const RSA_CTX *ctx); -#endif - -/************************************************************************** - * RNG declarations - **************************************************************************/ -EXP_FUNC void STDCALL RNG_initialize(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/axTLS/src/crypto/crypto_misc.c b/axTLS/src/crypto/crypto_misc.c deleted file mode 100644 index 8e7cbf9..0000000 --- a/axTLS/src/crypto/crypto_misc.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * 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 "crypto_misc.h" -#ifdef CONFIG_WIN32_USE_CRYPTO_LIB -#include "wincrypt.h" -#endif - -#ifndef WIN32 -static int rng_fd = -1; -#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB) -static HCRYPTPROV gCryptProv; -#endif - -#if (!defined(CONFIG_USE_DEV_URANDOM) && !defined(CONFIG_WIN32_USE_CRYPTO_LIB)) -/* change to processor registers as appropriate */ -#define ENTROPY_POOL_SIZE 32 -#define ENTROPY_COUNTER1 ((((uint64_t)tv.tv_sec)<<32) | tv.tv_usec) -#define ENTROPY_COUNTER2 rand() -static uint8_t entropy_pool[ENTROPY_POOL_SIZE]; -#endif - -static int rng_ref_count; -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(const uint8_t *seed_buf, int size) -{ - if (rng_ref_count == 0) - { -#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 - int i; - uint32_t seed_addr_val = (uint32_t)&seed_buf; - uint32_t *ep = (uint32_t *)entropy_pool; - - /* help start the entropy with the user's private key - this is - a number that should be hard to find, due to the fact that it - relies on knowing the private key */ - memcpy(entropy_pool, seed_buf, ENTROPY_POOL_SIZE); - srand((long)entropy_pool); - - /* mix it up a little with a stack address */ - for (i = 0; i < ENTROPY_POOL_SIZE/4; i++) - ep[i] ^= seed_addr_val; - -#endif - } - - rng_ref_count++; -} - -/** - * Terminate the RNG engine. - */ -EXP_FUNC void STDCALL RNG_terminate(void) -{ - if (--rng_ref_count == 0) - { -#ifndef WIN32 - close(rng_fd); -#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB) - CryptReleaseContext(gCryptProv, 0); -#endif - } -} - -/** - * Set a series of bytes with a random number. Individual bytes can be 0 - */ -EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data) -{ -#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM) - /* use the Linux default */ - read(rng_fd, rand_data, num_rand_bytes); /* read from /dev/urandom */ -#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB) - /* use Microsoft Crypto Libraries */ - CryptGenRandom(gCryptProv, num_rand_bytes, rand_data); -#else /* nothing else to use, so use a custom RNG */ - /* The method we use when we've got nothing better. Use RC4, time - and a couple of random seeds to generate a random sequence */ - RC4_CTX rng_ctx; - struct timeval tv; - MD5_CTX rng_digest_ctx; - uint8_t digest[MD5_SIZE]; - uint64_t *ep; - int i; - - /* A proper implementation would use counters etc for entropy */ - gettimeofday(&tv, NULL); - ep = (uint64_t *)entropy_pool; - ep[0] ^= ENTROPY_COUNTER1; - ep[1] ^= ENTROPY_COUNTER2; - - /* use a digested version of the entropy pool as a key */ - MD5_Init(&rng_digest_ctx); - MD5_Update(&rng_digest_ctx, entropy_pool, ENTROPY_POOL_SIZE); - MD5_Final(digest, &rng_digest_ctx); - - /* come up with the random sequence */ - RC4_setup(&rng_ctx, digest, MD5_SIZE); /* use as a key */ - memcpy(rand_data, entropy_pool, num_rand_bytes < ENTROPY_POOL_SIZE ? - num_rand_bytes : ENTROPY_POOL_SIZE); - RC4_crypt(&rng_ctx, rand_data, rand_data, num_rand_bytes); - - /* move things along */ - for (i = ENTROPY_POOL_SIZE-1; i >= MD5_SIZE ; i--) - entropy_pool[i] = entropy_pool[i-MD5_SIZE]; - - /* insert the digest at the start of the entropy pool */ - memcpy(entropy_pool, digest, MD5_SIZE); -#endif -} - -/** - * Set a series of bytes with a random number. Individual bytes are not zero. - */ -void get_random_NZ(int num_rand_bytes, uint8_t *rand_data) -{ - int i; - get_random(num_rand_bytes, rand_data); - - for (i = 0; i < num_rand_bytes; i++) - { - while (rand_data[i] == 0) /* can't be 0 */ - rand_data[i] = (uint8_t)(rand()); - } -} - -/** - * Some useful diagnostic routines - */ -#if defined(CONFIG_SSL_FULL_MODE) || defined(CONFIG_DEBUG) -int hex_finish; -int hex_index; - -static void print_hex_init(int finish) -{ - hex_finish = finish; - hex_index = 0; -} - -static void print_hex(uint8_t hex) -{ - static int column; - - if (hex_index == 0) - { - column = 0; - } - - printf("%02x ", hex); - if (++column == 8) - { - printf(": "); - } - else if (column >= 16) - { - printf("\n"); - column = 0; - } - - if (++hex_index >= hex_finish && column > 0) - { - printf("\n"); - } -} - -/** - * Spit out a blob of data for diagnostics. The data is is a nice column format - * for easy reading. - * - * @param format [in] The string (with possible embedded format characters) - * @param size [in] The number of numbers to print - * @param data [in] The start of data to use - * @param ... [in] Any additional arguments - */ -EXP_FUNC void STDCALL print_blob(const char *format, - const uint8_t *data, int size, ...) -{ - int i; - char tmp[80]; - va_list(ap); - - va_start(ap, size); - sprintf(tmp, "%s\n", format); - vprintf(tmp, ap); - print_hex_init(size); - for (i = 0; i < size; i++) - { - print_hex(data[i]); - } - - va_end(ap); - TTY_FLUSH(); -} -#elif defined(WIN32) -/* VC6.0 doesn't handle variadic macros */ -EXP_FUNC void STDCALL print_blob(const char *format, const unsigned char *data, - int size, ...) {} -#endif - -#if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION) -/* base64 to binary lookup table */ -static const uint8_t map[128] = -{ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, - 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, - 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 255, 255, 255, 255, 255 -}; - -EXP_FUNC int STDCALL base64_decode(const char *in, int len, - uint8_t *out, int *outlen) -{ - int g, t, x, y, z; - uint8_t c; - int ret = -1; - - g = 3; - for (x = y = z = t = 0; x < len; x++) - { - if ((c = map[in[x]&0x7F]) == 0xff) - continue; - - if (c == 254) /* this is the end... */ - { - c = 0; - - if (--g < 0) - goto error; - } - else if (g != 3) /* only allow = at end */ - goto error; - - t = (t<<6) | c; - - if (++y == 4) - { - out[z++] = (uint8_t)((t>>16)&255); - - if (g > 1) - out[z++] = (uint8_t)((t>>8)&255); - - if (g > 2) - out[z++] = (uint8_t)(t&255); - - y = t = 0; - } - } - - if (y != 0) - goto error; - - if (outlen) - *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/axTLS/src/crypto/hmac.c b/axTLS/src/crypto/hmac.c deleted file mode 100644 index 24a04d7..0000000 --- a/axTLS/src/crypto/hmac.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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/axTLS/src/crypto/md2.c b/axTLS/src/crypto/md2.c deleted file mode 100644 index dee909a..0000000 --- a/axTLS/src/crypto/md2.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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" - -/** - * 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/axTLS/src/crypto/md5.c b/axTLS/src/crypto/md5.c deleted file mode 100644 index 7f50713..0000000 --- a/axTLS/src/crypto/md5.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * 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/axTLS/src/crypto/rc4.c b/axTLS/src/crypto/rc4.c deleted file mode 100644 index 12a1211..0000000 --- a/axTLS/src/crypto/rc4.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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/axTLS/src/crypto/rsa.c b/axTLS/src/crypto/rsa.c deleted file mode 100644 index 143e66a..0000000 --- a/axTLS/src/crypto/rsa.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * 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) -{ -#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/axTLS/src/crypto/sha1.c b/axTLS/src/crypto/sha1.c deleted file mode 100644 index 1082733..0000000 --- a/axTLS/src/crypto/sha1.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * 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/axTLS/src/ssl/asn1.c b/axTLS/src/ssl/asn1.c deleted file mode 100644 index cf8d5be..0000000 --- a/axTLS/src/ssl/asn1.c +++ /dev/null @@ -1,565 +0,0 @@ -/* - * 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" - -#define SIG_OID_PREFIX_SIZE 8 -#define SIG_IIS6_OID_SIZE 5 -#define SIG_SUBJECT_ALT_NAME_SIZE 3 - -/* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */ -static const uint8_t sig_oid_prefix[SIG_OID_PREFIX_SIZE] = -{ - 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01 -}; - -static const uint8_t sig_sha1WithRSAEncrypt[SIG_IIS6_OID_SIZE] = -{ - 0x2b, 0x0e, 0x03, 0x02, 0x1d -}; - -static const uint8_t sig_subject_alt_name[SIG_SUBJECT_ALT_NAME_SIZE] = -{ - 0x55, 0x1d, 0x11 -}; - -/* CN, O, OU */ -static const uint8_t g_dn_types[] = { 3, 10, 11 }; - -int get_asn1_length(const uint8_t *buf, int *offset) -{ - int len, i; - - if (!(buf[*offset] & 0x80)) /* short form */ - { - len = buf[(*offset)++]; - } - else /* long form */ - { - int length_bytes = buf[(*offset)++]&0x7f; - len = 0; - for (i = 0; i < length_bytes; i++) - { - len <<= 8; - len += buf[(*offset)++]; - } - } - - return len; -} - -/** - * Skip the ASN1.1 object type and its length. Get ready to read the object's - * data. - */ -int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type) -{ - if (buf[*offset] != obj_type) - return X509_NOT_OK; - (*offset)++; - return get_asn1_length(buf, offset); -} - -/** - * Skip over an ASN.1 object type completely. Get ready to read the next - * object. - */ -int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type) -{ - int len; - - if (buf[*offset] != obj_type) - return X509_NOT_OK; - (*offset)++; - len = get_asn1_length(buf, offset); - *offset += len; - return 0; -} - -/** - * Read an integer value for ASN.1 data - * Note: This function allocates memory which must be freed by the user. - */ -int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object) -{ - int len; - - if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0) - goto end_int_array; - - if (len > 1 && buf[*offset] == 0x00) /* ignore the negative byte */ - { - len--; - (*offset)++; - } - - *object = (uint8_t *)malloc(len); - memcpy(*object, &buf[*offset], len); - *offset += len; - -end_int_array: - return len; -} - -/** - * Get all the RSA private key specifics from an ASN.1 encoded file - */ -int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx) -{ - int offset = 7; - uint8_t *modulus = NULL, *priv_exp = NULL, *pub_exp = NULL; - int mod_len, priv_len, pub_len; -#ifdef CONFIG_BIGINT_CRT - uint8_t *p = NULL, *q = NULL, *dP = NULL, *dQ = NULL, *qInv = NULL; - int p_len, q_len, dP_len, dQ_len, qInv_len; -#endif - - /* not in der format */ - if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */ - { -#ifdef CONFIG_SSL_FULL_MODE - printf("Error: This is not a valid ASN.1 file\n"); -#endif - return X509_INVALID_PRIV_KEY; - } - - /* initialise the RNG */ - RNG_initialize(buf, len); - - mod_len = asn1_get_int(buf, &offset, &modulus); - pub_len = asn1_get_int(buf, &offset, &pub_exp); - priv_len = asn1_get_int(buf, &offset, &priv_exp); - - if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0) - return X509_INVALID_PRIV_KEY; - -#ifdef CONFIG_BIGINT_CRT - p_len = asn1_get_int(buf, &offset, &p); - q_len = asn1_get_int(buf, &offset, &q); - dP_len = asn1_get_int(buf, &offset, &dP); - dQ_len = asn1_get_int(buf, &offset, &dQ); - qInv_len = asn1_get_int(buf, &offset, &qInv); - - if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0) - return X509_INVALID_PRIV_KEY; - - RSA_priv_key_new(rsa_ctx, - modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len, - p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len); - - free(p); - free(q); - free(dP); - free(dQ); - free(qInv); -#else - RSA_priv_key_new(rsa_ctx, - modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len); -#endif - - free(modulus); - free(priv_exp); - free(pub_exp); - return X509_OK; -} - -/** - * Get the time of a certificate. Ignore hours/minutes/seconds. - */ -static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t) -{ - int ret = X509_NOT_OK, len, t_offset; - struct tm tm; - - if (buf[(*offset)++] != ASN1_UTC_TIME) - goto end_utc_time; - - len = get_asn1_length(buf, offset); - t_offset = *offset; - - memset(&tm, 0, sizeof(struct tm)); - tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0'); - - if (tm.tm_year <= 50) /* 1951-2050 thing */ - { - tm.tm_year += 100; - } - - tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1; - tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0'); - *t = mktime(&tm); - *offset += len; - ret = X509_OK; - -end_utc_time: - return ret; -} - -/** - * Get the version type of a certificate (which we don't actually care about) - */ -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; - - /* some certs have this awful crud in them for some reason */ - if (buf[*offset] != ASN1_PRINTABLE_STR && - buf[*offset] != ASN1_PRINTABLE_STR2 && - buf[*offset] != ASN1_TELETEX_STR && - buf[*offset] != ASN1_IA5_STR && - buf[*offset] != ASN1_UNICODE_STR) - goto end_pnt_str; - - (*offset)++; - len = get_asn1_length(buf, offset); - - if (buf[*offset - 1] == 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/axTLS/src/ssl/cert.h b/axTLS/src/ssl/cert.h deleted file mode 100644 index 30c7b65..0000000 --- a/axTLS/src/ssl/cert.h +++ /dev/null @@ -1,43 +0,0 @@ -unsigned char default_certificate[] = { - 0x30, 0x82, 0x01, 0xd7, 0x30, 0x82, 0x01, 0x40, 0x02, 0x09, 0x00, 0xab, - 0x08, 0x18, 0xa7, 0x03, 0x07, 0x27, 0xfd, 0x30, 0x0d, 0x06, 0x09, 0x2a, - 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x34, - 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x29, 0x61, - 0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x20, 0x44, 0x6f, 0x64, 0x67, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x31, 0x32, - 0x32, 0x36, 0x32, 0x32, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x17, 0x0d, 0x32, - 0x34, 0x30, 0x39, 0x30, 0x33, 0x32, 0x32, 0x33, 0x33, 0x33, 0x39, 0x5a, - 0x30, 0x2c, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, - 0x0d, 0x61, 0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, - 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81, - 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, - 0x81, 0x81, 0x00, 0xcd, 0xfd, 0x89, 0x48, 0xbe, 0x36, 0xb9, 0x95, 0x76, - 0xd4, 0x13, 0x30, 0x0e, 0xbf, 0xb2, 0xed, 0x67, 0x0a, 0xc0, 0x16, 0x3f, - 0x51, 0x09, 0x9d, 0x29, 0x2f, 0xb2, 0x6d, 0x3f, 0x3e, 0x6c, 0x2f, 0x90, - 0x80, 0xa1, 0x71, 0xdf, 0xbe, 0x38, 0xc5, 0xcb, 0xa9, 0x9a, 0x40, 0x14, - 0x90, 0x0a, 0xf9, 0xb7, 0x07, 0x0b, 0xe1, 0xda, 0xe7, 0x09, 0xbf, 0x0d, - 0x57, 0x41, 0x86, 0x60, 0xa1, 0xc1, 0x27, 0x91, 0x5b, 0x0a, 0x98, 0x46, - 0x1b, 0xf6, 0xa2, 0x84, 0xf8, 0x65, 0xc7, 0xce, 0x2d, 0x96, 0x17, 0xaa, - 0x91, 0xf8, 0x61, 0x04, 0x50, 0x70, 0xeb, 0xb4, 0x43, 0xb7, 0xdc, 0x9a, - 0xcc, 0x31, 0x01, 0x14, 0xd4, 0xcd, 0xcc, 0xc2, 0x37, 0x6d, 0x69, 0x82, - 0xd6, 0xc6, 0xc4, 0xbe, 0xf2, 0x34, 0xa5, 0xc9, 0xa6, 0x19, 0x53, 0x32, - 0x7a, 0x86, 0x0e, 0x91, 0x82, 0x0f, 0xa1, 0x42, 0x54, 0xaa, 0x01, 0x02, - 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x40, - 0xb4, 0x94, 0x9a, 0xa8, 0x89, 0x72, 0x1d, 0x07, 0xe5, 0xb3, 0x6b, 0x88, - 0x21, 0xc2, 0x38, 0x36, 0x9e, 0x7a, 0x8c, 0x49, 0x48, 0x68, 0x0c, 0x06, - 0xe8, 0xdb, 0x1f, 0x4e, 0x05, 0xe6, 0x31, 0xe3, 0xfd, 0xe6, 0x0d, 0x6b, - 0xd8, 0x13, 0x17, 0xe0, 0x2d, 0x0d, 0xb8, 0x7e, 0xcb, 0x20, 0x6c, 0xa8, - 0x73, 0xa7, 0xfd, 0xe3, 0xa7, 0xfa, 0xf3, 0x02, 0x60, 0x78, 0x1f, 0x13, - 0x40, 0x45, 0xee, 0x75, 0xf5, 0x10, 0xfd, 0x8f, 0x68, 0x74, 0xd4, 0xac, - 0xae, 0x04, 0x09, 0x55, 0x2c, 0xdb, 0xd8, 0x07, 0x07, 0x65, 0x69, 0x27, - 0x6e, 0xbf, 0x5e, 0x61, 0x40, 0x56, 0x8b, 0xd7, 0x33, 0x3b, 0xff, 0x6e, - 0x53, 0x7e, 0x9d, 0x3f, 0xc0, 0x40, 0x3a, 0xab, 0xa0, 0x50, 0x4e, 0x80, - 0x47, 0x46, 0x0d, 0x1e, 0xdb, 0x4c, 0xf1, 0x1b, 0x5d, 0x3c, 0x2a, 0x54, - 0xa7, 0x4d, 0xfa, 0x7b, 0x72, 0x66, 0xc5 -}; -unsigned int default_certificate_len = 475; diff --git a/axTLS/src/ssl/crypto_misc.h b/axTLS/src/ssl/crypto_misc.h deleted file mode 100644 index 9c9e2aa..0000000 --- a/axTLS/src/ssl/crypto_misc.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2007, Cameron Rich - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the axTLS project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/** - * @file crypto_misc.h - */ - -#ifndef HEADER_CRYPTO_MISC_H -#define HEADER_CRYPTO_MISC_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "crypto.h" -#include "bigint.h" - -/************************************************************************** - * X509 declarations - **************************************************************************/ -#define X509_OK 0 -#define X509_NOT_OK -1 -#define X509_VFY_ERROR_NO_TRUSTED_CERT -2 -#define X509_VFY_ERROR_BAD_SIGNATURE -3 -#define X509_VFY_ERROR_NOT_YET_VALID -4 -#define X509_VFY_ERROR_EXPIRED -5 -#define X509_VFY_ERROR_SELF_SIGNED -6 -#define X509_VFY_ERROR_INVALID_CHAIN -7 -#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8 -#define X509_INVALID_PRIV_KEY -9 - -/* - * The Distinguished Name - */ -#define X509_NUM_DN_TYPES 3 -#define X509_COMMON_NAME 0 -#define X509_ORGANIZATION 1 -#define X509_ORGANIZATIONAL_UNIT 2 - -struct _x509_ctx -{ - char *ca_cert_dn[X509_NUM_DN_TYPES]; - char *cert_dn[X509_NUM_DN_TYPES]; - char **subject_alt_dnsnames; - time_t not_before; - time_t not_after; - uint8_t *signature; - uint16_t sig_len; - uint8_t sig_type; - RSA_CTX *rsa_ctx; - bigint *digest; - uint8_t sha1_fingerprint[SHA1_SIZE]; - struct _x509_ctx *next; -}; - -typedef struct _x509_ctx X509_CTX; - -#ifdef CONFIG_SSL_CERT_VERIFICATION -typedef struct -{ - X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS]; -} CA_CERT_CTX; -#endif - -int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx); -void x509_free(X509_CTX *x509_ctx); -#ifdef CONFIG_SSL_CERT_VERIFICATION -int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert); -#endif -#ifdef CONFIG_SSL_FULL_MODE -void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx); -const char * x509_display_error(int error); -#endif - -/************************************************************************** - * ASN1 declarations - **************************************************************************/ -#define ASN1_INTEGER 0x02 -#define ASN1_BIT_STRING 0x03 -#define ASN1_OCTET_STRING 0x04 -#define ASN1_NULL 0x05 -#define ASN1_PRINTABLE_STR2 0x0C -#define ASN1_OID 0x06 -#define ASN1_PRINTABLE_STR2 0x0C -#define ASN1_PRINTABLE_STR 0x13 -#define ASN1_TELETEX_STR 0x14 -#define ASN1_IA5_STR 0x16 -#define ASN1_UTC_TIME 0x17 -#define ASN1_UNICODE_STR 0x1e -#define ASN1_SEQUENCE 0x30 -#define ASN1_CONTEXT_DNSNAME 0x82 -#define ASN1_SET 0x31 -#define ASN1_V3_DATA 0xa3 -#define ASN1_IMPLICIT_TAG 0x80 -#define ASN1_CONTEXT_DNSNAME 0x82 -#define ASN1_EXPLICIT_TAG 0xa0 -#define ASN1_V3_DATA 0xa3 - -#define SIG_TYPE_MD2 0x02 -#define SIG_TYPE_MD5 0x04 -#define SIG_TYPE_SHA1 0x05 - -int get_asn1_length(const uint8_t *buf, int *offset); -int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx); -int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type); -int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type); -int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object); -int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); -int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); -int asn1_name(const uint8_t *cert, int *offset, char *dn[]); -int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); -#ifdef CONFIG_SSL_CERT_VERIFICATION -int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); -int asn1_find_subjectaltname(const uint8_t* cert, int offset); -int asn1_compare_dn(char * const dn1[], char * const dn2[]); -#endif /* CONFIG_SSL_CERT_VERIFICATION */ -int asn1_signature_type(const uint8_t *cert, - int *offset, X509_CTX *x509_ctx); - -/************************************************************************** - * MISC declarations - **************************************************************************/ -#define SALT_SIZE 8 - -extern const char * const unsupported_str; - -typedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int); -typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key, - int key_len, uint8_t *digest); - -int get_file(const char *filename, uint8_t **buf); - -#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG) -EXP_FUNC void STDCALL print_blob(const char *format, const uint8_t *data, int size, ...); -#else - #define print_blob(...) -#endif - -EXP_FUNC int STDCALL base64_decode(const char *in, int len, - uint8_t *out, int *outlen); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/axTLS/src/ssl/gen_cert.c b/axTLS/src/ssl/gen_cert.c deleted file mode 100644 index c2fe381..0000000 --- a/axTLS/src/ssl/gen_cert.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * 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/axTLS/src/ssl/loader.c b/axTLS/src/ssl/loader.c deleted file mode 100644 index 90231f3..0000000 --- a/axTLS/src/ssl/loader.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - * 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" - -static int do_obj(SSL_CTX *ssl_ctx, int obj_type, - SSLObjLoader *ssl_obj, const char *password); -#ifdef CONFIG_SSL_HAS_PEM -static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, - SSLObjLoader *ssl_obj, const char *password); -#endif - -/* - * Load a file into memory that is in binary DER (or ascii PEM) format. - */ -EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, - const char *filename, const char *password) -{ -#ifndef CONFIG_SSL_SKELETON_MODE - static const char * const begin = "-----BEGIN"; - int ret = SSL_OK; - SSLObjLoader *ssl_obj = NULL; - - if (filename == NULL) - { - ret = SSL_ERROR_INVALID_KEY; - goto error; - } - - ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader)); - ssl_obj->len = get_file(filename, &ssl_obj->buf); - if (ssl_obj->len <= 0) - { - ret = SSL_ERROR_INVALID_KEY; - goto error; - } - - /* is the file a PEM file? */ - if (strstr((char *)ssl_obj->buf, begin) != NULL) - { -#ifdef CONFIG_SSL_HAS_PEM - ret = ssl_obj_PEM_load(ssl_ctx, obj_type, ssl_obj, password); -#else - printf(unsupported_str); - ret = SSL_ERROR_NOT_SUPPORTED; -#endif - } - else - ret = do_obj(ssl_ctx, obj_type, ssl_obj, password); - -error: - ssl_obj_free(ssl_obj); - return ret; -#else - printf(unsupported_str); - return SSL_ERROR_NOT_SUPPORTED; -#endif /* CONFIG_SSL_SKELETON_MODE */ -} - -/* - * Transfer binary data into the object loader. - */ -EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int mem_type, - const uint8_t *data, int len, const char *password) -{ - int ret; - SSLObjLoader *ssl_obj; - - ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader)); - ssl_obj->buf = (uint8_t *)malloc(len); - memcpy(ssl_obj->buf, data, len); - ssl_obj->len = len; - ret = do_obj(ssl_ctx, mem_type, ssl_obj, password); - ssl_obj_free(ssl_obj); - return ret; -} - -/* - * Actually work out what we are doing - */ -static int do_obj(SSL_CTX *ssl_ctx, int obj_type, - SSLObjLoader *ssl_obj, const char *password) -{ - int ret = SSL_OK; - - switch (obj_type) - { - case SSL_OBJ_RSA_KEY: - ret = add_private_key(ssl_ctx, ssl_obj); - break; - - case SSL_OBJ_X509_CERT: - ret = add_cert(ssl_ctx, ssl_obj->buf, ssl_obj->len); - break; - -#ifdef CONFIG_SSL_CERT_VERIFICATION - case SSL_OBJ_X509_CACERT: - add_cert_auth(ssl_ctx, ssl_obj->buf, ssl_obj->len); - break; -#endif - -#ifdef CONFIG_SSL_USE_PKCS12 - case SSL_OBJ_PKCS8: - ret = pkcs8_decode(ssl_ctx, ssl_obj, password); - break; - - case SSL_OBJ_PKCS12: - ret = pkcs12_decode(ssl_ctx, ssl_obj, password); - break; -#endif - default: - printf(unsupported_str); - ret = SSL_ERROR_NOT_SUPPORTED; - break; - } - - return ret; -} - -/* - * Clean up our mess. - */ -void ssl_obj_free(SSLObjLoader *ssl_obj) -{ - if (ssl_obj) - { - free(ssl_obj->buf); - free(ssl_obj); - } -} - -/* - * Support for PEM encoded keys/certificates. - */ -#ifdef CONFIG_SSL_HAS_PEM - -#define NUM_PEM_TYPES 4 -#define IV_SIZE 16 -#define IS_RSA_PRIVATE_KEY 0 -#define IS_ENCRYPTED_PRIVATE_KEY 1 -#define IS_PRIVATE_KEY 2 -#define IS_CERTIFICATE 3 - -static const char * const begins[NUM_PEM_TYPES] = -{ - "-----BEGIN RSA PRIVATE KEY-----", - "-----BEGIN ENCRYPTED PRIVATE KEY-----", - "-----BEGIN PRIVATE KEY-----", - "-----BEGIN CERTIFICATE-----", -}; - -static const char * const ends[NUM_PEM_TYPES] = -{ - "-----END RSA PRIVATE KEY-----", - "-----END ENCRYPTED PRIVATE KEY-----", - "-----END PRIVATE KEY-----", - "-----END CERTIFICATE-----", -}; - -static const char * const aes_str[2] = -{ - "DEK-Info: AES-128-CBC,", - "DEK-Info: AES-256-CBC," -}; - -/** - * Take a base64 blob of data and decrypt it (using AES) into its - * proper ASN.1 form. - */ -static int pem_decrypt(const char *where, const char *end, - const char *password, SSLObjLoader *ssl_obj) -{ - int ret = -1; - int is_aes_256 = 0; - char *start = NULL; - uint8_t iv[IV_SIZE]; - int i, pem_size; - MD5_CTX md5_ctx; - AES_CTX aes_ctx; - uint8_t key[32]; /* AES256 size */ - - if (password == NULL || strlen(password) == 0) - { -#ifdef CONFIG_SSL_FULL_MODE - printf("Error: Need a password for this PEM file\n"); TTY_FLUSH(); -#endif - goto error; - } - - if ((start = strstr((const char *)where, aes_str[0]))) /* AES128? */ - { - start += strlen(aes_str[0]); - } - else if ((start = strstr((const char *)where, aes_str[1]))) /* AES256? */ - { - is_aes_256 = 1; - start += strlen(aes_str[1]); - } - else - { -#ifdef CONFIG_SSL_FULL_MODE - printf("Error: Unsupported password cipher\n"); TTY_FLUSH(); -#endif - goto error; - } - - /* convert from hex to binary - assumes uppercase hex */ - for (i = 0; i < IV_SIZE; i++) - { - char c = *start++ - '0'; - iv[i] = (c > 9 ? c + '0' - 'A' + 10 : c) << 4; - c = *start++ - '0'; - iv[i] += (c > 9 ? c + '0' - 'A' + 10 : c); - } - - while (*start == '\r' || *start == '\n') - start++; - - /* turn base64 into binary */ - pem_size = (int)(end-start); - if (base64_decode(start, pem_size, ssl_obj->buf, &ssl_obj->len) != 0) - goto error; - - /* work out the key */ - MD5_Init(&md5_ctx); - MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password)); - MD5_Update(&md5_ctx, iv, SALT_SIZE); - MD5_Final(key, &md5_ctx); - - if (is_aes_256) - { - MD5_Init(&md5_ctx); - MD5_Update(&md5_ctx, key, MD5_SIZE); - MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password)); - MD5_Update(&md5_ctx, iv, SALT_SIZE); - MD5_Final(&key[MD5_SIZE], &md5_ctx); - } - - /* decrypt using the key/iv */ - AES_set_key(&aes_ctx, key, iv, is_aes_256 ? AES_MODE_256 : AES_MODE_128); - AES_convert_key(&aes_ctx); - AES_cbc_decrypt(&aes_ctx, ssl_obj->buf, ssl_obj->buf, ssl_obj->len); - ret = 0; - -error: - return ret; -} - -/** - * Take a base64 blob of data and turn it into its proper ASN.1 form. - */ -static int new_pem_obj(SSL_CTX *ssl_ctx, int is_cacert, char *where, - int remain, const char *password) -{ - int ret = SSL_ERROR_BAD_CERTIFICATE; - SSLObjLoader *ssl_obj = NULL; - - while (remain > 0) - { - int i, pem_size, obj_type; - char *start = NULL, *end = NULL; - - for (i = 0; i < NUM_PEM_TYPES; i++) - { - if ((start = strstr(where, begins[i])) && - (end = strstr(where, ends[i]))) - { - remain -= (int)(end-where); - start += strlen(begins[i]); - pem_size = (int)(end-start); - - ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader)); - - /* 4/3 bigger than what we need but so what */ - ssl_obj->buf = (uint8_t *)calloc(1, pem_size); - - 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 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/axTLS/src/ssl/openssl.c b/axTLS/src/ssl/openssl.c deleted file mode 100644 index 6b5c4d8..0000000 --- a/axTLS/src/ssl/openssl.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * 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/axTLS/src/ssl/os_port.c b/axTLS/src/ssl/os_port.c deleted file mode 100644 index 9859d08..0000000 --- a/axTLS/src/ssl/os_port.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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" - -#ifdef _MSC_VER -/** - * gettimeofday() not in Win32 - */ -EXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone) -{ -#if defined(_WIN32_WCE) - t->tv_sec = time(NULL); - t->tv_usec = 0; /* 1sec precision only */ -#else - struct _timeb timebuffer; - _ftime(&timebuffer); - t->tv_sec = (long)timebuffer.time; - t->tv_usec = 1000 * timebuffer.millitm; /* 1ms precision */ -#endif -} - -/** - * strcasecmp() not in Win32 - */ -EXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2) -{ - while (tolower(*s1) == tolower(*s2++)) - { - if (*s1++ == '\0') - { - return 0; - } - } - - return *(unsigned char *)s1 - *(unsigned char *)(s2 - 1); -} - - -EXP_FUNC int STDCALL getdomainname(char *buf, int buf_size) -{ - HKEY hKey; - unsigned long datatype; - unsigned long bufferlength = buf_size; - - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, - TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), - 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) - return -1; - - RegQueryValueEx(hKey, "Domain", NULL, &datatype, buf, &bufferlength); - RegCloseKey(hKey); - return 0; -} -#endif - -#undef malloc -#undef realloc -#undef calloc - -static const char * out_of_mem_str = "out of memory"; -static const char * file_open_str = "Could not open file \"%s\""; - -/* - * Some functions that call display some error trace and then call abort(). - * This just makes life much easier on embedded systems, since we're - * suffering major trauma... - */ -EXP_FUNC void * STDCALL ax_malloc(size_t s) -{ - void *x; - - if ((x = malloc(s)) == NULL) - exit_now(out_of_mem_str); - - return x; -} - -EXP_FUNC void * STDCALL ax_realloc(void *y, size_t s) -{ - void *x; - - if ((x = realloc(y, s)) == NULL) - exit_now(out_of_mem_str); - - return x; -} - -EXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s) -{ - void *x; - - if ((x = calloc(n, s)) == NULL) - exit_now(out_of_mem_str); - - return x; -} - -EXP_FUNC int STDCALL ax_open(const char *pathname, int flags) -{ - int x; - - if ((x = open(pathname, flags)) < 0) - exit_now(file_open_str, pathname); - - return x; -} - -/** - * This is a call which will deliberately exit an application, but will - * display some information before dying. - */ -void exit_now(const char *format, ...) -{ - va_list argp; - - va_start(argp, format); - vfprintf(stderr, format, argp); - va_end(argp); - abort(); -} - diff --git a/axTLS/src/ssl/os_port.h b/axTLS/src/ssl/os_port.h deleted file mode 100644 index b2924b4..0000000 --- a/axTLS/src/ssl/os_port.h +++ /dev/null @@ -1,208 +0,0 @@ -/*
- * 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 <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.
- */
-#ifdef _MSC_VER
-#pragma comment(lib, "WS2_32.lib")
-#pragma comment(lib, "AdvAPI32.lib")
-
-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;
-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
-#include <stdint.h>
-#endif
-
-#else /* Not Win32 */
-
-#ifdef CONFIG_PLATFORM_SOLARIS
-#include <inttypes.h>
-#else
-#include <stdint.h>
-#endif /* Not Solaris */
-
-#include <unistd.h>
-#include <pwd.h>
-#include <netdb.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <netinet/in.h>
-#include <arpa/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/axTLS/src/ssl/p12.c b/axTLS/src/ssl/p12.c deleted file mode 100644 index 2bafaf7..0000000 --- a/axTLS/src/ssl/p12.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * 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/axTLS/src/ssl/private_key.h b/axTLS/src/ssl/private_key.h deleted file mode 100644 index ce7985c..0000000 --- a/axTLS/src/ssl/private_key.h +++ /dev/null @@ -1,54 +0,0 @@ -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/axTLS/src/ssl/ssl.h b/axTLS/src/ssl/ssl.h deleted file mode 100644 index 198efc6..0000000 --- a/axTLS/src/ssl/ssl.h +++ /dev/null @@ -1,499 +0,0 @@ -/* - * 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(uint32_t options, int num_sessions); - -/** - * @brief Remove a client/server context. - * - * Frees any used resources used by this context. Each connection will be - * sent a "Close Notify" alert (if possible). - * @param ssl_ctx [in] The client/server context. - */ -EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx); - -/** - * @brief (server only) Establish a new SSL connection to an SSL client. - * - * It is up to the application to establish the logical connection (whether it - * is a socket, serial connection etc). - * @param ssl_ctx [in] The server context. - * @param client_fd [in] The client's file descriptor. - * @return An SSL object reference. - */ -EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd); - -/** - * @brief (client only) Establish a new SSL connection to an SSL server. - * - * It is up to the application to establish the initial logical connection - * (whether it is a socket, serial connection etc). - * - * This is a normally a blocking call - it will finish when the handshake is - * complete (or has failed). To use in non-blocking mode, set - * SSL_CONNECT_IN_PARTS in ssl_ctx_new(). - * @param ssl_ctx [in] The client context. - * @param client_fd [in] The client's file descriptor. - * @param session_id [in] A 32 byte session id for session resumption. This - * can be null if no session resumption is being used or required. This option - * is not used in skeleton mode. - * @param sess_id_size The size of the session id (max 32) - * @return An SSL object reference. Use ssl_handshake_status() to check - * if a handshake succeeded. - */ -EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const uint8_t *session_id, uint8_t sess_id_size); - -/** - * @brief Free any used resources on this connection. - - * A "Close Notify" message is sent on this connection (if possible). It is up - * to the application to close the socket or file descriptor. - * @param ssl [in] The ssl object reference. - */ -EXP_FUNC void STDCALL ssl_free(SSL *ssl); - -/** - * @brief Read the SSL data stream. - * If the socket is non-blocking and data is blocked then SSO_OK will be - * returned. - * @param ssl [in] An SSL object reference. - * @param in_data [out] If the read was successful, a pointer to the read - * buffer will be here. Do NOT ever free this memory as this buffer is used in - * sucessive calls. If the call was unsuccessful, this value will be null. - * @return The number of decrypted bytes: - * - if > 0, then the handshaking is complete and we are returning the number - * of decrypted bytes. - * - SSL_OK if the handshaking stage is successful (but not yet complete). - * - < 0 if an error. - * @see ssl.h for the error code list. - * @note Use in_data before doing any successive ssl calls. - */ -EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data); - -/** - * @brief Write to the SSL data stream. - * if the socket is non-blocking and data is blocked then a check is made - * to ensure that all data is sent (i.e. blocked mode is forced). - * @param ssl [in] An SSL obect reference. - * @param out_data [in] The data to be written - * @param out_len [in] The number of bytes to be written. - * @return The number of bytes sent, or if < 0 if an error. - * @see ssl.h for the error code list. - */ -EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len); - -/** - * @brief Find an ssl object based on a file descriptor. - * - * Goes through the list of SSL objects maintained in a client/server context - * to look for a file descriptor match. - * @param ssl_ctx [in] The client/server context. - * @param client_fd [in] The file descriptor. - * @return A reference to the SSL object. Returns null if the object could not - * be found. - */ -EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd); - -/** - * @brief Get the session id for a handshake. - * - * This will be a 32 byte sequence and is available after the first - * handshaking messages are sent. - * @param ssl [in] An SSL object reference. - * @return The session id as a 32 byte sequence. - * @note A SSLv23 handshake may have only 16 valid bytes. - */ -EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl); - -/** - * @brief Get the session id size for a handshake. - * - * This will normally be 32 but could be 0 (no session id) or something else. - * @param ssl [in] An SSL object reference. - * @return The size of the session id. - */ -EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl); - -/** - * @brief Return the cipher id (in the SSL form). - * @param ssl [in] An SSL object reference. - * @return The cipher id. This will be one of the following: - * - SSL_AES128_SHA (0x2f) - * - SSL_AES256_SHA (0x35) - * - SSL_RC4_128_SHA (0x05) - * - SSL_RC4_128_MD5 (0x04) - */ -EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl); - -/** - * @brief Return the status of the handshake. - * @param ssl [in] An SSL object reference. - * @return SSL_OK if the handshake is complete and ok. - * @see ssl.h for the error code list. - */ -EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl); - -/** - * @brief Retrieve various parameters about the axTLS engine. - * @param offset [in] The configuration offset. It will be one of the following: - * - SSL_BUILD_MODE The build mode. This will be one of the following: - * - SSL_BUILD_SERVER_ONLY (basic server mode) - * - SSL_BUILD_ENABLE_VERIFICATION (server can do client authentication) - * - SSL_BUILD_ENABLE_CLIENT (client/server capabilties) - * - SSL_BUILD_FULL_MODE (client/server with diagnostics) - * - SSL_BUILD_SKELETON_MODE (skeleton mode) - * - SSL_MAX_CERT_CFG_OFFSET The maximum number of certificates allowed. - * - SSL_MAX_CA_CERT_CFG_OFFSET The maximum number of CA certificates allowed. - * - SSL_HAS_PEM 1 if supported - * @return The value of the requested parameter. - */ -EXP_FUNC int STDCALL ssl_get_config(int offset); - -/** - * @brief Display why the handshake failed. - * - * This call is only useful in a 'full mode' build. The output is to stdout. - * @param error_code [in] An error code. - * @see ssl.h for the error code list. - */ -EXP_FUNC void STDCALL ssl_display_error(int error_code); - -/** - * @brief Authenticate a received certificate. - * - * This call is usually made by a client after a handshake is complete and the - * context is in SSL_SERVER_VERIFY_LATER mode. - * @param ssl [in] An SSL object reference. - * @return SSL_OK if the certificate is verified. - */ -EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl); - -/** - * @brief Retrieve an X.509 distinguished name component. - * - * When a handshake is complete and a certificate has been exchanged, then the - * details of the remote certificate can be retrieved. - * - * This will usually be used by a client to check that the server's common - * name matches the URL. - * - * @param ssl [in] An SSL object reference. - * @param component [in] one of: - * - SSL_X509_CERT_COMMON_NAME - * - SSL_X509_CERT_ORGANIZATION - * - SSL_X509_CERT_ORGANIZATIONAL_NAME - * - SSL_X509_CA_CERT_COMMON_NAME - * - SSL_X509_CA_CERT_ORGANIZATION - * - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME - * @return The appropriate string (or null if not defined) - * @note Verification build mode must be enabled. - */ -EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component); - -/** - * @brief Retrieve a Subject Alternative DNSName - * - * When a handshake is complete and a certificate has been exchanged, then the - * details of the remote certificate can be retrieved. - * - * This will usually be used by a client to check that the server's DNS - * name matches the URL. - * - * @param ssl [in] An SSL object reference. - * @param dnsindex [in] The index of the DNS name to retrieve. - * @return The appropriate string (or null if not defined) - * @note Verification build mode must be enabled. - */ -EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int dnsindex); - -/** - * @brief Force the client to perform its handshake again. - * - * For a client this involves sending another "client hello" message. - * For the server is means sending a "hello request" message. - * - * This is a blocking call on the client (until the handshake completes). - * - * @param ssl [in] An SSL object reference. - * @return SSL_OK if renegotiation instantiation was ok - */ -EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl); - -/** - * @brief Process a file that is in binary DER or ASCII PEM format. - * - * These are temporary objects that are used to load private keys, - * certificates etc into memory. - * @param ssl_ctx [in] The client/server context. - * @param obj_type [in] The format of the file. Can be one of: - * - SSL_OBJ_X509_CERT (no password required) - * - SSL_OBJ_X509_CACERT (no password required) - * - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported) - * - SSL_OBJ_PKCS8 (RC4-128 encrypted data supported) - * - SSL_OBJ_PKCS12 (RC4-128 encrypted data supported) - * - * PEM files are automatically detected (if supported). The object type is - * also detected, and so is not relevant for these types of files. - * @param filename [in] The location of a file in DER/PEM format. - * @param password [in] The password used. Can be null if not required. - * @return SSL_OK if all ok - * @note Not available in skeleton build mode. - */ -EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, const char *filename, const char *password); - -/** - * @brief Process binary data. - * - * These are temporary objects that are used to load private keys, - * certificates etc into memory. - * @param ssl_ctx [in] The client/server context. - * @param obj_type [in] The format of the memory data. - * @param data [in] The binary data to be loaded. - * @param len [in] The amount of data to be loaded. - * @param password [in] The password used. Can be null if not required. - * @return SSL_OK if all ok - * @see ssl_obj_load for more details on obj_type. - */ -EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int obj_type, const uint8_t *data, int len, const char *password); - -#ifdef CONFIG_SSL_GENERATE_X509_CERT -/** - * @brief Create an X.509 certificate. - * - * This certificate is a self-signed v1 cert with a fixed start/stop validity - * times. It is signed with an internal private key in ssl_ctx. - * - * @param ssl_ctx [in] The client/server context. - * @param options [in] Not used yet. - * @param dn [in] An array of distinguished name strings. The array is defined - * by: - * - SSL_X509_CERT_COMMON_NAME (0) - * - If SSL_X509_CERT_COMMON_NAME is empty or not defined, then the - * hostname will be used. - * - SSL_X509_CERT_ORGANIZATION (1) - * - If SSL_X509_CERT_ORGANIZATION is empty or not defined, then $USERNAME - * will be used. - * - SSL_X509_CERT_ORGANIZATIONAL_NAME (2) - * - SSL_X509_CERT_ORGANIZATIONAL_NAME is optional. - * @param cert_data [out] The certificate as a sequence of bytes. - * @return < 0 if an error, or the size of the certificate in bytes. - * @note cert_data must be freed when there is no more need for it. - */ -EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data); -#endif - -/** - * @brief Return the axTLS library version as a string. - */ -EXP_FUNC const char * STDCALL ssl_version(void); - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/axTLS/src/ssl/tls1.c b/axTLS/src/ssl/tls1.c deleted file mode 100644 index 4b18365..0000000 --- a/axTLS/src/ssl/tls1.c +++ /dev/null @@ -1,2195 +0,0 @@ -/* - * 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 "os_port.h" -#include "ssl.h" - -/* The session expiry time */ -#define SSL_EXPIRY_TIME (CONFIG_SSL_EXPIRY_TIME*3600) - -static const uint8_t g_hello_request[] = { HS_HELLO_REQUEST, 0, 0, 0 }; -static const uint8_t g_chg_cipher_spec_pkt[] = { 1 }; -static const char * server_finished = "server finished"; -static const char * client_finished = "client finished"; - -static int do_handshake(SSL *ssl, uint8_t *buf, int read_len); -static int set_key_block(SSL *ssl, int is_write); -static int verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len); -static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt); -static int send_raw_packet(SSL *ssl, uint8_t protocol); - -/** - * The server will pick the cipher based on the order that the order that the - * ciphers are listed. This order is defined at compile time. - */ -#ifdef CONFIG_SSL_SKELETON_MODE -const uint8_t ssl_prot_prefs[NUM_PROTOCOLS] = -{ SSL_RC4_128_SHA }; -#else -static void session_free(SSL_SESSION *ssl_sessions[], int sess_index); - -const uint8_t ssl_prot_prefs[NUM_PROTOCOLS] = -#ifdef CONFIG_SSL_PROT_LOW /* low security, fast speed */ -{ SSL_RC4_128_SHA, SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_MD5 }; -#elif CONFIG_SSL_PROT_MEDIUM /* medium security, medium speed */ -{ SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5 }; -#else /* CONFIG_SSL_PROT_HIGH */ /* high security, low speed */ -{ SSL_AES256_SHA, SSL_AES128_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5 }; -#endif -#endif /* CONFIG_SSL_SKELETON_MODE */ - -/** - * The cipher map containing all the essentials for each cipher. - */ -#ifdef CONFIG_SSL_SKELETON_MODE -static const cipher_info_t cipher_info[NUM_PROTOCOLS] = -{ - { /* RC4-SHA */ - SSL_RC4_128_SHA, /* RC4-SHA */ - 16, /* key size */ - 0, /* iv size */ - 2*(SHA1_SIZE+16), /* key block size */ - 0, /* no padding */ - SHA1_SIZE, /* digest size */ - hmac_sha1, /* hmac algorithm */ - (crypt_func)RC4_crypt, /* encrypt */ - (crypt_func)RC4_crypt /* decrypt */ - }, -}; -#else -static const cipher_info_t cipher_info[NUM_PROTOCOLS] = -{ - { /* AES128-SHA */ - SSL_AES128_SHA, /* AES128-SHA */ - 16, /* key size */ - 16, /* iv size */ - 2*(SHA1_SIZE+16+16), /* key block size */ - 16, /* block padding size */ - SHA1_SIZE, /* digest size */ - hmac_sha1, /* hmac algorithm */ - (crypt_func)AES_cbc_encrypt, /* encrypt */ - (crypt_func)AES_cbc_decrypt /* decrypt */ - }, - { /* AES256-SHA */ - SSL_AES256_SHA, /* AES256-SHA */ - 32, /* key size */ - 16, /* iv size */ - 2*(SHA1_SIZE+32+16), /* key block size */ - 16, /* block padding size */ - SHA1_SIZE, /* digest size */ - hmac_sha1, /* hmac algorithm */ - (crypt_func)AES_cbc_encrypt, /* encrypt */ - (crypt_func)AES_cbc_decrypt /* decrypt */ - }, - { /* RC4-SHA */ - SSL_RC4_128_SHA, /* RC4-SHA */ - 16, /* key size */ - 0, /* iv size */ - 2*(SHA1_SIZE+16), /* key block size */ - 0, /* no padding */ - SHA1_SIZE, /* digest size */ - hmac_sha1, /* hmac algorithm */ - (crypt_func)RC4_crypt, /* encrypt */ - (crypt_func)RC4_crypt /* decrypt */ - }, - /* - * This protocol is from SSLv2 days and is unlikely to be used - but was - * useful for testing different possible digest algorithms. - */ - { /* RC4-MD5 */ - SSL_RC4_128_MD5, /* RC4-MD5 */ - 16, /* key size */ - 0, /* iv size */ - 2*(MD5_SIZE+16), /* key block size */ - 0, /* no padding */ - MD5_SIZE, /* digest size */ - hmac_md5, /* hmac algorithm */ - (crypt_func)RC4_crypt, /* encrypt */ - (crypt_func)RC4_crypt /* decrypt */ - }, -}; -#endif - -static void prf(const uint8_t *sec, int sec_len, uint8_t *seed, int seed_len, - uint8_t *out, int olen); -static const cipher_info_t *get_cipher_info(uint8_t cipher); -static void increment_read_sequence(SSL *ssl); -static void increment_write_sequence(SSL *ssl); -static void add_hmac_digest(SSL *ssl, int snd, uint8_t *hmac_header, - const uint8_t *buf, int buf_len, uint8_t *hmac_buf); - -/* win32 VC6.0 doesn't have variadic macros */ -#if defined(WIN32) && !defined(CONFIG_SSL_FULL_MODE) -void DISPLAY_BYTES(SSL *ssl, const char *format, - const uint8_t *data, int size, ...) {} -#endif - -/** - * Establish a new client/server context. - */ -EXP_FUNC SSL_CTX *STDCALL ssl_ctx_new(uint32_t options, int num_sessions) -{ - SSL_CTX *ssl_ctx = (SSL_CTX *)calloc(1, sizeof (SSL_CTX)); - ssl_ctx->options = options; - - if (load_key_certs(ssl_ctx) < 0) - { - free(ssl_ctx); /* can't load our key/certificate pair, so die */ - return NULL; - } - -#ifndef CONFIG_SSL_SKELETON_MODE - ssl_ctx->num_sessions = num_sessions; -#endif - - SSL_CTX_MUTEX_INIT(ssl_ctx->mutex); - -#ifndef CONFIG_SSL_SKELETON_MODE - if (num_sessions) - { - ssl_ctx->ssl_sessions = (SSL_SESSION **) - calloc(1, num_sessions*sizeof(SSL_SESSION *)); - } -#endif - - return ssl_ctx; -} - -/* - * Remove a client/server context. - */ -EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx) -{ - SSL *ssl; - int i; - - if (ssl_ctx == NULL) - return; - - ssl = ssl_ctx->head; - - /* clear out all the ssl entries */ - while (ssl) - { - SSL *next = ssl->next; - ssl_free(ssl); - ssl = next; - } - -#ifndef CONFIG_SSL_SKELETON_MODE - /* clear out all the sessions */ - for (i = 0; i < ssl_ctx->num_sessions; i++) - session_free(ssl_ctx->ssl_sessions, i); - - free(ssl_ctx->ssl_sessions); -#endif - - i = 0; - while (i < CONFIG_SSL_MAX_CERTS && ssl_ctx->certs[i].buf) - { - free(ssl_ctx->certs[i].buf); - ssl_ctx->certs[i++].buf = NULL; - } - -#ifdef CONFIG_SSL_CERT_VERIFICATION - remove_ca_certs(ssl_ctx->ca_cert_ctx); -#endif - ssl_ctx->chain_length = 0; - SSL_CTX_MUTEX_DESTROY(ssl_ctx->mutex); - RSA_free(ssl_ctx->rsa_ctx); - RNG_terminate(); - free(ssl_ctx); -} - -/* - * Free any used resources used by this connection. - */ -EXP_FUNC void STDCALL ssl_free(SSL *ssl) -{ - SSL_CTX *ssl_ctx; - - if (ssl == NULL) /* just ignore null pointers */ - return; - - /* only notify if we weren't notified first */ - /* spec says we must notify when we are dying */ - if (!IS_SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY)) - send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY); - - ssl_ctx = ssl->ssl_ctx; - - SSL_CTX_LOCK(ssl_ctx->mutex); - - /* adjust the server SSL list */ - if (ssl->prev) - ssl->prev->next = ssl->next; - else - ssl_ctx->head = ssl->next; - - if (ssl->next) - ssl->next->prev = ssl->prev; - else - ssl_ctx->tail = ssl->prev; - - SSL_CTX_UNLOCK(ssl_ctx->mutex); - - /* may already be free - but be sure */ - free(ssl->encrypt_ctx); - free(ssl->decrypt_ctx); - disposable_free(ssl); -#ifdef CONFIG_SSL_CERT_VERIFICATION - x509_free(ssl->x509_ctx); -#endif - - free(ssl); -} - -EXP_FUNC int STDCALL ssl_handshake(SSL_CTX* ctx); - -/* - * Read the SSL connection and send any alerts for various errors. - */ -EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data) -{ - int ret = basic_read(ssl, in_data); - - /* check for return code so we can send an alert */ - if (ret < SSL_OK && ret != SSL_CLOSE_NOTIFY) - { - if (ret != SSL_ERROR_CONN_LOST) - { - send_alert(ssl, ret); -#ifndef CONFIG_SSL_SKELETON_MODE - /* something nasty happened, so get rid of this session */ - kill_ssl_session(ssl->ssl_ctx->ssl_sessions, ssl); -#endif - } - } - - return ret; -} - -/* - * Write application data to the client - */ -EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len) -{ - int n = out_len, nw, i, tot = 0; - - /* maximum size of a TLS packet is around 16kB, so fragment */ - do - { - nw = n; - - if (nw > RT_MAX_PLAIN_LENGTH) /* fragment if necessary */ - nw = RT_MAX_PLAIN_LENGTH; - - if ((i = send_packet(ssl, PT_APP_PROTOCOL_DATA, - &out_data[tot], nw)) <= 0) - { - out_len = i; /* an error */ - break; - } - - tot += i; - n -= i; - } while (n > 0); - - return out_len; -} - -/** - * Add a certificate to the certificate chain. - */ -int add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len) -{ - int ret = SSL_ERROR_NO_CERT_DEFINED, i = 0; - SSL_CERT *ssl_cert; - X509_CTX *cert = NULL; - int offset; - - while (ssl_ctx->certs[i].buf && i < CONFIG_SSL_MAX_CERTS) - i++; - - if (i == CONFIG_SSL_MAX_CERTS) /* too many certs */ - { -#ifdef CONFIG_SSL_FULL_MODE - printf("Error: maximum number of certs added (%d) - change of " - "compile-time configuration required\n", - CONFIG_SSL_MAX_CERTS); -#endif - goto error; - } - - if ((ret = x509_new(buf, &offset, &cert))) - goto error; - -#if defined (CONFIG_SSL_FULL_MODE) - if (ssl_ctx->options & SSL_DISPLAY_CERTS) - x509_print(cert, NULL); -#endif - - ssl_cert = &ssl_ctx->certs[i]; - ssl_cert->size = len; - ssl_cert->buf = (uint8_t *)malloc(len); - memcpy(ssl_cert->buf, buf, len); - ssl_ctx->chain_length++; - len -= offset; - ret = SSL_OK; /* ok so far */ - - /* recurse? */ - if (len > 0) - { - ret = add_cert(ssl_ctx, &buf[offset], len); - } - -error: - x509_free(cert); /* don't need anymore */ - return ret; -} - -#ifdef CONFIG_SSL_CERT_VERIFICATION -/** - * Add a certificate authority. - */ -int add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len) -{ - int ret = SSL_OK; /* ignore errors for now */ - int i = 0; - CA_CERT_CTX *ca_cert_ctx; - - if (ssl_ctx->ca_cert_ctx == NULL) - ssl_ctx->ca_cert_ctx = (CA_CERT_CTX *)calloc(1, sizeof(CA_CERT_CTX)); - - ca_cert_ctx = ssl_ctx->ca_cert_ctx; - - while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) - i++; - - while (len > 0) - { - int offset; - if (i >= CONFIG_X509_MAX_CA_CERTS) - { -#ifdef CONFIG_SSL_FULL_MODE - printf("Error: maximum number of CA certs added (%d) - change of " - "compile-time configuration required\n", - CONFIG_X509_MAX_CA_CERTS); -#endif - break; - } - - - /* ignore the return code */ - if (x509_new(buf, &offset, &ca_cert_ctx->cert[i]) == X509_OK) - { -#if defined (CONFIG_SSL_FULL_MODE) - if (ssl_ctx->options & SSL_DISPLAY_CERTS) - x509_print(ca_cert_ctx->cert[i], NULL); -#endif - } - - i++; - len -= offset; - } - - return ret; -} - -/* - * Retrieve an X.509 distinguished name component - */ -EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component) -{ - if (ssl->x509_ctx == NULL) - return NULL; - - switch (component) - { - case SSL_X509_CERT_COMMON_NAME: - return ssl->x509_ctx->cert_dn[X509_COMMON_NAME]; - - case SSL_X509_CERT_ORGANIZATION: - return ssl->x509_ctx->cert_dn[X509_ORGANIZATION]; - - case SSL_X509_CERT_ORGANIZATIONAL_NAME: - return ssl->x509_ctx->cert_dn[X509_ORGANIZATIONAL_UNIT]; - - case SSL_X509_CA_CERT_COMMON_NAME: - return ssl->x509_ctx->ca_cert_dn[X509_COMMON_NAME]; - - case SSL_X509_CA_CERT_ORGANIZATION: - return ssl->x509_ctx->ca_cert_dn[X509_ORGANIZATION]; - - case SSL_X509_CA_CERT_ORGANIZATIONAL_NAME: - return ssl->x509_ctx->ca_cert_dn[X509_ORGANIZATIONAL_UNIT]; - - default: - return NULL; - } -} - -/* - * Retrieve a "Subject Alternative Name" from a v3 certificate - */ -EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, - int dnsindex) -{ - int i; - - if (ssl->x509_ctx == NULL || ssl->x509_ctx->subject_alt_dnsnames == NULL) - return NULL; - - for (i = 0; i < dnsindex; ++i) - { - if (ssl->x509_ctx->subject_alt_dnsnames[i] == NULL) - return NULL; - } - - return ssl->x509_ctx->subject_alt_dnsnames[dnsindex]; -} - -#endif /* CONFIG_SSL_CERT_VERIFICATION */ - -/* - * Find an ssl object based on the client's file descriptor. - */ -EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd) -{ - SSL *ssl; - - SSL_CTX_LOCK(ssl_ctx->mutex); - ssl = ssl_ctx->head; - - /* search through all the ssl entries */ - while (ssl) - { - if (ssl->client_fd == client_fd) - { - SSL_CTX_UNLOCK(ssl_ctx->mutex); - return ssl; - } - - ssl = ssl->next; - } - - SSL_CTX_UNLOCK(ssl_ctx->mutex); - return NULL; -} - -/* - * Force the client to perform its handshake again. - */ -EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl) -{ - int ret = SSL_OK; - - disposable_new(ssl); -#ifdef CONFIG_SSL_ENABLE_CLIENT - if (IS_SET_SSL_FLAG(SSL_IS_CLIENT)) - { - ret = do_client_connect(ssl); - } - else -#endif - { - send_packet(ssl, PT_HANDSHAKE_PROTOCOL, - g_hello_request, sizeof(g_hello_request)); - SET_SSL_FLAG(SSL_NEED_RECORD); - } - - return ret; -} - -/** - * @brief Get what we need for key info. - * @param cipher [in] The cipher information we are after - * @param key_size [out] The key size for the cipher - * @param iv_size [out] The iv size for the cipher - * @return The amount of key information we need. - */ -static const cipher_info_t *get_cipher_info(uint8_t cipher) -{ - int i; - - for (i = 0; i < NUM_PROTOCOLS; i++) - { - if (cipher_info[i].cipher == cipher) - { - return &cipher_info[i]; - } - } - - return NULL; /* error */ -} - -/* - * Get a new ssl context for a new connection. - */ -SSL *ssl_new(SSL_CTX *ssl_ctx, int client_fd) -{ - SSL *ssl = (SSL *)calloc(1, sizeof(SSL)); - ssl->ssl_ctx = ssl_ctx; - ssl->need_bytes = SSL_RECORD_SIZE; /* need a record */ - ssl->client_fd = client_fd; - ssl->flag = SSL_NEED_RECORD; - ssl->bm_data = ssl->bm_all_data+BM_RECORD_OFFSET; /* space at the start */ - ssl->hs_status = SSL_NOT_OK; /* not connected */ -#ifdef CONFIG_ENABLE_VERIFICATION - ssl->ca_cert_ctx = ssl_ctx->ca_cert_ctx; -#endif - disposable_new(ssl); - - /* a bit hacky but saves a few bytes of memory */ - ssl->flag |= ssl_ctx->options; - SSL_CTX_LOCK(ssl_ctx->mutex); - - if (ssl_ctx->head == NULL) - { - ssl_ctx->head = ssl; - ssl_ctx->tail = ssl; - } - else - { - ssl->prev = ssl_ctx->tail; - ssl_ctx->tail->next = ssl; - ssl_ctx->tail = ssl; - } - - SSL_CTX_UNLOCK(ssl_ctx->mutex); - return ssl; -} - -/* - * Add a private key to a context. - */ -int add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj) -{ - int ret = SSL_OK; - - /* get the private key details */ - if (asn1_get_private_key(ssl_obj->buf, ssl_obj->len, &ssl_ctx->rsa_ctx)) - { - ret = SSL_ERROR_INVALID_KEY; - goto error; - } - -error: - return ret; -} - -/** - * Increment the read sequence number (as a 64 bit endian indepenent #) - */ -static void increment_read_sequence(SSL *ssl) -{ - int i; - - for (i = 7; i >= 0; i--) - { - if (++ssl->read_sequence[i]) - break; - } -} - -/** - * Increment the read sequence number (as a 64 bit endian indepenent #) - */ -static void increment_write_sequence(SSL *ssl) -{ - int i; - - for (i = 7; i >= 0; i--) - { - if (++ssl->write_sequence[i]) - break; - } -} - -/** - * Work out the HMAC digest in a packet. - */ -static void add_hmac_digest(SSL *ssl, int mode, uint8_t *hmac_header, - const uint8_t *buf, int buf_len, uint8_t *hmac_buf) -{ - int hmac_len = buf_len + 8 + SSL_RECORD_SIZE; - uint8_t *t_buf = (uint8_t *)alloca(hmac_len+10); - - memcpy(t_buf, (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE) ? - ssl->write_sequence : ssl->read_sequence, 8); - memcpy(&t_buf[8], hmac_header, SSL_RECORD_SIZE); - memcpy(&t_buf[8+SSL_RECORD_SIZE], buf, buf_len); - - ssl->cipher_info->hmac(t_buf, hmac_len, - (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ) ? - ssl->server_mac : ssl->client_mac, - ssl->cipher_info->digest_size, hmac_buf); - -#if 0 - print_blob("record", ssl->hmac_tx, SSL_RECORD_SIZE); - print_blob("buf", buf, buf_len); - if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE) - { - print_blob("write seq", ssl->write_sequence, 8); - } - else - { - print_blob("read seq", ssl->read_sequence, 8); - } - - if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ) - { - print_blob("server mac", - ssl->server_mac, ssl->cipher_info->digest_size); - } - else - { - print_blob("client mac", - ssl->client_mac, ssl->cipher_info->digest_size); - } - print_blob("hmac", hmac_buf, SHA1_SIZE); -#endif -} - -/** - * Verify that the digest of a packet is correct. - */ -static int verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len) -{ - uint8_t hmac_buf[SHA1_SIZE]; - int hmac_offset; - - if (ssl->cipher_info->padding_size) - { - int last_blk_size = buf[read_len-1], i; - hmac_offset = read_len-last_blk_size-ssl->cipher_info->digest_size-1; - - /* guard against a timing attack - make sure we do the digest */ - if (hmac_offset < 0) - { - hmac_offset = 0; - } - else - { - /* already looked at last byte */ - for (i = 1; i < last_blk_size; i++) - { - if (buf[read_len-i] != last_blk_size) - { - hmac_offset = 0; - break; - } - } - } - } - else /* stream cipher */ - { - hmac_offset = read_len - ssl->cipher_info->digest_size; - - if (hmac_offset < 0) - { - hmac_offset = 0; - } - } - - /* sanity check the offset */ - ssl->hmac_header[3] = hmac_offset >> 8; /* insert size */ - ssl->hmac_header[4] = hmac_offset & 0xff; - add_hmac_digest(ssl, mode, ssl->hmac_header, buf, hmac_offset, hmac_buf); - - if (memcmp(hmac_buf, &buf[hmac_offset], ssl->cipher_info->digest_size)) - { - return SSL_ERROR_INVALID_HMAC; - } - - return hmac_offset; -} - -/** - * Add a packet to the end of our sent and received packets, so that we may use - * it to calculate the hash at the end. - */ -void add_packet(SSL *ssl, const uint8_t *pkt, int len) -{ - MD5_Update(&ssl->dc->md5_ctx, pkt, len); - SHA1_Update(&ssl->dc->sha1_ctx, pkt, len); -} - -/** - * Work out the MD5 PRF. - */ -static void p_hash_md5(const uint8_t *sec, int sec_len, - uint8_t *seed, int seed_len, uint8_t *out, int olen) -{ - uint8_t a1[128]; - - /* A(1) */ - hmac_md5(seed, seed_len, sec, sec_len, a1); - memcpy(&a1[MD5_SIZE], seed, seed_len); - hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out); - - while (olen > MD5_SIZE) - { - uint8_t a2[MD5_SIZE]; - out += MD5_SIZE; - olen -= MD5_SIZE; - - /* A(N) */ - hmac_md5(a1, MD5_SIZE, sec, sec_len, a2); - memcpy(a1, a2, MD5_SIZE); - - /* work out the actual hash */ - hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out); - } -} - -/** - * Work out the SHA1 PRF. - */ -static void p_hash_sha1(const uint8_t *sec, int sec_len, - uint8_t *seed, int seed_len, uint8_t *out, int olen) -{ - uint8_t a1[128]; - - /* A(1) */ - hmac_sha1(seed, seed_len, sec, sec_len, a1); - memcpy(&a1[SHA1_SIZE], seed, seed_len); - hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out); - - while (olen > SHA1_SIZE) - { - uint8_t a2[SHA1_SIZE]; - out += SHA1_SIZE; - olen -= SHA1_SIZE; - - /* A(N) */ - hmac_sha1(a1, SHA1_SIZE, sec, sec_len, a2); - memcpy(a1, a2, SHA1_SIZE); - - /* work out the actual hash */ - hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out); - } -} - -/** - * Work out the PRF. - */ -static void prf(const uint8_t *sec, int sec_len, uint8_t *seed, int seed_len, - uint8_t *out, int olen) -{ - int len, i; - const uint8_t *S1, *S2; - uint8_t xbuf[256]; /* needs to be > the amount of key data */ - uint8_t ybuf[256]; /* needs to be > the amount of key data */ - - len = sec_len/2; - S1 = sec; - S2 = &sec[len]; - len += (sec_len & 1); /* add for odd, make longer */ - - p_hash_md5(S1, len, seed, seed_len, xbuf, olen); - p_hash_sha1(S2, len, seed, seed_len, ybuf, olen); - - for (i = 0; i < olen; i++) - out[i] = xbuf[i] ^ ybuf[i]; -} - -/** - * Generate a master secret based on the client/server random data and the - * premaster secret. - */ -void generate_master_secret(SSL *ssl, const uint8_t *premaster_secret) -{ - uint8_t buf[128]; /* needs to be > 13+32+32 in size */ - strcpy((char *)buf, "master secret"); - memcpy(&buf[13], ssl->dc->client_random, SSL_RANDOM_SIZE); - memcpy(&buf[45], ssl->dc->server_random, SSL_RANDOM_SIZE); - prf(premaster_secret, SSL_SECRET_SIZE, buf, 77, ssl->dc->master_secret, - SSL_SECRET_SIZE); -} - -/** - * Generate a 'random' blob of data used for the generation of keys. - */ -static void generate_key_block(uint8_t *client_random, uint8_t *server_random, - uint8_t *master_secret, uint8_t *key_block, int key_block_size) -{ - uint8_t buf[128]; - strcpy((char *)buf, "key expansion"); - memcpy(&buf[13], server_random, SSL_RANDOM_SIZE); - memcpy(&buf[45], client_random, SSL_RANDOM_SIZE); - prf(master_secret, SSL_SECRET_SIZE, buf, 77, key_block, key_block_size); -} - -/** - * Calculate the digest used in the finished message. This function also - * doubles up as a certificate verify function. - */ -void finished_digest(SSL *ssl, const char *label, uint8_t *digest) -{ - uint8_t mac_buf[128]; - uint8_t *q = mac_buf; - MD5_CTX md5_ctx = ssl->dc->md5_ctx; - SHA1_CTX sha1_ctx = ssl->dc->sha1_ctx; - - if (label) - { - strcpy((char *)q, label); - q += strlen(label); - } - - MD5_Final(q, &md5_ctx); - q += MD5_SIZE; - - SHA1_Final(q, &sha1_ctx); - q += SHA1_SIZE; - - if (label) - { - prf(ssl->dc->master_secret, SSL_SECRET_SIZE, mac_buf, (int)(q-mac_buf), - digest, SSL_FINISHED_HASH_SIZE); - } - else /* for use in a certificate verify */ - { - memcpy(digest, mac_buf, MD5_SIZE + SHA1_SIZE); - } - -#if 0 - printf("label: %s\n", label); - print_blob("master secret", ssl->dc->master_secret, 48); - print_blob("mac_buf", mac_buf, q-mac_buf); - print_blob("finished digest", digest, SSL_FINISHED_HASH_SIZE); -#endif -} - -/** - * Retrieve (and initialise) the context of a cipher. - */ -static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt) -{ - switch (ssl->cipher) - { -#ifndef CONFIG_SSL_SKELETON_MODE - case SSL_AES128_SHA: - { - AES_CTX *aes_ctx = (AES_CTX *)malloc(sizeof(AES_CTX)); - AES_set_key(aes_ctx, key, iv, AES_MODE_128); - - if (is_decrypt) - { - AES_convert_key(aes_ctx); - } - - return (void *)aes_ctx; - } - - case SSL_AES256_SHA: - { - AES_CTX *aes_ctx = (AES_CTX *)malloc(sizeof(AES_CTX)); - AES_set_key(aes_ctx, key, iv, AES_MODE_256); - - if (is_decrypt) - { - AES_convert_key(aes_ctx); - } - - return (void *)aes_ctx; - } - - case SSL_RC4_128_MD5: -#endif - case SSL_RC4_128_SHA: - { - RC4_CTX *rc4_ctx = (RC4_CTX *)malloc(sizeof(RC4_CTX)); - RC4_setup(rc4_ctx, key, 16); - return (void *)rc4_ctx; - } - } - - return NULL; /* its all gone wrong */ -} - -/** - * Send a packet over the socket. - */ -static int send_raw_packet(SSL *ssl, uint8_t protocol) -{ - uint8_t *rec_buf = ssl->bm_all_data; - int pkt_size = SSL_RECORD_SIZE+ssl->bm_index; - int sent = 0; - int ret = SSL_OK; - - rec_buf[0] = protocol; - rec_buf[1] = 0x03; /* version = 3.1 or higher */ - rec_buf[2] = ssl->version & 0x0f; - rec_buf[3] = ssl->bm_index >> 8; - rec_buf[4] = ssl->bm_index & 0xff; - - DISPLAY_BYTES(ssl, "sending %d bytes", ssl->bm_all_data, - pkt_size, pkt_size); - - while (sent < pkt_size) - { - ret = SOCKET_WRITE(ssl->client_fd, - &ssl->bm_all_data[sent], pkt_size-sent); - - if (ret >= 0) - sent += ret; - else - { - -#ifdef WIN32 - if (GetLastError() != WSAEWOULDBLOCK) -#else - if (errno != EAGAIN && errno != EWOULDBLOCK) -#endif - return SSL_ERROR_CONN_LOST; - } - - /* keep going until the write buffer has some space */ - if (sent != pkt_size) - { - fd_set wfds; - FD_ZERO(&wfds); - FD_SET(ssl->client_fd, &wfds); - - /* block and wait for it */ - if (select(ssl->client_fd + 1, NULL, &wfds, NULL, NULL) < 0) - return SSL_ERROR_CONN_LOST; - } - } - - SET_SSL_FLAG(SSL_NEED_RECORD); /* reset for next time */ - ssl->bm_index = 0; - - if (protocol != PT_APP_PROTOCOL_DATA) - { - /* always return SSL_OK during handshake */ - ret = SSL_OK; - } - - return ret; -} - -/** - * Send an encrypted packet with padding bytes if necessary. - */ -int send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length) -{ - int ret, msg_length = 0; - - /* if our state is bad, don't bother */ - if (ssl->hs_status == SSL_ERROR_DEAD) - return SSL_ERROR_CONN_LOST; - - if (in) /* has the buffer already been initialised? */ - { - memcpy(ssl->bm_data, in, length); - } - - msg_length += length; - - if (IS_SET_SSL_FLAG(SSL_TX_ENCRYPTED)) - { - int mode = IS_SET_SSL_FLAG(SSL_IS_CLIENT) ? - SSL_CLIENT_WRITE : SSL_SERVER_WRITE; - uint8_t hmac_header[SSL_RECORD_SIZE] = - { - protocol, - 0x03, /* version = 3.1 or higher */ - ssl->version & 0x0f, - msg_length >> 8, - msg_length & 0xff - }; - - if (protocol == PT_HANDSHAKE_PROTOCOL) - { - DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0); - - if (ssl->bm_data[0] != HS_HELLO_REQUEST) - { - add_packet(ssl, ssl->bm_data, msg_length); - } - } - - /* add the packet digest */ - add_hmac_digest(ssl, mode, hmac_header, ssl->bm_data, msg_length, - &ssl->bm_data[msg_length]); - msg_length += ssl->cipher_info->digest_size; - - /* add padding? */ - if (ssl->cipher_info->padding_size) - { - int last_blk_size = msg_length%ssl->cipher_info->padding_size; - int pad_bytes = ssl->cipher_info->padding_size - last_blk_size; - - /* ensure we always have at least 1 padding byte */ - if (pad_bytes == 0) - pad_bytes += ssl->cipher_info->padding_size; - - memset(&ssl->bm_data[msg_length], pad_bytes-1, pad_bytes); - msg_length += pad_bytes; - } - - DISPLAY_BYTES(ssl, "unencrypted write", ssl->bm_data, msg_length); - increment_write_sequence(ssl); - - /* add the explicit IV for TLS1.1 */ - if (ssl->version >= SSL_PROTOCOL_VERSION1_1 && - ssl->cipher_info->iv_size) - - { - uint8_t iv_size = ssl->cipher_info->iv_size; - uint8_t *t_buf = alloca(msg_length + iv_size); - memcpy(t_buf + iv_size, ssl->bm_data, msg_length); - get_random(iv_size, t_buf); - msg_length += iv_size; - memcpy(ssl->bm_data, t_buf, msg_length); - } - - /* now encrypt the packet */ - ssl->cipher_info->encrypt(ssl->encrypt_ctx, ssl->bm_data, - ssl->bm_data, msg_length); - } - else if (protocol == PT_HANDSHAKE_PROTOCOL) - { - DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0); - - if (ssl->bm_data[0] != HS_HELLO_REQUEST) - { - add_packet(ssl, ssl->bm_data, length); - } - } - - ssl->bm_index = msg_length; - if ((ret = send_raw_packet(ssl, protocol)) <= 0) - return ret; - - return length; /* just return what we wanted to send */ -} - -/** - * Work out the cipher keys we are going to use for this session based on the - * master secret. - */ -static int set_key_block(SSL *ssl, int is_write) -{ - const cipher_info_t *ciph_info = get_cipher_info(ssl->cipher); - uint8_t *q; - uint8_t client_key[32], server_key[32]; /* big enough for AES256 */ - uint8_t client_iv[16], server_iv[16]; /* big enough for AES128/256 */ - int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); - - if (ciph_info == NULL) - return -1; - - /* only do once in a handshake */ - if (ssl->dc->key_block == NULL) - { - ssl->dc->key_block = (uint8_t *)malloc(ciph_info->key_block_size); - -#if 0 - print_blob("client", ssl->dc->client_random, 32); - print_blob("server", ssl->dc->server_random, 32); - print_blob("master", ssl->dc->master_secret, SSL_SECRET_SIZE); -#endif - generate_key_block(ssl->dc->client_random, ssl->dc->server_random, - ssl->dc->master_secret, ssl->dc->key_block, - ciph_info->key_block_size); -#if 0 - print_blob("keyblock", ssl->key_block, ciph_info->key_block_size); -#endif - } - - q = ssl->dc->key_block; - - if ((is_client && is_write) || (!is_client && !is_write)) - { - memcpy(ssl->client_mac, q, ciph_info->digest_size); - } - - q += ciph_info->digest_size; - - if ((!is_client && is_write) || (is_client && !is_write)) - { - memcpy(ssl->server_mac, q, ciph_info->digest_size); - } - - q += ciph_info->digest_size; - memcpy(client_key, q, ciph_info->key_size); - q += ciph_info->key_size; - memcpy(server_key, q, ciph_info->key_size); - q += ciph_info->key_size; - -#ifndef CONFIG_SSL_SKELETON_MODE - if (ciph_info->iv_size) /* RC4 has no IV, AES does */ - { - memcpy(client_iv, q, ciph_info->iv_size); - q += ciph_info->iv_size; - memcpy(server_iv, q, ciph_info->iv_size); - q += ciph_info->iv_size; - } -#endif - - free(is_write ? ssl->encrypt_ctx : ssl->decrypt_ctx); - - /* now initialise the ciphers */ - if (is_client) - { - finished_digest(ssl, server_finished, ssl->dc->final_finish_mac); - - if (is_write) - ssl->encrypt_ctx = crypt_new(ssl, client_key, client_iv, 0); - else - ssl->decrypt_ctx = crypt_new(ssl, server_key, server_iv, 1); - } - else - { - finished_digest(ssl, client_finished, ssl->dc->final_finish_mac); - - if (is_write) - ssl->encrypt_ctx = crypt_new(ssl, server_key, server_iv, 0); - else - ssl->decrypt_ctx = crypt_new(ssl, client_key, client_iv, 1); - } - - ssl->cipher_info = ciph_info; - return 0; -} - -/** - * Read the SSL connection. - */ -int basic_read(SSL *ssl, uint8_t **in_data) -{ - int ret = SSL_OK; - int read_len, is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); - uint8_t *buf = ssl->bm_data; - - read_len = SOCKET_READ(ssl->client_fd, &buf[ssl->bm_read_index], - ssl->need_bytes-ssl->got_bytes); - - if (read_len < 0) - { -#ifdef WIN32 - if (GetLastError() == WSAEWOULDBLOCK) -#else - if (errno == EAGAIN || errno == EWOULDBLOCK) -#endif - return 0; - } - - /* connection has gone, so die */ - if (read_len <= 0) - { - ret = SSL_ERROR_CONN_LOST; - ssl->hs_status = SSL_ERROR_DEAD; /* make sure it stays dead */ - goto error; - } - - DISPLAY_BYTES(ssl, "received %d bytes", - &ssl->bm_data[ssl->bm_read_index], read_len, read_len); - - ssl->got_bytes += read_len; - ssl->bm_read_index += read_len; - - /* haven't quite got what we want, so try again later */ - if (ssl->got_bytes < ssl->need_bytes) - return SSL_OK; - - read_len = ssl->got_bytes; - ssl->got_bytes = 0; - - if (IS_SET_SSL_FLAG(SSL_NEED_RECORD)) - { - /* check for sslv2 "client hello" */ - if (buf[0] & 0x80 && buf[2] == 1) - { -#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE - uint8_t version = (buf[3] << 4) + buf[4]; - DISPLAY_BYTES(ssl, "ssl2 record", buf, 5); - - /* should be v3.1 (TLSv1) or better */ - ssl->version = ssl->client_version = version; - - if (version > SSL_PROTOCOL_VERSION_MAX) - { - /* use client's version */ - ssl->version = SSL_PROTOCOL_VERSION_MAX; - } - else if (version < SSL_PROTOCOL_MIN_VERSION) - { - ret = SSL_ERROR_INVALID_VERSION; - ssl_display_error(ret); - return ret; - } - - add_packet(ssl, &buf[2], 3); - ret = process_sslv23_client_hello(ssl); -#else - printf("Error: no SSLv23 handshaking allowed\n"); TTY_FLUSH(); - ret = SSL_ERROR_NOT_SUPPORTED; -#endif - goto error; /* not an error - just get out of here */ - } - - ssl->need_bytes = (buf[3] << 8) + buf[4]; - - /* do we violate the spec with the message size? */ - if (ssl->need_bytes > RT_MAX_PLAIN_LENGTH+RT_EXTRA-BM_RECORD_OFFSET) - { - ret = SSL_ERROR_INVALID_PROT_MSG; - goto error; - } - - CLR_SSL_FLAG(SSL_NEED_RECORD); - memcpy(ssl->hmac_header, buf, 3); /* store for hmac */ - ssl->record_type = buf[0]; - goto error; /* no error, we're done */ - } - - /* for next time - just do it now in case of an error */ - SET_SSL_FLAG(SSL_NEED_RECORD); - ssl->need_bytes = SSL_RECORD_SIZE; - - /* decrypt if we need to */ - if (IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED)) - { - ssl->cipher_info->decrypt(ssl->decrypt_ctx, buf, buf, read_len); - - if (ssl->version >= SSL_PROTOCOL_VERSION1_1 && - ssl->cipher_info->iv_size) - { - buf += ssl->cipher_info->iv_size; - read_len -= ssl->cipher_info->iv_size; - } - - read_len = verify_digest(ssl, - is_client ? SSL_CLIENT_READ : SSL_SERVER_READ, buf, read_len); - - /* does the hmac work? */ - if (read_len < 0) - { - ret = read_len; - goto error; - } - - DISPLAY_BYTES(ssl, "decrypted", buf, read_len); - increment_read_sequence(ssl); - } - - /* The main part of the SSL packet */ - switch (ssl->record_type) - { - case PT_HANDSHAKE_PROTOCOL: - if (ssl->dc != NULL) - { - ssl->dc->bm_proc_index = 0; - ret = do_handshake(ssl, buf, read_len); - } - else /* no client renegotiation allowed */ - { - ret = SSL_ERROR_NO_CLIENT_RENOG; - goto error; - } - break; - - case PT_CHANGE_CIPHER_SPEC: - if (ssl->next_state != HS_FINISHED) - { - ret = SSL_ERROR_INVALID_HANDSHAKE; - goto error; - } - - /* all encrypted from now on */ - SET_SSL_FLAG(SSL_RX_ENCRYPTED); - if (set_key_block(ssl, 0) < 0) - { - ret = SSL_ERROR_INVALID_HANDSHAKE; - goto error; - } - - memset(ssl->read_sequence, 0, 8); - break; - - case PT_APP_PROTOCOL_DATA: - if (in_data) - { - *in_data = buf; /* point to the work buffer */ - (*in_data)[read_len] = 0; /* null terminate just in case */ - } - - ret = read_len; - break; - - case PT_ALERT_PROTOCOL: - /* return the alert # with alert bit set */ - if(buf[0] == SSL_ALERT_TYPE_WARNING && - buf[1] == SSL_ALERT_CLOSE_NOTIFY) - { - ret = SSL_CLOSE_NOTIFY; - send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY); - SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY); - } - else - { - ret = -buf[1]; - DISPLAY_ALERT(ssl, buf[1]); - } - - break; - - default: - ret = SSL_ERROR_INVALID_PROT_MSG; - break; - } - -error: - ssl->bm_read_index = 0; /* reset to go again */ - - if (ret < SSL_OK && in_data)/* if all wrong, then clear this buffer ptr */ - *in_data = NULL; - - return ret; -} - -/** - * Do some basic checking of data and then perform the appropriate handshaking. - */ -static int do_handshake(SSL *ssl, uint8_t *buf, int read_len) -{ - int hs_len = (buf[2]<<8) + buf[3]; - uint8_t handshake_type = buf[0]; - int ret = SSL_OK; - int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); - - /* some integrity checking on the handshake */ - PARANOIA_CHECK(read_len-SSL_HS_HDR_SIZE, hs_len); - - if (handshake_type != ssl->next_state) - { - /* handle a special case on the client */ - if (!is_client || handshake_type != HS_CERT_REQ || - ssl->next_state != HS_SERVER_HELLO_DONE) - { - ret = SSL_ERROR_INVALID_HANDSHAKE; - goto error; - } - } - - hs_len += SSL_HS_HDR_SIZE; /* adjust for when adding packets */ - ssl->bm_index = hs_len; /* store the size and check later */ - DISPLAY_STATE(ssl, 0, handshake_type, 0); - - if (handshake_type != HS_CERT_VERIFY && handshake_type != HS_HELLO_REQUEST) - add_packet(ssl, buf, hs_len); - -#if defined(CONFIG_SSL_ENABLE_CLIENT) - ret = is_client ? - do_clnt_handshake(ssl, handshake_type, buf, hs_len) : - do_svr_handshake(ssl, handshake_type, buf, hs_len); -#else - ret = do_svr_handshake(ssl, handshake_type, buf, hs_len); -#endif - - /* just use recursion to get the rest */ - if (hs_len < read_len && ret == SSL_OK) - ret = do_handshake(ssl, &buf[hs_len], read_len-hs_len); - -error: - return ret; -} - -/** - * Sends the change cipher spec message. We have just read a finished message - * from the client. - */ -int send_change_cipher_spec(SSL *ssl) -{ - int ret = send_packet(ssl, PT_CHANGE_CIPHER_SPEC, - g_chg_cipher_spec_pkt, sizeof(g_chg_cipher_spec_pkt)); - SET_SSL_FLAG(SSL_TX_ENCRYPTED); - - if (ret >= 0 && set_key_block(ssl, 1) < 0) - ret = SSL_ERROR_INVALID_HANDSHAKE; - - memset(ssl->write_sequence, 0, 8); - return ret; -} - -/** - * Send a "finished" message - */ -int send_finished(SSL *ssl) -{ - uint8_t buf[SSL_FINISHED_HASH_SIZE+4] = { - HS_FINISHED, 0, 0, SSL_FINISHED_HASH_SIZE }; - - /* now add the finished digest mac (12 bytes) */ - finished_digest(ssl, - IS_SET_SSL_FLAG(SSL_IS_CLIENT) ? - client_finished : server_finished, &buf[4]); - -#ifndef CONFIG_SSL_SKELETON_MODE - /* store in the session cache */ - if (!IS_SET_SSL_FLAG(SSL_SESSION_RESUME) && ssl->ssl_ctx->num_sessions) - { - memcpy(ssl->session->master_secret, - ssl->dc->master_secret, SSL_SECRET_SIZE); - } -#endif - - return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, - buf, SSL_FINISHED_HASH_SIZE+4); -} - -/** - * Send an alert message. - * Return 1 if the alert was an "error". - */ -int send_alert(SSL *ssl, int error_code) -{ - int alert_num = 0; - int is_warning = 0; - uint8_t buf[2]; - - /* Don't bother we're already dead */ - if (ssl->hs_status == SSL_ERROR_DEAD) - { - return SSL_ERROR_CONN_LOST; - } - -#ifdef CONFIG_SSL_FULL_MODE - if (IS_SET_SSL_FLAG(SSL_DISPLAY_STATES)) - ssl_display_error(error_code); -#endif - - switch (error_code) - { - case SSL_ALERT_CLOSE_NOTIFY: - is_warning = 1; - alert_num = SSL_ALERT_CLOSE_NOTIFY; - break; - - case SSL_ERROR_CONN_LOST: /* don't send alert just yet */ - is_warning = 1; - break; - - case SSL_ERROR_INVALID_HANDSHAKE: - case SSL_ERROR_INVALID_PROT_MSG: - alert_num = SSL_ALERT_HANDSHAKE_FAILURE; - break; - - case SSL_ERROR_INVALID_HMAC: - case SSL_ERROR_FINISHED_INVALID: - alert_num = SSL_ALERT_BAD_RECORD_MAC; - break; - - case SSL_ERROR_INVALID_VERSION: - alert_num = SSL_ALERT_INVALID_VERSION; - break; - - case SSL_ERROR_INVALID_SESSION: - case SSL_ERROR_NO_CIPHER: - case SSL_ERROR_INVALID_KEY: - alert_num = SSL_ALERT_ILLEGAL_PARAMETER; - break; - - case SSL_ERROR_BAD_CERTIFICATE: - alert_num = SSL_ALERT_BAD_CERTIFICATE; - break; - - case SSL_ERROR_NO_CLIENT_RENOG: - alert_num = SSL_ALERT_NO_RENEGOTIATION; - break; - - default: - /* a catch-all for any badly verified certificates */ - alert_num = (error_code <= SSL_X509_OFFSET) ? - SSL_ALERT_BAD_CERTIFICATE : SSL_ALERT_UNEXPECTED_MESSAGE; - break; - } - - buf[0] = is_warning ? 1 : 2; - buf[1] = alert_num; - send_packet(ssl, PT_ALERT_PROTOCOL, buf, sizeof(buf)); - DISPLAY_ALERT(ssl, alert_num); - return is_warning ? 0 : 1; -} - -/** - * Process a client finished message. - */ -int process_finished(SSL *ssl, uint8_t *buf, int hs_len) -{ - int ret = SSL_OK; - int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); - int resume = IS_SET_SSL_FLAG(SSL_SESSION_RESUME); - - PARANOIA_CHECK(ssl->bm_index, SSL_FINISHED_HASH_SIZE+4); - - /* check that we all work before we continue */ - if (memcmp(ssl->dc->final_finish_mac, &buf[4], SSL_FINISHED_HASH_SIZE)) - return SSL_ERROR_FINISHED_INVALID; - - if ((!is_client && !resume) || (is_client && resume)) - { - if ((ret = send_change_cipher_spec(ssl)) == SSL_OK) - ret = send_finished(ssl); - } - - /* if we ever renegotiate */ - ssl->next_state = is_client ? HS_HELLO_REQUEST : HS_CLIENT_HELLO; - ssl->hs_status = ret; /* set the final handshake status */ - -error: - return ret; -} - -/** - * Send a certificate. - */ -int send_certificate(SSL *ssl) -{ - int i = 0; - uint8_t *buf = ssl->bm_data; - int offset = 7; - int chain_length; - - buf[0] = HS_CERTIFICATE; - buf[1] = 0; - buf[4] = 0; - - while (i < ssl->ssl_ctx->chain_length) - { - SSL_CERT *cert = &ssl->ssl_ctx->certs[i]; - buf[offset++] = 0; - buf[offset++] = cert->size >> 8; /* cert 1 length */ - buf[offset++] = cert->size & 0xff; - memcpy(&buf[offset], cert->buf, cert->size); - offset += cert->size; - i++; - } - - chain_length = offset - 7; - buf[5] = chain_length >> 8; /* cert chain length */ - buf[6] = chain_length & 0xff; - chain_length += 3; - buf[2] = chain_length >> 8; /* handshake length */ - buf[3] = chain_length & 0xff; - ssl->bm_index = offset; - return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset); -} - -/** - * Create a blob of memory that we'll get rid of once the handshake is - * complete. - */ -void disposable_new(SSL *ssl) -{ - if (ssl->dc == NULL) - { - ssl->dc = (DISPOSABLE_CTX *)calloc(1, sizeof(DISPOSABLE_CTX)); - MD5_Init(&ssl->dc->md5_ctx); - SHA1_Init(&ssl->dc->sha1_ctx); - } -} - -/** - * Remove the temporary blob of memory. - */ -void disposable_free(SSL *ssl) -{ - if (ssl->dc) - { - free(ssl->dc->key_block); - memset(ssl->dc, 0, sizeof(DISPOSABLE_CTX)); - free(ssl->dc); - ssl->dc = NULL; - } - -} - -#ifndef CONFIG_SSL_SKELETON_MODE /* no session resumption in this mode */ -/** - * Find if an existing session has the same session id. If so, use the - * master secret from this session for session resumption. - */ -SSL_SESSION *ssl_session_update(int max_sessions, SSL_SESSION *ssl_sessions[], - SSL *ssl, const uint8_t *session_id) -{ - time_t tm = time(NULL); - time_t oldest_sess_time = tm; - SSL_SESSION *oldest_sess = NULL; - int i; - - /* no sessions? Then bail */ - if (max_sessions == 0) - return NULL; - - SSL_CTX_LOCK(ssl->ssl_ctx->mutex); - if (session_id) - { - for (i = 0; i < max_sessions; i++) - { - if (ssl_sessions[i]) - { - /* kill off any expired sessions */ - if (tm > ssl_sessions[i]->conn_time + SSL_EXPIRY_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 */ - if (oldest_sess != NULL) - { - oldest_sess->conn_time = tm; - memset(oldest_sess->session_id, 0, sizeof(SSL_SESSION_ID_SIZE)); - memset(oldest_sess->master_secret, 0, sizeof(SSL_SECRET_SIZE)); - } - - SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); - return oldest_sess; -} - -/** - * Free an existing session. - */ -static void session_free(SSL_SESSION *ssl_sessions[], int sess_index) -{ - if (ssl_sessions[sess_index]) - { - free(ssl_sessions[sess_index]); - ssl_sessions[sess_index] = NULL; - } -} - -/** - * This ssl object doesn't want this session anymore. - */ -void kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl) -{ - SSL_CTX_LOCK(ssl->ssl_ctx->mutex); - - if (ssl->ssl_ctx->num_sessions) - { - session_free(ssl_sessions, ssl->session_index); - ssl->session = NULL; - } - - SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); -} -#endif /* CONFIG_SSL_SKELETON_MODE */ - -/* - * Get the session id for a handshake. This will be a 32 byte sequence. - */ -EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl) -{ - return ssl->session_id; -} - -/* - * Get the session id size for a handshake. - */ -EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl) -{ - return ssl->sess_id_size; -} - -/* - * Return the cipher id (in the SSL form). - */ -EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl) -{ - return ssl->cipher; -} - -/* - * Return the status of the handshake. - */ -EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl) -{ - return ssl->hs_status; -} - -/* - * Retrieve various parameters about the SSL engine. - */ -EXP_FUNC int STDCALL ssl_get_config(int offset) -{ - switch (offset) - { - /* return the appropriate build mode */ - case SSL_BUILD_MODE: -#if defined(CONFIG_SSL_FULL_MODE) - return SSL_BUILD_FULL_MODE; -#elif defined(CONFIG_SSL_ENABLE_CLIENT) - return SSL_BUILD_ENABLE_CLIENT; -#elif defined(CONFIG_ENABLE_VERIFICATION) - return SSL_BUILD_ENABLE_VERIFICATION; -#elif defined(CONFIG_SSL_SERVER_ONLY ) - return SSL_BUILD_SERVER_ONLY; -#else - return SSL_BUILD_SKELETON_MODE; -#endif - - case SSL_MAX_CERT_CFG_OFFSET: - return CONFIG_SSL_MAX_CERTS; - -#ifdef CONFIG_SSL_CERT_VERIFICATION - case SSL_MAX_CA_CERT_CFG_OFFSET: - return CONFIG_X509_MAX_CA_CERTS; -#endif -#ifdef CONFIG_SSL_HAS_PEM - case SSL_HAS_PEM: - return 1; -#endif - default: - return 0; - } -} - -#ifdef CONFIG_SSL_CERT_VERIFICATION -/** - * Authenticate a received certificate. - */ -EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl) -{ - int ret; - SSL_CTX_LOCK(ssl->ssl_ctx->mutex); - ret = x509_verify(ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx); - SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); - - if (ret) /* modify into an SSL error type */ - { - ret = SSL_X509_ERROR(ret); - } - - return ret; -} - -/** - * Process a certificate message. - */ -int process_certificate(SSL *ssl, X509_CTX **x509_ctx) -{ - int ret = SSL_OK; - uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index]; - int pkt_size = ssl->bm_index; - int cert_size, offset = 5; - int total_cert_size = (buf[offset]<<8) + buf[offset+1]; - int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); - X509_CTX **chain = x509_ctx; - offset += 2; - - PARANOIA_CHECK(total_cert_size, offset); - - while (offset < total_cert_size) - { - offset++; /* skip empty char */ - cert_size = (buf[offset]<<8) + buf[offset+1]; - offset += 2; - - if (x509_new(&buf[offset], NULL, chain)) - { - ret = SSL_ERROR_BAD_CERTIFICATE; - goto error; - } - - chain = &((*chain)->next); - offset += cert_size; - } - - PARANOIA_CHECK(pkt_size, offset); - - /* if we are client we can do the verify now or later */ - if (is_client && !IS_SET_SSL_FLAG(SSL_SERVER_VERIFY_LATER)) - { - ret = ssl_verify_cert(ssl); - } - - ssl->next_state = is_client ? HS_SERVER_HELLO_DONE : HS_CLIENT_KEY_XCHG; - ssl->dc->bm_proc_index += offset; -error: - return ret; -} - -#endif /* CONFIG_SSL_CERT_VERIFICATION */ - -/** - * Debugging routine to display SSL handshaking stuff. - */ -#ifdef CONFIG_SSL_FULL_MODE -/** - * Debugging routine to display SSL states. - */ -void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok) -{ - const char *str; - - if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES)) - return; - - printf(not_ok ? "Error - invalid State:\t" : "State:\t"); - printf(is_send ? "sending " : "receiving "); - - switch (state) - { - case HS_HELLO_REQUEST: - str = "Hello Request (0)"; - break; - - case HS_CLIENT_HELLO: - str = "Client Hello (1)"; - break; - - case HS_SERVER_HELLO: - str = "Server Hello (2)"; - break; - - case HS_CERTIFICATE: - str = "Certificate (11)"; - break; - - case HS_SERVER_KEY_XCHG: - str = "Certificate Request (12)"; - break; - - case HS_CERT_REQ: - str = "Certificate Request (13)"; - break; - - case HS_SERVER_HELLO_DONE: - str = "Server Hello Done (14)"; - break; - - case HS_CERT_VERIFY: - str = "Certificate Verify (15)"; - break; - - case HS_CLIENT_KEY_XCHG: - str = "Client Key Exchange (16)"; - break; - - case HS_FINISHED: - str = "Finished (16)"; - break; - - default: - str = "Error (Unknown)"; - - break; - } - - printf("%s\n", str); - TTY_FLUSH(); -} - -/** - * Debugging routine to display RSA objects - */ -void DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx) -{ - if (!IS_SET_SSL_FLAG(SSL_DISPLAY_RSA)) - return; - - RSA_print(rsa_ctx); - TTY_FLUSH(); -} - -/** - * Debugging routine to display SSL handshaking bytes. - */ -void DISPLAY_BYTES(SSL *ssl, const char *format, - const uint8_t *data, int size, ...) -{ - va_list(ap); - - if (!IS_SET_SSL_FLAG(SSL_DISPLAY_BYTES)) - return; - - va_start(ap, size); - print_blob(format, data, size, va_arg(ap, char *)); - va_end(ap); - TTY_FLUSH(); -} - -/** - * Debugging routine to display SSL handshaking errors. - */ -EXP_FUNC void STDCALL ssl_display_error(int error_code) -{ - if (error_code == SSL_OK) - return; - - printf("Error: "); - - /* X509 error? */ - if (error_code < SSL_X509_OFFSET) - { - printf("%s\n", x509_display_error(error_code - SSL_X509_OFFSET)); - return; - } - - /* SSL alert error code */ - if (error_code > SSL_ERROR_CONN_LOST) - { - printf("SSL error %d\n", -error_code); - return; - } - - switch (error_code) - { - case SSL_ERROR_DEAD: - printf("connection dead"); - break; - - case SSL_ERROR_INVALID_HANDSHAKE: - printf("invalid handshake"); - break; - - case SSL_ERROR_INVALID_PROT_MSG: - printf("invalid protocol message"); - break; - - case SSL_ERROR_INVALID_HMAC: - printf("invalid mac"); - break; - - case SSL_ERROR_INVALID_VERSION: - printf("invalid version"); - break; - - case SSL_ERROR_INVALID_SESSION: - printf("invalid session"); - break; - - case SSL_ERROR_NO_CIPHER: - printf("no cipher"); - break; - - case SSL_ERROR_CONN_LOST: - printf("connection lost"); - break; - - case SSL_ERROR_BAD_CERTIFICATE: - printf("bad certificate"); - break; - - case SSL_ERROR_INVALID_KEY: - printf("invalid key"); - break; - - case SSL_ERROR_FINISHED_INVALID: - printf("finished invalid"); - break; - - case SSL_ERROR_NO_CERT_DEFINED: - printf("no certificate defined"); - break; - - case SSL_ERROR_NO_CLIENT_RENOG: - printf("client renegotiation not supported"); - break; - - case SSL_ERROR_NOT_SUPPORTED: - printf("Option not supported"); - break; - - default: - printf("undefined as yet - %d", error_code); - break; - } - - printf("\n"); - TTY_FLUSH(); -} - -/** - * Debugging routine to display alerts. - */ -void DISPLAY_ALERT(SSL *ssl, int alert) -{ - if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES)) - return; - - printf("Alert: "); - - switch (alert) - { - case SSL_ALERT_CLOSE_NOTIFY: - printf("close notify"); - break; - - case SSL_ALERT_INVALID_VERSION: - printf("invalid version"); - break; - - case SSL_ALERT_BAD_CERTIFICATE: - printf("bad certificate"); - break; - - case SSL_ALERT_UNEXPECTED_MESSAGE: - printf("unexpected message"); - break; - - case SSL_ALERT_BAD_RECORD_MAC: - printf("bad record mac"); - break; - - case SSL_ALERT_HANDSHAKE_FAILURE: - printf("handshake failure"); - break; - - case SSL_ALERT_ILLEGAL_PARAMETER: - printf("illegal parameter"); - break; - - case SSL_ALERT_DECODE_ERROR: - printf("decode error"); - break; - - case SSL_ALERT_DECRYPT_ERROR: - printf("decrypt error"); - break; - - case SSL_ALERT_NO_RENEGOTIATION: - printf("no renegotiation"); - break; - - default: - printf("alert - (unknown %d)", alert); - break; - } - - printf("\n"); - TTY_FLUSH(); -} - -#endif /* CONFIG_SSL_FULL_MODE */ - -/** - * Return the version of this library. - */ -EXP_FUNC const char * STDCALL ssl_version() -{ - static const char * axtls_version = AXTLS_VERSION; - return axtls_version; -} - -/** - * Enable the various language bindings to work regardless of the - * configuration - they just return an error statement and a bad return code. - */ -#if !defined(CONFIG_SSL_FULL_MODE) -EXP_FUNC void STDCALL ssl_display_error(int error_code) {} -#endif - -#ifdef CONFIG_BINDINGS -#if !defined(CONFIG_SSL_ENABLE_CLIENT) -EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const - uint8_t *session_id, uint8_t sess_id_size) -{ - printf(unsupported_str); - return NULL; -} -#endif - -#if !defined(CONFIG_SSL_CERT_VERIFICATION) -EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl) -{ - printf(unsupported_str); - return -1; -} - - -EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component) -{ - printf(unsupported_str); - return NULL; -} - -EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int index) -{ - printf(unsupported_str); - return NULL; -} - -#endif /* CONFIG_SSL_CERT_VERIFICATION */ - -#endif /* CONFIG_BINDINGS */ - diff --git a/axTLS/src/ssl/tls1.h b/axTLS/src/ssl/tls1.h deleted file mode 100644 index e73bc1a..0000000 --- a/axTLS/src/ssl/tls1.h +++ /dev/null @@ -1,295 +0,0 @@ -/*
- * 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 "crypto.h"
-#include "crypto_misc.h"
-
-#define SSL_PROTOCOL_MIN_VERSION 0x31 /* TLS v1.0 */
-#define SSL_PROTOCOL_MINOR_VERSION 0x02 /* TLS v1.1 */
-#define SSL_PROTOCOL_VERSION_MAX 0x32 /* TLS v1.1 */
-#define SSL_PROTOCOL_VERSION1_1 0x32 /* TLS v1.1 */
-#define SSL_RANDOM_SIZE 32
-#define SSL_SECRET_SIZE 48
-#define SSL_FINISHED_HASH_SIZE 12
-#define SSL_RECORD_SIZE 5
-#define SSL_SERVER_READ 0
-#define SSL_SERVER_WRITE 1
-#define SSL_CLIENT_READ 2
-#define SSL_CLIENT_WRITE 3
-#define SSL_HS_HDR_SIZE 4
-
-/* the flags we use while establishing a connection */
-#define SSL_NEED_RECORD 0x0001
-#define SSL_TX_ENCRYPTED 0x0002
-#define SSL_RX_ENCRYPTED 0x0004
-#define SSL_SESSION_RESUME 0x0008
-#define SSL_IS_CLIENT 0x0010
-#define SSL_HAS_CERT_REQ 0x0020
-#define SSL_SENT_CLOSE_NOTIFY 0x0040
-
-/* some macros to muck around with flag bits */
-#define SET_SSL_FLAG(A) (ssl->flag |= A)
-#define CLR_SSL_FLAG(A) (ssl->flag &= ~A)
-#define IS_SET_SSL_FLAG(A) (ssl->flag & A)
-
-#define MAX_KEY_BYTE_SIZE 512 /* for a 4096 bit key */
-#define RT_MAX_PLAIN_LENGTH 16384
-#define RT_EXTRA 1024
-#define BM_RECORD_OFFSET 5
-
-#ifdef CONFIG_SSL_SKELETON_MODE
-#define NUM_PROTOCOLS 1
-#else
-#define NUM_PROTOCOLS 4
-#endif
-
-#define PARANOIA_CHECK(A, B) if (A < B) { \
- ret = SSL_ERROR_INVALID_HANDSHAKE; goto error; }
-
-/* protocol types */
-enum
-{
- PT_CHANGE_CIPHER_SPEC = 20,
- PT_ALERT_PROTOCOL,
- PT_HANDSHAKE_PROTOCOL,
- PT_APP_PROTOCOL_DATA
-};
-
-/* handshaking types */
-enum
-{
- HS_HELLO_REQUEST,
- HS_CLIENT_HELLO,
- HS_SERVER_HELLO,
- HS_CERTIFICATE = 11,
- HS_SERVER_KEY_XCHG,
- HS_CERT_REQ,
- HS_SERVER_HELLO_DONE,
- HS_CERT_VERIFY,
- HS_CLIENT_KEY_XCHG,
- HS_FINISHED = 20
-};
-
-typedef struct
-{
- uint8_t cipher;
- uint8_t key_size;
- uint8_t iv_size;
- uint8_t key_block_size;
- uint8_t padding_size;
- uint8_t digest_size;
- hmac_func hmac;
- crypt_func encrypt;
- crypt_func decrypt;
-} cipher_info_t;
-
-struct _SSLObjLoader
-{
- uint8_t *buf;
- int len;
-};
-
-typedef struct _SSLObjLoader SSLObjLoader;
-
-typedef struct
-{
- time_t conn_time;
- uint8_t session_id[SSL_SESSION_ID_SIZE];
- uint8_t master_secret[SSL_SECRET_SIZE];
-} SSL_SESSION;
-
-typedef struct
-{
- uint8_t *buf;
- int size;
-} SSL_CERT;
-
-typedef struct
-{
- MD5_CTX md5_ctx;
- SHA1_CTX sha1_ctx;
- uint8_t final_finish_mac[SSL_FINISHED_HASH_SIZE];
- uint8_t *key_block;
- uint8_t master_secret[SSL_SECRET_SIZE];
- uint8_t client_random[SSL_RANDOM_SIZE]; /* client's random sequence */
- uint8_t server_random[SSL_RANDOM_SIZE]; /* server's random sequence */
- uint16_t bm_proc_index;
-} DISPOSABLE_CTX;
-
-struct _SSL
-{
- uint32_t flag;
- uint16_t need_bytes;
- uint16_t got_bytes;
- uint8_t record_type;
- uint8_t cipher;
- uint8_t sess_id_size;
- uint8_t version;
- uint8_t client_version;
- int16_t next_state;
- int16_t hs_status;
- DISPOSABLE_CTX *dc; /* temporary data which we'll get rid of soon */
- int client_fd;
- const cipher_info_t *cipher_info;
- void *encrypt_ctx;
- void *decrypt_ctx;
- uint8_t bm_all_data[RT_MAX_PLAIN_LENGTH+RT_EXTRA];
- uint8_t *bm_data;
- uint16_t bm_index;
- uint16_t bm_read_index;
- struct _SSL *next; /* doubly linked list */
- struct _SSL *prev;
- struct _SSL_CTX *ssl_ctx; /* back reference to a clnt/svr ctx */
-#ifndef CONFIG_SSL_SKELETON_MODE
- uint16_t session_index;
- SSL_SESSION *session;
-#endif
-#ifdef CONFIG_SSL_CERT_VERIFICATION
- X509_CTX *x509_ctx;
-#endif
-
- uint8_t session_id[SSL_SESSION_ID_SIZE];
- uint8_t client_mac[SHA1_SIZE]; /* for HMAC verification */
- uint8_t server_mac[SHA1_SIZE]; /* for HMAC verification */
- uint8_t read_sequence[8]; /* 64 bit sequence number */
- uint8_t write_sequence[8]; /* 64 bit sequence number */
- uint8_t hmac_header[SSL_RECORD_SIZE]; /* rx hmac */
-};
-
-typedef struct _SSL SSL;
-
-struct _SSL_CTX
-{
- uint32_t options;
- uint8_t chain_length;
- RSA_CTX *rsa_ctx;
-#ifdef CONFIG_SSL_CERT_VERIFICATION
- CA_CERT_CTX *ca_cert_ctx;
-#endif
- SSL *head;
- SSL *tail;
- SSL_CERT certs[CONFIG_SSL_MAX_CERTS];
-#ifndef CONFIG_SSL_SKELETON_MODE
- uint16_t num_sessions;
- SSL_SESSION **ssl_sessions;
-#endif
-#ifdef CONFIG_SSL_CTX_MUTEXING
- SSL_CTX_MUTEX_TYPE mutex;
-#endif
-#ifdef CONFIG_OPENSSL_COMPATIBLE
- void *bonus_attr;
-#endif
-};
-
-typedef struct _SSL_CTX SSL_CTX;
-
-/* backwards compatibility */
-typedef struct _SSL_CTX SSLCTX;
-
-extern const uint8_t ssl_prot_prefs[NUM_PROTOCOLS];
-
-SSL *ssl_new(SSL_CTX *ssl_ctx, int client_fd);
-void disposable_new(SSL *ssl);
-void disposable_free(SSL *ssl);
-int send_packet(SSL *ssl, uint8_t protocol,
- const uint8_t *in, int length);
-int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len);
-int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len);
-int process_finished(SSL *ssl, uint8_t *buf, int hs_len);
-int process_sslv23_client_hello(SSL *ssl);
-int send_alert(SSL *ssl, int error_code);
-int send_finished(SSL *ssl);
-int send_certificate(SSL *ssl);
-int basic_read(SSL *ssl, uint8_t **in_data);
-int send_change_cipher_spec(SSL *ssl);
-void finished_digest(SSL *ssl, const char *label, uint8_t *digest);
-void generate_master_secret(SSL *ssl, const uint8_t *premaster_secret);
-void add_packet(SSL *ssl, const uint8_t *pkt, int len);
-int add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len);
-int add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj);
-void ssl_obj_free(SSLObjLoader *ssl_obj);
-int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password);
-int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password);
-int load_key_certs(SSL_CTX *ssl_ctx);
-#ifdef CONFIG_SSL_CERT_VERIFICATION
-int add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len);
-void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx);
-#endif
-#ifdef CONFIG_SSL_ENABLE_CLIENT
-int do_client_connect(SSL *ssl);
-#endif
-
-#ifdef CONFIG_SSL_FULL_MODE
-void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok);
-void DISPLAY_BYTES(SSL *ssl, const char *format,
- const uint8_t *data, int size, ...);
-void DISPLAY_CERT(SSL *ssl, const X509_CTX *x509_ctx);
-void DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx);
-void DISPLAY_ALERT(SSL *ssl, int alert);
-#else
-#define DISPLAY_STATE(A,B,C,D)
-#define DISPLAY_CERT(A,B)
-#define DISPLAY_RSA(A,B)
-#define DISPLAY_ALERT(A, B)
-#ifdef WIN32
-void DISPLAY_BYTES(SSL *ssl, const char *format,/* win32 has no variadic macros */
- const uint8_t *data, int size, ...);
-#else
-#define DISPLAY_BYTES(A,B,C,D,...)
-#endif
-#endif
-
-#ifdef CONFIG_SSL_CERT_VERIFICATION
-int process_certificate(SSL *ssl, X509_CTX **x509_ctx);
-#endif
-
-SSL_SESSION *ssl_session_update(int max_sessions,
- SSL_SESSION *ssl_sessions[], SSL *ssl,
- const uint8_t *session_id);
-void kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/axTLS/src/ssl/tls1_clnt.c b/axTLS/src/ssl/tls1_clnt.c deleted file mode 100644 index 196b40e..0000000 --- a/axTLS/src/ssl/tls1_clnt.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * 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_CTX *ssl_ctx, int client_fd, const - uint8_t *session_id, uint8_t sess_id_size) -{ - SSL *ssl = ssl_new(ssl_ctx, client_fd); - ssl->version = SSL_PROTOCOL_VERSION_MAX; /* try top version first */ - - if (session_id && ssl_ctx->num_sessions) - { - if (sess_id_size > SSL_SESSION_ID_SIZE) /* validity check */ - { - ssl_free(ssl); - return NULL; - } - - memcpy(ssl->session_id, session_id, sess_id_size); - ssl->sess_id_size = sess_id_size; - SET_SSL_FLAG(SSL_SESSION_RESUME); /* just flag for later */ - } - - SET_SSL_FLAG(SSL_IS_CLIENT); - do_client_connect(ssl); - return ssl; -} - -/* - * Process the handshake record. - */ -int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len) -{ - int ret; - - /* To get here the state must be valid */ - switch (handshake_type) - { - case HS_SERVER_HELLO: - ret = process_server_hello(ssl); - break; - - case HS_CERTIFICATE: - ret = process_certificate(ssl, &ssl->x509_ctx); - break; - - case HS_SERVER_HELLO_DONE: - if ((ret = process_server_hello_done(ssl)) == SSL_OK) - { - if (IS_SET_SSL_FLAG(SSL_HAS_CERT_REQ)) - { - if ((ret = send_certificate(ssl)) == SSL_OK && - (ret = send_client_key_xchg(ssl)) == SSL_OK) - { - send_cert_verify(ssl); - } - } - else - { - ret = send_client_key_xchg(ssl); - } - - if (ret == SSL_OK && - (ret = send_change_cipher_spec(ssl)) == SSL_OK) - { - ret = send_finished(ssl); - } - } - break; - - case HS_CERT_REQ: - ret = process_cert_req(ssl); - break; - - case HS_FINISHED: - ret = process_finished(ssl, buf, hs_len); - disposable_free(ssl); /* free up some memory */ - /* note: client renegotiation is not allowed after this */ - break; - - case HS_HELLO_REQUEST: - disposable_new(ssl); - ret = do_client_connect(ssl); - break; - - default: - ret = SSL_ERROR_INVALID_HANDSHAKE; - break; - } - - return ret; -} - -/* - * Do the handshaking from the beginning. - */ -int do_client_connect(SSL *ssl) -{ - int ret = SSL_OK; - - send_client_hello(ssl); /* send the client hello */ - ssl->bm_read_index = 0; - ssl->next_state = HS_SERVER_HELLO; - ssl->hs_status = SSL_NOT_OK; /* not connected */ - - /* sit in a loop until it all looks good */ - if (!IS_SET_SSL_FLAG(SSL_CONNECT_IN_PARTS)) - { - while (ssl->hs_status != SSL_OK) - { - ret = ssl_read(ssl, NULL); - - if (ret < SSL_OK) - break; - } - - ssl->hs_status = ret; /* connected? */ - } - - return ret; -} - -/* - * Send the initial client hello. - */ -static int send_client_hello(SSL *ssl) -{ - uint8_t *buf = ssl->bm_data; - time_t tm = time(NULL); - uint8_t *tm_ptr = &buf[6]; /* time will go here */ - int i, offset; - - buf[0] = HS_CLIENT_HELLO; - buf[1] = 0; - buf[2] = 0; - /* byte 3 is calculated later */ - buf[4] = 0x03; - buf[5] = ssl->version & 0x0f; - - /* client random value - spec says that 1st 4 bytes are big endian time */ - *tm_ptr++ = (uint8_t)(((long)tm & 0xff000000) >> 24); - *tm_ptr++ = (uint8_t)(((long)tm & 0x00ff0000) >> 16); - *tm_ptr++ = (uint8_t)(((long)tm & 0x0000ff00) >> 8); - *tm_ptr++ = (uint8_t)(((long)tm & 0x000000ff)); - get_random(SSL_RANDOM_SIZE-4, &buf[10]); - memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE); - offset = 6 + SSL_RANDOM_SIZE; - - /* give session resumption a go */ - if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) /* set initially by user */ - { - buf[offset++] = ssl->sess_id_size; - memcpy(&buf[offset], ssl->session_id, ssl->sess_id_size); - offset += ssl->sess_id_size; - CLR_SSL_FLAG(SSL_SESSION_RESUME); /* clear so we can set later */ - } - else - { - /* no session id - because no session resumption just yet */ - buf[offset++] = 0; - } - - buf[offset++] = 0; /* number of ciphers */ - buf[offset++] = NUM_PROTOCOLS*2;/* number of ciphers */ - - /* put all our supported protocols in our request */ - for (i = 0; i < NUM_PROTOCOLS; i++) - { - buf[offset++] = 0; /* cipher we are using */ - buf[offset++] = ssl_prot_prefs[i]; - } - - buf[offset++] = 1; /* no compression */ - buf[offset++] = 0; - buf[3] = offset - 4; /* handshake size */ - - return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset); -} - -/* - * Process the server hello. - */ -static int process_server_hello(SSL *ssl) -{ - uint8_t *buf = ssl->bm_data; - int pkt_size = ssl->bm_index; - int num_sessions = ssl->ssl_ctx->num_sessions; - uint8_t sess_id_size; - int offset, ret = SSL_OK; - - /* check that we are talking to a TLSv1 server */ - uint8_t version = (buf[4] << 4) + buf[5]; - if (version > SSL_PROTOCOL_VERSION_MAX) - { - version = SSL_PROTOCOL_VERSION_MAX; - } - else if (ssl->version < SSL_PROTOCOL_MIN_VERSION) - { - ret = SSL_ERROR_INVALID_VERSION; - ssl_display_error(ret); - goto error; - } - - ssl->version = version; - - /* get the server random value */ - memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE); - offset = 6 + SSL_RANDOM_SIZE; /* skip of session id size */ - sess_id_size = buf[offset++]; - - if (sess_id_size > SSL_SESSION_ID_SIZE) - { - ret = SSL_ERROR_INVALID_SESSION; - goto error; - } - - if (num_sessions) - { - ssl->session = ssl_session_update(num_sessions, - ssl->ssl_ctx->ssl_sessions, ssl, &buf[offset]); - memcpy(ssl->session->session_id, &buf[offset], sess_id_size); - - /* pad the rest with 0's */ - if (sess_id_size < SSL_SESSION_ID_SIZE) - { - memset(&ssl->session->session_id[sess_id_size], 0, - SSL_SESSION_ID_SIZE-sess_id_size); - } - } - - memcpy(ssl->session_id, &buf[offset], sess_id_size); - ssl->sess_id_size = sess_id_size; - offset += sess_id_size; - - /* get the real cipher we are using */ - ssl->cipher = buf[++offset]; - ssl->next_state = IS_SET_SSL_FLAG(SSL_SESSION_RESUME) ? - HS_FINISHED : HS_CERTIFICATE; - - offset++; // skip the compr - PARANOIA_CHECK(pkt_size, offset); - ssl->dc->bm_proc_index = offset+1; - -error: - return ret; -} - -/** - * Process the server hello done message. - */ -static int process_server_hello_done(SSL *ssl) -{ - ssl->next_state = HS_FINISHED; - return SSL_OK; -} - -/* - * Send a client key exchange message. - */ -static int send_client_key_xchg(SSL *ssl) -{ - uint8_t *buf = ssl->bm_data; - uint8_t premaster_secret[SSL_SECRET_SIZE]; - int enc_secret_size = -1; - - buf[0] = HS_CLIENT_KEY_XCHG; - buf[1] = 0; - - premaster_secret[0] = 0x03; /* encode the version number */ - premaster_secret[1] = SSL_PROTOCOL_MINOR_VERSION; /* must be TLS 1.1 */ - get_random(SSL_SECRET_SIZE-2, &premaster_secret[2]); - DISPLAY_RSA(ssl, ssl->x509_ctx->rsa_ctx); - - /* rsa_ctx->bi_ctx is not thread-safe */ - SSL_CTX_LOCK(ssl->ssl_ctx->mutex); - enc_secret_size = RSA_encrypt(ssl->x509_ctx->rsa_ctx, premaster_secret, - SSL_SECRET_SIZE, &buf[6], 0); - SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); - - buf[2] = (enc_secret_size + 2) >> 8; - buf[3] = (enc_secret_size + 2) & 0xff; - buf[4] = enc_secret_size >> 8; - buf[5] = enc_secret_size & 0xff; - - generate_master_secret(ssl, premaster_secret); - return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, enc_secret_size+6); -} - -/* - * Process the certificate request. - */ -static int process_cert_req(SSL *ssl) -{ - uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index]; - int ret = SSL_OK; - int offset = (buf[2] << 4) + buf[3]; - int pkt_size = ssl->bm_index; - - /* don't do any processing - we will send back an RSA certificate anyway */ - ssl->next_state = HS_SERVER_HELLO_DONE; - SET_SSL_FLAG(SSL_HAS_CERT_REQ); - ssl->dc->bm_proc_index += offset; - PARANOIA_CHECK(pkt_size, offset); -error: - return ret; -} - -/* - * Send a certificate verify message. - */ -static int send_cert_verify(SSL *ssl) -{ - uint8_t *buf = ssl->bm_data; - uint8_t dgst[MD5_SIZE+SHA1_SIZE]; - RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx; - int n = 0, ret; - - DISPLAY_RSA(ssl, rsa_ctx); - - buf[0] = HS_CERT_VERIFY; - buf[1] = 0; - - finished_digest(ssl, NULL, dgst); /* calculate the digest */ - - /* rsa_ctx->bi_ctx is not thread-safe */ - if (rsa_ctx) - { - SSL_CTX_LOCK(ssl->ssl_ctx->mutex); - n = RSA_encrypt(rsa_ctx, dgst, sizeof(dgst), &buf[6], 1); - SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); - - if (n == 0) - { - ret = SSL_ERROR_INVALID_KEY; - goto error; - } - } - - buf[4] = n >> 8; /* add the RSA size (not officially documented) */ - buf[5] = n & 0xff; - n += 2; - buf[2] = n >> 8; - buf[3] = n & 0xff; - ret = send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, n+4); - -error: - return ret; -} - -#endif /* CONFIG_SSL_ENABLE_CLIENT */ diff --git a/axTLS/src/ssl/tls1_svr.c b/axTLS/src/ssl/tls1_svr.c deleted file mode 100644 index f374928..0000000 --- a/axTLS/src/ssl/tls1_svr.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - * 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 = (record_buf[1] << 4) + record_buf[2]; - 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/axTLS/src/ssl/version.h b/axTLS/src/ssl/version.h deleted file mode 100644 index cc1ddb2..0000000 --- a/axTLS/src/ssl/version.h +++ /dev/null @@ -1 +0,0 @@ -#define AXTLS_VERSION "1.4.4" diff --git a/axTLS/src/ssl/x509.c b/axTLS/src/ssl/x509.c deleted file mode 100644 index 116fa00..0000000 --- a/axTLS/src/ssl/x509.c +++ /dev/null @@ -1,564 +0,0 @@ -/* - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include "os_port.h" -#include "crypto_misc.h" - -#ifdef CONFIG_SSL_CERT_VERIFICATION -/** - * Retrieve the signature from a certificate. - */ -static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len) -{ - int offset = 0; - const uint8_t *ptr = NULL; - - if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 || - asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE)) - goto end_get_sig; - - if (asn1_sig[offset++] != ASN1_OCTET_STRING) - goto end_get_sig; - *len = get_asn1_length(asn1_sig, &offset); - ptr = &asn1_sig[offset]; /* all ok */ - -end_get_sig: - return ptr; -} - -#endif - -/** - * Construct a new x509 object. - * @return 0 if ok. < 0 if there was a problem. - */ -int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) -{ - int begin_tbs, end_tbs; - int ret = X509_NOT_OK, offset = 0, cert_size = 0; - X509_CTX *x509_ctx; - BI_CTX *bi_ctx; - SHA1_CTX sha_ctx_fp; - - *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; - - SHA1_Init(&sha_ctx_fp); - SHA1_Update(&sha_ctx_fp, cert, cert_size); - SHA1_Final(x509_ctx->sha1_fingerprint, &sha_ctx_fp); - -#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */ - /* use the appropriate signature algorithm (SHA1/MD5/MD2) */ - if (x509_ctx->sig_type == SIG_TYPE_MD5) - { - MD5_CTX md5_ctx; - uint8_t md5_dgst[MD5_SIZE]; - MD5_Init(&md5_ctx); - MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs); - MD5_Final(md5_dgst, &md5_ctx); - x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE); - } - else if (x509_ctx->sig_type == SIG_TYPE_SHA1) - { - SHA1_CTX sha_ctx; - uint8_t sha_dgst[SHA1_SIZE]; - SHA1_Init(&sha_ctx); - SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs); - SHA1_Final(sha_dgst, &sha_ctx); - x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE); - } - else if (x509_ctx->sig_type == SIG_TYPE_MD2) - { - MD2_CTX md2_ctx; - uint8_t md2_dgst[MD2_SIZE]; - MD2_Init(&md2_ctx); - MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs); - MD2_Final(md2_dgst, &md2_ctx); - x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE); - } - - if (cert[offset] == ASN1_V3_DATA) - { - int suboffset; - - ++offset; - get_asn1_length(cert, &offset); - - if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0) - { - if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0) - { - int altlen; - - if ((altlen = asn1_next_obj(cert, - &suboffset, ASN1_SEQUENCE)) > 0) - { - int endalt = suboffset + altlen; - int totalnames = 0; - - while (suboffset < endalt) - { - int type = cert[suboffset++]; - int dnslen = get_asn1_length(cert, &suboffset); - - if (type == ASN1_CONTEXT_DNSNAME) - { - x509_ctx->subject_alt_dnsnames = (char**) - realloc(x509_ctx->subject_alt_dnsnames, - (totalnames + 2) * sizeof(char*)); - x509_ctx->subject_alt_dnsnames[totalnames] = - (char*)malloc(dnslen + 1); - x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL; - memcpy(x509_ctx->subject_alt_dnsnames[totalnames], - cert + suboffset, dnslen); - x509_ctx->subject_alt_dnsnames[ - totalnames][dnslen] = 0; - ++totalnames; - } - - suboffset += dnslen; - } - } - } - } - } - - offset = end_tbs; /* skip the rest of v3 data */ - if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || - asn1_signature(cert, &offset, x509_ctx)) - goto end_cert; -#endif - ret = X509_OK; -end_cert: - if (len) - { - *len = cert_size; - } - - if (ret) - { -#ifdef CONFIG_SSL_FULL_MODE - printf("Error: Invalid X509 ASN.1 file (%s)\n", - x509_display_error(ret)); -#endif - x509_free(x509_ctx); - *ctx = NULL; - } - - return ret; -} - -/** - * Free an X.509 object's resources. - */ -void x509_free(X509_CTX *x509_ctx) -{ - X509_CTX *next; - int i; - - if (x509_ctx == NULL) /* if already null, then don't bother */ - return; - - for (i = 0; i < X509_NUM_DN_TYPES; i++) - { - free(x509_ctx->ca_cert_dn[i]); - free(x509_ctx->cert_dn[i]); - } - - free(x509_ctx->signature); - -#ifdef CONFIG_SSL_CERT_VERIFICATION - if (x509_ctx->digest) - { - bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest); - } - - if (x509_ctx->subject_alt_dnsnames) - { - for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i) - free(x509_ctx->subject_alt_dnsnames[i]); - - free(x509_ctx->subject_alt_dnsnames); - } -#endif - - RSA_free(x509_ctx->rsa_ctx); - next = x509_ctx->next; - free(x509_ctx); - x509_free(next); /* clear the chain */ -} - -#ifdef CONFIG_SSL_CERT_VERIFICATION -/** - * Take a signature and decrypt it. - */ -static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, - bigint *modulus, bigint *pub_exp) -{ - int i, size; - bigint *decrypted_bi, *dat_bi; - bigint *bir = NULL; - uint8_t *block = (uint8_t *)alloca(sig_len); - - /* decrypt */ - dat_bi = bi_import(ctx, sig, sig_len); - ctx->mod_offset = BIGINT_M_OFFSET; - - /* convert to a normal block */ - decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp); - - bi_export(ctx, decrypted_bi, block, sig_len); - ctx->mod_offset = BIGINT_M_OFFSET; - - i = 10; /* start at the first possible non-padded byte */ - while (block[i++] && i < sig_len); - size = sig_len - i; - - /* get only the bit we want */ - if (size > 0) - { - int len; - const uint8_t *sig_ptr = get_signature(&block[i], &len); - - if (sig_ptr) - { - bir = bi_import(ctx, sig_ptr, len); - } - } - - /* save a few bytes of memory */ - bi_clear_cache(ctx); - return bir; -} - -/** - * Do some basic checks on the certificate chain. - * - * Certificate verification consists of a number of checks: - * - The date of the certificate is after the start date. - * - The date of the certificate is before the finish date. - * - A root certificate exists in the certificate store. - * - That the certificate(s) are not self-signed. - * - The certificate chain is valid. - * - The signature of the certificate is valid. - */ -int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert) -{ - int ret = X509_OK, i = 0; - bigint *cert_sig; - X509_CTX *next_cert = NULL; - BI_CTX *ctx = NULL; - bigint *mod = NULL, *expn = NULL; - int match_ca_cert = 0; - struct timeval tv; - uint8_t is_self_signed = 0; - - if (cert == NULL) - { - ret = X509_VFY_ERROR_NO_TRUSTED_CERT; - goto end_verify; - } - - /* a self-signed certificate that is not in the CA store - use this - to check the signature */ - if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0) - { - is_self_signed = 1; - ctx = cert->rsa_ctx->bi_ctx; - mod = cert->rsa_ctx->m; - expn = cert->rsa_ctx->e; - } - - gettimeofday(&tv, NULL); - - /* check the not before date */ - if (tv.tv_sec < cert->not_before) - { - ret = X509_VFY_ERROR_NOT_YET_VALID; - goto end_verify; - } - - /* check the not after date */ - if (tv.tv_sec > cert->not_after) - { - ret = X509_VFY_ERROR_EXPIRED; - goto end_verify; - } - - next_cert = cert->next; - - /* last cert in the chain - look for a trusted cert */ - if (next_cert == NULL) - { - if (ca_cert_ctx != NULL) - { - /* go thu the CA store */ - while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) - { - if (asn1_compare_dn(cert->ca_cert_dn, - ca_cert_ctx->cert[i]->cert_dn) == 0) - { - /* use this CA certificate for signature verification */ - match_ca_cert = 1; - ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx; - mod = ca_cert_ctx->cert[i]->rsa_ctx->m; - expn = ca_cert_ctx->cert[i]->rsa_ctx->e; - break; - } - - i++; - } - } - - /* couldn't find a trusted cert (& let self-signed errors - be returned) */ - if (!match_ca_cert && !is_self_signed) - { - ret = X509_VFY_ERROR_NO_TRUSTED_CERT; - goto end_verify; - } - } - else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0) - { - /* check the chain */ - ret = X509_VFY_ERROR_INVALID_CHAIN; - goto end_verify; - } - else /* use the next certificate in the chain for signature verify */ - { - ctx = next_cert->rsa_ctx->bi_ctx; - mod = next_cert->rsa_ctx->m; - expn = next_cert->rsa_ctx->e; - } - - /* cert is self signed */ - if (!match_ca_cert && is_self_signed) - { - ret = X509_VFY_ERROR_SELF_SIGNED; - goto end_verify; - } - - /* check the signature */ - cert_sig = sig_verify(ctx, cert->signature, cert->sig_len, - bi_clone(ctx, mod), bi_clone(ctx, expn)); - - if (cert_sig && cert->digest) - { - if (bi_compare(cert_sig, cert->digest) != 0) - ret = X509_VFY_ERROR_BAD_SIGNATURE; - - - bi_free(ctx, cert_sig); - } - else - { - ret = X509_VFY_ERROR_BAD_SIGNATURE; - } - - if (ret) - goto end_verify; - - /* go down the certificate chain using recursion. */ - if (next_cert != NULL) - { - ret = x509_verify(ca_cert_ctx, next_cert); - } - -end_verify: - return ret; -} -#endif - -#if defined (CONFIG_SSL_FULL_MODE) -/** - * Used for diagnostics. - */ -static const char *not_part_of_cert = "<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\n", cert->cert_dn[X509_COMMON_NAME] ? - cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert); - - printf("Organization (O):\t\t"); - printf("%s\n", cert->cert_dn[X509_ORGANIZATION] ? - cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert); - - printf("Organizational Unit (OU):\t"); - printf("%s\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ? - cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert); - - printf("=== CERTIFICATE ISSUED BY ===\n"); - printf("Common Name (CN):\t\t"); - printf("%s\n", cert->ca_cert_dn[X509_COMMON_NAME] ? - cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert); - - printf("Organization (O):\t\t"); - printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATION] ? - cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert); - - printf("Organizational Unit (OU):\t"); - printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ? - cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert); - - printf("Not Before:\t\t\t%s", ctime(&cert->not_before)); - printf("Not After:\t\t\t%s", ctime(&cert->not_after)); - printf("RSA bitsize:\t\t\t%d\n", cert->rsa_ctx->num_octets*8); - printf("Sig Type:\t\t\t"); - switch (cert->sig_type) - { - case SIG_TYPE_MD5: - printf("MD5\n"); - break; - case SIG_TYPE_SHA1: - printf("SHA1\n"); - break; - case SIG_TYPE_MD2: - printf("MD2\n"); - break; - default: - printf("Unrecognized: %d\n", cert->sig_type); - break; - } - - if (ca_cert_ctx) - { - printf("Verify:\t\t\t\t%s\n", - x509_display_error(x509_verify(ca_cert_ctx, cert))); - } - -#if 0 - print_blob("Signature", cert->signature, cert->sig_len); - bi_print("Modulus", cert->rsa_ctx->m); - bi_print("Pub Exp", cert->rsa_ctx->e); -#endif - - if (ca_cert_ctx) - { - x509_print(cert->next, ca_cert_ctx); - } - - TTY_FLUSH(); -} - -const char * x509_display_error(int error) -{ - switch (error) - { - case X509_OK: - return "Certificate verify successful"; - - case X509_NOT_OK: - return "X509 not ok"; - - case X509_VFY_ERROR_NO_TRUSTED_CERT: - return "No trusted cert is available"; - - case X509_VFY_ERROR_BAD_SIGNATURE: - return "Bad signature"; - - case X509_VFY_ERROR_NOT_YET_VALID: - return "Cert is not yet valid"; - - case X509_VFY_ERROR_EXPIRED: - return "Cert has expired"; - - case X509_VFY_ERROR_SELF_SIGNED: - return "Cert is self-signed"; - - case X509_VFY_ERROR_INVALID_CHAIN: - return "Chain is invalid (check order of certs)"; - - case X509_VFY_ERROR_UNSUPPORTED_DIGEST: - return "Unsupported digest"; - - case X509_INVALID_PRIV_KEY: - return "Invalid private key"; - - default: - return "Unknown"; - } -} -#endif /* CONFIG_SSL_FULL_MODE */ - diff --git a/axTLS/src/www/index.html b/axTLS/src/www/index.html deleted file mode 100644 index 7055794..0000000 --- a/axTLS/src/www/index.html +++ /dev/null @@ -1,7106 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head> -<script type="text/javascript"> -//<![CDATA[ -var version = {major: 2, minor: 1, revision: 3, date: new Date("Nov 3, 2006"), extensions: {}}; -//]]> -</script> -<!-- -TiddlyWiki 2.1.3 by Jeremy Ruston, (jeremy [at] osmosoft [dot] com) - -Copyright (c) Osmosoft Limited 2004-2006 - -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 Osmosoft Limited 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. ---> -<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> -<!--PRE-HEAD-START--> -<!--{{{--> -<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/> -<!--}}}--> -<!--PRE-HEAD-END--> -<title> axTLS Embedded SSL - changes, notes and errata </title> -<script type="text/javascript"> -//<![CDATA[ -// --------------------------------------------------------------------------------- -// Configuration repository -// --------------------------------------------------------------------------------- - -// Miscellaneous options -var config = { - numRssItems: 20, // Number of items in the RSS feed - animFast: 0.12, // Speed for animations (lower == slower) - animSlow: 0.01, // Speed for EasterEgg animations - cascadeFast: 20, // Speed for cascade animations (higher == slower) - cascadeSlow: 60, // Speed for EasterEgg cascade animations - cascadeDepth: 5, // Depth of cascade animation - displayStartupTime: false // Whether to display startup time - }; - -// Messages -config.messages = { - messageClose: {}, - dates: {} -}; - -// Options that can be set in the options panel and/or cookies -config.options = { - chkRegExpSearch: false, - chkCaseSensitiveSearch: false, - chkAnimate: true, - chkSaveBackups: true, - chkAutoSave: false, - chkGenerateAnRssFeed: false, - chkSaveEmptyTemplate: false, - chkOpenInNewWindow: true, - chkToggleLinks: false, - chkHttpReadOnly: true, - chkForceMinorUpdate: false, - chkConfirmDelete: true, - chkInsertTabs: false, - txtBackupFolder: "", - txtMainTab: "tabTimeline", - txtMoreTab: "moreTabAll", - txtMaxEditRows: "30" - }; - -// List of notification functions to be called when certain tiddlers are changed or deleted -config.notifyTiddlers = [ - {name: "StyleSheetLayout", notify: refreshStyles}, - {name: "StyleSheetColors", notify: refreshStyles}, - {name: "StyleSheet", notify: refreshStyles}, - {name: "StyleSheetPrint", notify: refreshStyles}, - {name: "PageTemplate", notify: refreshPageTemplate}, - {name: "SiteTitle", notify: refreshPageTitle}, - {name: "SiteSubtitle", notify: refreshPageTitle}, - {name: "ColorPalette", notify: refreshColorPalette}, - {name: null, notify: refreshDisplay} - ]; - -// Default tiddler templates -var DEFAULT_VIEW_TEMPLATE = 1; -var DEFAULT_EDIT_TEMPLATE = 2; -config.tiddlerTemplates = { - 1: "ViewTemplate", - 2: "EditTemplate" - }; - -// More messages (rather a legacy layout that shouldn't really be like this) -config.views = { - wikified: { - tag: {} - }, - editor: { - tagChooser: {} - } - }; - -// Macros; each has a 'handler' member that is inserted later -config.macros = { - today: {}, - version: {}, - search: {sizeTextbox: 15}, - tiddler: {}, - tag: {}, - tags: {}, - tagging: {}, - timeline: {}, - allTags: {}, - list: { - all: {}, - missing: {}, - orphans: {}, - shadowed: {} - }, - closeAll: {}, - permaview: {}, - saveChanges: {}, - slider: {}, - option: {}, - newTiddler: {}, - newJournal: {}, - sparkline: {}, - tabs: {}, - gradient: {}, - message: {}, - view: {}, - edit: {}, - tagChooser: {}, - toolbar: {}, - br: {}, - plugins: {}, - refreshDisplay: {}, - importTiddlers: {} - }; - -// Commands supported by the toolbar macro -config.commands = { - closeTiddler: {}, - closeOthers: {}, - editTiddler: {}, - saveTiddler: {hideReadOnly: true}, - cancelTiddler: {}, - deleteTiddler: {hideReadOnly: true}, - permalink: {}, - references: {}, - jump: {} - }; - -// Browser detection... In a very few places, there's nothing else for it but to -// know what browser we're using. -config.userAgent = navigator.userAgent.toLowerCase(); -config.browser = { - isIE: config.userAgent.indexOf("msie") != -1 && config.userAgent.indexOf("opera") == -1, - ieVersion: /MSIE (\d.\d)/i.exec(config.userAgent), // config.browser.ieVersion[1], if it exists, will be the IE version string, eg "6.0" - isSafari: config.userAgent.indexOf("applewebkit") != -1, - isBadSafari: !((new RegExp("[\u0150\u0170]","g")).test("\u0150")), - firefoxDate: /Gecko\/(\d{8})/i.exec(config.userAgent), // config.browser.firefoxDate[1], if it exists, will be Firefox release date as "YYYYMMDD" - isOpera: config.userAgent.indexOf("opera") != -1, - isLinux: config.userAgent.indexOf("linux") != -1, - isUnix: config.userAgent.indexOf("x11") != -1, - isMac: config.userAgent.indexOf("mac") != -1, - isWindows: config.userAgent.indexOf("win") != -1 - }; - -// Basic regular expressions -config.textPrimitives = { - upperLetter: "[A-Z\u00c0-\u00de\u0150\u0170]", - lowerLetter: "[a-z0-9_\\-\u00df-\u00ff\u0151\u0171]", - anyLetter: "[A-Za-z0-9_\\-\u00c0-\u00de\u00df-\u00ff\u0150\u0170\u0151\u0171]", - anyLetterStrict: "[A-Za-z0-9\u00c0-\u00de\u00df-\u00ff\u0150\u0170\u0151\u0171]" - }; -if(config.browser.isBadSafari) - config.textPrimitives = { - upperLetter: "[A-Z\u00c0-\u00de]", - lowerLetter: "[a-z0-9_\\-\u00df-\u00ff]", - anyLetter: "[A-Za-z0-9_\\-\u00c0-\u00de\u00df-\u00ff]", - anyLetterStrict: "[A-Za-z0-9\u00c0-\u00de\u00df-\u00ff]" - } -config.textPrimitives.sliceSeparator = "::"; -config.textPrimitives.urlPattern = "[a-z]{3,8}:[^\\s:'\"][^\\s'\"]*(?:/|\\b)"; -config.textPrimitives.unWikiLink = "~"; -config.textPrimitives.wikiLink = "(?:(?:" + config.textPrimitives.upperLetter + "+" + - config.textPrimitives.lowerLetter + "+" + - config.textPrimitives.upperLetter + - config.textPrimitives.anyLetter + "*)|(?:" + - config.textPrimitives.upperLetter + "{2,}" + - config.textPrimitives.lowerLetter + "+))"; - -config.textPrimitives.cssLookahead = "(?:(" + config.textPrimitives.anyLetter + "+)\\(([^\\)\\|\\n]+)(?:\\):))|(?:(" + config.textPrimitives.anyLetter + "+):([^;\\|\\n]+);)"; -config.textPrimitives.cssLookaheadRegExp = new RegExp(config.textPrimitives.cssLookahead,"mg"); - -config.textPrimitives.brackettedLink = "\\[\\[([^\\]]+)\\]\\]"; -config.textPrimitives.titledBrackettedLink = "\\[\\[([^\\[\\]\\|]+)\\|([^\\[\\]\\|]+)\\]\\]"; -config.textPrimitives.tiddlerForcedLinkRegExp = new RegExp("(?:" + config.textPrimitives.titledBrackettedLink + ")|(?:" + - config.textPrimitives.brackettedLink + ")|(?:" + - config.textPrimitives.urlPattern + ")","mg"); -config.textPrimitives.tiddlerAnyLinkRegExp = new RegExp("("+ config.textPrimitives.wikiLink + ")|(?:" + - config.textPrimitives.titledBrackettedLink + ")|(?:" + - config.textPrimitives.brackettedLink + ")|(?:" + - config.textPrimitives.urlPattern + ")","mg"); - -// --------------------------------------------------------------------------------- -// Shadow tiddlers -// --------------------------------------------------------------------------------- - -config.shadowTiddlers = { - ColorPalette: "Background: #fff\n" + - "Foreground: #000\n" + - "PrimaryPale: #8cf\n" + - "PrimaryLight: #18f\n" + - "PrimaryMid: #04b\n" + - "PrimaryDark: #014\n" + - "SecondaryPale: #ffc\n" + - "SecondaryLight: #fe8\n" + - "SecondaryMid: #db4\n" + - "SecondaryDark: #841\n" + - "TertiaryPale: #eee\n" + - "TertiaryLight: #ccc\n" + - "TertiaryMid: #999\n" + - "TertiaryDark: #666\n" + - "Error: #f88\n", - StyleSheet: "", - StyleSheetColors: "/*{{{*/\nbody {\n background: [[ColorPalette::Background]];\n color: [[ColorPalette::Foreground]];\n}\n\na{\n color: [[ColorPalette::PrimaryMid]];\n}\n\na:hover{\n background: [[ColorPalette::PrimaryMid]];\n color: [[ColorPalette::Background]];\n}\n\na img{\n border: 0;\n}\n\nh1,h2,h3,h4,h5 {\n color: [[ColorPalette::SecondaryDark]];\n background: [[ColorPalette::PrimaryPale]];\n}\n\n.button {\n color: [[ColorPalette::PrimaryDark]];\n border: 1px solid [[ColorPalette::Background]];\n}\n\n.button:hover {\n color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::SecondaryLight]];\n border-color: [[ColorPalette::SecondaryMid]];\n}\n\n.button:active {\n color: [[ColorPalette::Background]];\n background: [[ColorPalette::SecondaryMid]];\n border: 1px solid [[ColorPalette::SecondaryDark]];\n}\n\n.header {\n background: [[ColorPalette::PrimaryMid]];\n}\n\n.headerShadow {\n color: [[ColorPalette::Foreground]];\n}\n\n.headerShadow a {\n font-weight: normal;\n color: [[ColorPalette::Foreground]];\n}\n\n.headerForeground {\n color: [[ColorPalette::Background]];\n}\n\n.headerForeground a {\n font-weight: normal;\n color: [[ColorPalette::PrimaryPale]];\n}\n\n.tabSelected{\n color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::TertiaryPale]];\n border-left: 1px solid [[ColorPalette::TertiaryLight]];\n border-top: 1px solid [[ColorPalette::TertiaryLight]];\n border-right: 1px solid [[ColorPalette::TertiaryLight]];\n}\n\n.tabUnselected {\n color: [[ColorPalette::Background]];\n background: [[ColorPalette::TertiaryMid]];\n}\n\n.tabContents {\n color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::TertiaryPale]];\n border: 1px solid [[ColorPalette::TertiaryLight]];\n}\n\n.tabContents .button {\n border: 0;}\n\n#sidebar {\n}\n\n#sidebarOptions input {\n border: 1px solid [[ColorPalette::PrimaryMid]];\n}\n\n#sidebarOptions .sliderPanel {\n background: [[ColorPalette::PrimaryPale]];\n}\n\n#sidebarOptions .sliderPanel a {\n border: none;\n color: [[ColorPalette::PrimaryMid]];\n}\n\n#sidebarOptions .sliderPanel a:hover {\n color: [[ColorPalette::Background]];\n background: [[ColorPalette::PrimaryMid]];\n}\n\n#sidebarOptions .sliderPanel a:active {\n color: [[ColorPalette::PrimaryMid]];\n background: [[ColorPalette::Background]];\n}\n\n.wizard {\n background: [[ColorPalette::SecondaryLight]];\n border-top: 1px solid [[ColorPalette::SecondaryMid]];\n border-left: 1px solid [[ColorPalette::SecondaryMid]];\n}\n\n.wizard h1 {\n color: [[ColorPalette::SecondaryDark]];\n}\n\n.wizard h2 {\n color: [[ColorPalette::Foreground]];\n}\n\n.wizardStep {\n background: [[ColorPalette::Background]];\n border-top: 1px solid [[ColorPalette::SecondaryMid]];\n border-bottom: 1px solid [[ColorPalette::SecondaryMid]];\n border-left: 1px solid [[ColorPalette::SecondaryMid]];\n}\n\n.wizard .button {\n color: [[ColorPalette::Background]];\n background: [[ColorPalette::PrimaryMid]];\n border-top: 1px solid [[ColorPalette::PrimaryLight]];\n border-right: 1px solid [[ColorPalette::PrimaryDark]];\n border-bottom: 1px solid [[ColorPalette::PrimaryDark]];\n border-left: 1px solid [[ColorPalette::PrimaryLight]];\n}\n\n.wizard .button:hover {\n color: [[ColorPalette::PrimaryLight]];\n background: [[ColorPalette::PrimaryDark]];\n border-color: [[ColorPalette::PrimaryLight]];\n}\n\n.wizard .button:active {\n color: [[ColorPalette::Background]];\n background: [[ColorPalette::PrimaryMid]];\n border-top: 1px solid [[ColorPalette::PrimaryLight]];\n border-right: 1px solid [[ColorPalette::PrimaryDark]];\n border-bottom: 1px solid [[ColorPalette::PrimaryDark]];\n border-left: 1px solid [[ColorPalette::PrimaryLight]];\n}\n\n#messageArea {\n border: 1px solid [[ColorPalette::SecondaryDark]];\n background: [[ColorPalette::SecondaryMid]];\n color: [[ColorPalette::PrimaryDark]];\n}\n\n#messageArea .button {\n padding: 0.2em 0.2em 0.2em 0.2em;\n color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::Background]];\n}\n\n.popup {\n background: [[ColorPalette::PrimaryLight]];\n border: 1px solid [[ColorPalette::PrimaryMid]];\n}\n\n.popup hr {\n color: [[ColorPalette::PrimaryDark]];\n background: [[ColorPalette::PrimaryDark]];\n border-bottom: 1px;\n}\n\n.listBreak div{\n border-bottom: 1px solid [[ColorPalette::PrimaryDark]];\n}\n\n.popup li.disabled {\n color: [[ColorPalette::PrimaryMid]];\n}\n\n.popup li a, .popup li a:visited {\n color: [[ColorPalette::TertiaryPale]];\n border: none;\n}\n\n.popup li a:hover {\n background: [[ColorPalette::PrimaryDark]];\n color: [[ColorPalette::Background]];\n border: none;\n}\n\n.tiddler .defaultCommand {\n font-weight: bold;\n}\n\n.shadow .title {\n color: [[ColorPalette::TertiaryDark]];\n}\n\n.title {\n color: [[ColorPalette::SecondaryDark]];\n}\n\n.subtitle {\n color: [[ColorPalette::TertiaryDark]];\n}\n\n.toolbar {\n color: [[ColorPalette::PrimaryMid]];\n}\n\n.tagging, .tagged {\n border: 1px solid [[ColorPalette::TertiaryPale]];\n background-color: [[ColorPalette::TertiaryPale]];\n}\n\n.selected .tagging, .selected .tagged {\n background-color: [[ColorPalette::TertiaryLight]];\n border: 1px solid [[ColorPalette::TertiaryMid]];\n}\n\n.tagging .listTitle, .tagged .listTitle {\n color: [[ColorPalette::PrimaryDark]];\n}\n\n.tagging .button, .tagged .button {\n border: none;\n}\n\n.footer {\n color: [[ColorPalette::TertiaryLight]];\n}\n\n.selected .footer {\n color: [[ColorPalette::TertiaryMid]];\n}\n\n.sparkline {\n background: [[ColorPalette::PrimaryPale]];\n border: 0;\n}\n\n.sparktick {\n background: [[ColorPalette::PrimaryDark]];\n}\n\n.error, .errorButton {\n color: [[ColorPalette::Foreground]];\n background: [[ColorPalette::Error]];\n}\n\n.warning {\n color: [[ColorPalette::Foreground]];\n background: [[ColorPalette::SecondaryPale]];\n}\n\n.cascade {\n background: [[ColorPalette::TertiaryPale]];\n color: [[ColorPalette::TertiaryMid]];\n border: 1px solid [[ColorPalette::TertiaryMid]];\n}\n\n.imageLink, #displayArea .imageLink {\n background: transparent;\n}\n\n.viewer .listTitle {list-style-type: none; margin-left: -2em;}\n\n.viewer .button {\n border: 1px solid [[ColorPalette::SecondaryMid]];\n}\n\n.viewer blockquote {\n border-left: 3px solid [[ColorPalette::TertiaryDark]];\n}\n\n.viewer table {\n border: 2px solid [[ColorPalette::TertiaryDark]];\n}\n\n.viewer th, thead td {\n background: [[ColorPalette::SecondaryMid]];\n border: 1px solid [[ColorPalette::TertiaryDark]];\n color: [[ColorPalette::Background]];\n}\n\n.viewer td, .viewer tr {\n border: 1px solid [[ColorPalette::TertiaryDark]];\n}\n\n.viewer pre {\n border: 1px solid [[ColorPalette::SecondaryLight]];\n background: [[ColorPalette::SecondaryPale]];\n}\n\n.viewer code {\n color: [[ColorPalette::SecondaryDark]];\n}\n\n.viewer hr {\n border: 0;\n border-top: dashed 1px [[ColorPalette::TertiaryDark]];\n color: [[ColorPalette::TertiaryDark]];\n}\n\n.highlight, .marked {\n background: [[ColorPalette::SecondaryLight]];\n}\n\n.editor input {\n border: 1px solid [[ColorPalette::PrimaryMid]];\n}\n\n.editor textarea {\n border: 1px solid [[ColorPalette::PrimaryMid]];\n width: 100%;\n}\n\n.editorFooter {\n color: [[ColorPalette::TertiaryMid]];\n}\n\n/*}}}*/", - StyleSheetLayout: "/*{{{*/\n* html .tiddler {\n height: 1%;\n}\n\nbody {\n font-size: .75em;\n font-family: arial,helvetica;\n margin: 0;\n padding: 0;\n}\n\nh1,h2,h3,h4,h5 {\n font-weight: bold;\n text-decoration: none;\n padding-left: 0.4em;\n}\n\nh1 {font-size: 1.35em;}\nh2 {font-size: 1.25em;}\nh3 {font-size: 1.1em;}\nh4 {font-size: 1em;}\nh5 {font-size: .9em;}\n\nhr {\n height: 1px;\n}\n\na{\n text-decoration: none;\n}\n\ndt {font-weight: bold;}\n\nol { list-style-type: decimal }\nol ol { list-style-type: lower-alpha }\nol ol ol { list-style-type: lower-roman }\nol ol ol ol { list-style-type: decimal }\nol ol ol ol ol { list-style-type: lower-alpha }\nol ol ol ol ol ol { list-style-type: lower-roman }\nol ol ol ol ol ol ol { list-style-type: decimal }\n\n.txtOptionInput {\n width: 11em;\n}\n\n#contentWrapper .chkOptionInput {\n border: 0;\n}\n\n.externalLink {\n text-decoration: underline;\n}\n\n.indent {margin-left:3em;}\n.outdent {margin-left:3em; text-indent:-3em;}\ncode.escaped {white-space:nowrap;}\n\n.tiddlyLinkExisting {\n font-weight: bold;\n}\n\n.tiddlyLinkNonExisting {\n font-style: italic;\n}\n\n/* the 'a' is required for IE, otherwise it renders the whole tiddler a bold */\na.tiddlyLinkNonExisting.shadow {\n font-weight: bold;\n}\n\n#mainMenu .tiddlyLinkExisting, \n#mainMenu .tiddlyLinkNonExisting,\n#sidebarTabs .tiddlyLinkNonExisting{\n font-weight: normal;\n font-style: normal;\n}\n\n#sidebarTabs .tiddlyLinkExisting {\n font-weight: bold;\n font-style: normal;\n}\n\n.header {\n position: relative;\n}\n\n.header a:hover {\n background: transparent;\n}\n\n.headerShadow {\n position: relative;\n padding: 4.5em 0em 1em 1em;\n left: -1px;\n top: -1px;\n}\n\n.headerForeground {\n position: absolute;\n padding: 4.5em 0em 1em 1em;\n left: 0px;\n top: 0px;\n}\n\n.siteTitle {\n font-size: 3em;\n}\n\n.siteSubtitle {\n font-size: 1.2em;\n}\n\n#mainMenu {\n position: absolute;\n left: 0;\n width: 10em;\n text-align: right;\n line-height: 1.6em;\n padding: 1.5em 0.5em 0.5em 0.5em;\n font-size: 1.1em;\n}\n\n#sidebar {\n position: absolute;\n right: 3px;\n width: 16em;\n font-size: .9em;\n}\n\n#sidebarOptions {\n padding-top: 0.3em;\n}\n\n#sidebarOptions a {\n margin: 0em 0.2em;\n padding: 0.2em 0.3em;\n display: block;\n}\n\n#sidebarOptions input {\n margin: 0.4em 0.5em;\n}\n\n#sidebarOptions .sliderPanel {\n margin-left: 1em;\n padding: 0.5em;\n font-size: .85em;\n}\n\n#sidebarOptions .sliderPanel a {\n font-weight: bold;\n display: inline;\n padding: 0;\n}\n\n#sidebarOptions .sliderPanel input {\n margin: 0 0 .3em 0;\n}\n\n#sidebarTabs .tabContents {\n width: 15em;\n overflow: hidden;\n}\n\n.wizard {\n padding: 0.1em 0em 0em 2em;\n}\n\n.wizard h1 {\n font-size: 2em;\n font-weight: bold;\n background: none;\n padding: 0em 0em 0em 0em;\n margin: 0.4em 0em 0.2em 0em;\n}\n\n.wizard h2 {\n font-size: 1.2em;\n font-weight: bold;\n background: none;\n padding: 0em 0em 0em 0em;\n margin: 0.2em 0em 0.2em 0em;\n}\n\n.wizardStep {\n padding: 1em 1em 1em 1em;\n}\n\n.wizard .button {\n margin: 0.5em 0em 0em 0em;\n font-size: 1.2em;\n}\n\n#messageArea {\nposition:absolute; top:0; right:0; margin: 0.5em; padding: 0.5em;\n}\n\n*[id='messageArea'] {\nposition:fixed !important; z-index:99;}\n\n.messageToolbar {\ndisplay: block;\ntext-align: right;\n}\n\n#messageArea a{\n text-decoration: underline;\n}\n\n.popup {\n font-size: .9em;\n padding: 0.2em;\n list-style: none;\n margin: 0;\n}\n\n.popup hr {\n display: block;\n height: 1px;\n width: auto;\n padding: 0;\n margin: 0.2em 0em;\n}\n\n.listBreak {\n font-size: 1px;\n line-height: 1px;\n}\n\n.listBreak div {\n margin: 2px 0;\n}\n\n.popup li.disabled {\n padding: 0.2em;\n}\n\n.popup li a{\n display: block;\n padding: 0.2em;\n}\n\n.tabset {\n padding: 1em 0em 0em 0.5em;\n}\n\n.tab {\n margin: 0em 0em 0em 0.25em;\n padding: 2px;\n}\n\n.tabContents {\n padding: 0.5em;\n}\n\n.tabContents ul, .tabContents ol {\n margin: 0;\n padding: 0;\n}\n\n.txtMainTab .tabContents li {\n list-style: none;\n}\n\n.tabContents li.listLink {\n margin-left: .75em;\n}\n\n#displayArea {\n margin: 1em 17em 0em 14em;\n}\n\n\n.toolbar {\n text-align: right;\n font-size: .9em;\n visibility: hidden;\n}\n\n.selected .toolbar {\n visibility: visible;\n}\n\n.tiddler {\n padding: 1em 1em 0em 1em;\n}\n\n.missing .viewer,.missing .title {\n font-style: italic;\n}\n\n.title {\n font-size: 1.6em;\n font-weight: bold;\n}\n\n.missing .subtitle {\n display: none;\n}\n\n.subtitle {\n font-size: 1.1em;\n}\n\n.tiddler .button {\n padding: 0.2em 0.4em;\n}\n\n.tagging {\nmargin: 0.5em 0.5em 0.5em 0;\nfloat: left;\ndisplay: none;\n}\n\n.isTag .tagging {\ndisplay: block;\n}\n\n.tagged {\nmargin: 0.5em;\nfloat: right;\n}\n\n.tagging, .tagged {\nfont-size: 0.9em;\npadding: 0.25em;\n}\n\n.tagging ul, .tagged ul {\nlist-style: none;margin: 0.25em;\npadding: 0;\n}\n\n.tagClear {\nclear: both;\n}\n\n.footer {\n font-size: .9em;\n}\n\n.footer li {\ndisplay: inline;\n}\n\n* html .viewer pre {\n width: 99%;\n padding: 0 0 1em 0;\n}\n\n.viewer {\n line-height: 1.4em;\n padding-top: 0.5em;\n}\n\n.viewer .button {\n margin: 0em 0.25em;\n padding: 0em 0.25em;\n}\n\n.viewer blockquote {\n line-height: 1.5em;\n padding-left: 0.8em;\n margin-left: 2.5em;\n}\n\n.viewer ul, .viewer ol{\n margin-left: 0.5em;\n padding-left: 1.5em;\n}\n\n.viewer table {\n border-collapse: collapse;\n margin: 0.8em 1.0em;\n}\n\n.viewer th, .viewer td, .viewer tr,.viewer caption{\n padding: 3px;\n}\n\n.viewer table.listView {\n font-size: 0.85em;\n margin: 0.8em 1.0em;\n}\n\n.viewer table.listView th, .viewer table.listView td, .viewer table.listView tr {\n padding: 0px 3px 0px 3px;\n}\n\n.viewer pre {\n padding: 0.5em;\n margin-left: 0.5em;\n font-size: 1.2em;\n line-height: 1.4em;\n overflow: auto;\n}\n\n.viewer code {\n font-size: 1.2em;\n line-height: 1.4em;\n}\n\n.editor {\nfont-size: 1.1em;\n}\n\n.editor input, .editor textarea {\n display: block;\n width: 100%;\n font: inherit;\n}\n\n.editorFooter {\n padding: 0.25em 0em;\n font-size: .9em;\n}\n\n.editorFooter .button {\npadding-top: 0px; padding-bottom: 0px;}\n\n.fieldsetFix {border: 0;\npadding: 0;\nmargin: 1px 0px 1px 0px;\n}\n\n.sparkline {\n line-height: 1em;\n}\n\n.sparktick {\n outline: 0;\n}\n\n.zoomer {\n font-size: 1.1em;\n position: absolute;\n padding: 1em;\n}\n\n.cascade {\n font-size: 1.1em;\n position: absolute;\n overflow: hidden;\n}\n/*}}}*/", - StyleSheetPrint: "/*{{{*/\n@media print {\n#mainMenu, #sidebar, #messageArea, .toolbar {display: none ! important;}\n#displayArea {margin: 1em 1em 0em 1em;}\n/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */\nnoscript {display:none;}\n}\n/*}}}*/", - PageTemplate: "<!--{{{-->\n<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>\n<div class='headerShadow'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span> \n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n<div class='headerForeground'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span> \n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n</div>\n<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>\n<div id='sidebar'>\n<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>\n<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>\n</div>\n<div id='displayArea'>\n<div id='messageArea'></div>\n<div id='tiddlerDisplay'></div>\n</div>\n<!--}}}-->", - ViewTemplate: "<!--{{{-->\n<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler permalink references jump'></div>\n<div class='title' macro='view title'></div>\n<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date [[DD MMM YYYY]]'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date [[DD MMM YYYY]]'></span>)</div>\n<div class='tagging' macro='tagging'></div>\n<div class='tagged' macro='tags'></div>\n<div class='viewer' macro='view text wikified'></div>\n<div class='tagClear'></div>\n<!--}}}-->", - EditTemplate: "<!--{{{-->\n<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'></div>\n<div class='title' macro='view title'></div>\n<div class='editor' macro='edit title'></div>\n<div class='editor' macro='edit text'></div>\n<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>\n<!--}}}-->", - MarkupPreHead: "<!--{{{-->\n<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/>\n<!--}}}-->", - MarkupPostHead: "", - MarkupPreBody: "", - MarkupPostBody: "" - }; - -// --------------------------------------------------------------------------------- -// Translateable strings -// --------------------------------------------------------------------------------- - -// Strings in "double quotes" should be translated; strings in 'single quotes' should be left alone - -merge(config.options,{ - txtUserName: "YourName"}); - -merge(config.messages,{ - customConfigError: "Problems were encountered loading plugins. See PluginManager for details", - pluginError: "Error: %0", - pluginDisabled: "Not executed because disabled via 'systemConfigDisable' tag", - pluginForced: "Executed because forced via 'systemConfigForce' tag", - pluginVersionError: "Not executed because this plugin needs a newer version of TiddlyWiki", - nothingSelected: "Nothing is selected. You must select one or more items first", - savedSnapshotError: "It appears that this TiddlyWiki has been incorrectly saved. Please see http://www.tiddlywiki.com/#DownloadSoftware for details", - subtitleUnknown: "(unknown)", - undefinedTiddlerToolTip: "The tiddler '%0' doesn't yet exist", - shadowedTiddlerToolTip: "The tiddler '%0' doesn't yet exist, but has a pre-defined shadow value", - tiddlerLinkTooltip: "%0 - %1, %2", - externalLinkTooltip: "External link to %0", - noTags: "There are no tagged tiddlers", - notFileUrlError: "You need to save this TiddlyWiki to a file before you can save changes", - cantSaveError: "It's not possible to save changes. This could be because your browser doesn't support saving (instead, use FireFox if you can), or because the pathname to your TiddlyWiki file contains illegal characters", - invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki", - backupSaved: "Backup saved", - backupFailed: "Failed to save backup file", - rssSaved: "RSS feed saved", - rssFailed: "Failed to save RSS feed file", - emptySaved: "Empty template saved", - emptyFailed: "Failed to save empty template file", - mainSaved: "Main TiddlyWiki file saved", - mainFailed: "Failed to save main TiddlyWiki file. Your changes have not been saved", - macroError: "Error in macro <<%0>>", - macroErrorDetails: "Error while executing macro <<%0>>:\n%1", - missingMacro: "No such macro", - overwriteWarning: "A tiddler named '%0' already exists. Choose OK to overwrite it", - unsavedChangesWarning: "WARNING! There are unsaved changes in TiddlyWiki\n\nChoose OK to save\nChoose CANCEL to discard", - confirmExit: "--------------------------------\n\nThere are unsaved changes in TiddlyWiki. If you continue you will lose those changes\n\n--------------------------------", - saveInstructions: "SaveChanges", - unsupportedTWFormat: "Unsupported TiddlyWiki format '%0'", - tiddlerSaveError: "Error when saving tiddler '%0'", - tiddlerLoadError: "Error when loading tiddler '%0'", - wrongSaveFormat: "Cannot save with storage format '%0'. Using standard format for save.", - invalidFieldName: "Invalid field name %0", - fieldCannotBeChanged: "Field '%0' cannot be changed"}); - -merge(config.messages.messageClose,{ - text: "close", - tooltip: "close this message area"}); - -config.messages.dates.months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November","December"]; -config.messages.dates.days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; -config.messages.dates.shortMonths = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; -config.messages.dates.shortDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; - -merge(config.views.wikified.tag,{ - labelNoTags: "no tags", - labelTags: "tags: ", - openTag: "Open tag '%0'", - tooltip: "Show tiddlers tagged with '%0'", - openAllText: "Open all", - openAllTooltip: "Open all of these tiddlers", - popupNone: "No other tiddlers tagged with '%0'"}); - -merge(config.views.wikified,{ - defaultText: "The tiddler '%0' doesn't yet exist. Double-click to create it", - defaultModifier: "(missing)", - shadowModifier: "(built-in shadow tiddler)", - createdPrompt: "created"}); - -merge(config.views.editor,{ - tagPrompt: "Type tags separated with spaces, [[use double square brackets]] if necessary, or add existing", - defaultText: "Type the text for '%0'"}); - -merge(config.views.editor.tagChooser,{ - text: "tags", - tooltip: "Choose existing tags to add to this tiddler", - popupNone: "There are no tags defined", - tagTooltip: "Add the tag '%0'"}); - -merge(config.macros.search,{ - label: "search", - prompt: "Search this TiddlyWiki", - accessKey: "F", - successMsg: "%0 tiddlers found matching %1", - failureMsg: "No tiddlers found matching %0"}); - -merge(config.macros.tagging,{ - label: "tagging: ", - labelNotTag: "not tagging", - tooltip: "List of tiddlers tagged with '%0'"}); - -merge(config.macros.timeline,{ - dateFormat: "DD MMM YYYY"}); - -merge(config.macros.allTags,{ - tooltip: "Show tiddlers tagged with '%0'", - noTags: "There are no tagged tiddlers"}); - -config.macros.list.all.prompt = "All tiddlers in alphabetical order"; -config.macros.list.missing.prompt = "Tiddlers that have links to them but are not defined"; -config.macros.list.orphans.prompt = "Tiddlers that are not linked to from any other tiddlers"; -config.macros.list.shadowed.prompt = "Tiddlers shadowed with default contents"; - -merge(config.macros.closeAll,{ - label: "close all", - prompt: "Close all displayed tiddlers (except any that are being edited)"}); - -merge(config.macros.permaview,{ - label: "permaview", - prompt: "Link to an URL that retrieves all the currently displayed tiddlers"}); - -merge(config.macros.saveChanges,{ - label: "save changes", - prompt: "Save all tiddlers to create a new TiddlyWiki", - accessKey: "S"}); - -merge(config.macros.newTiddler,{ - label: "new tiddler", - prompt: "Create a new tiddler", - title: "New Tiddler", - accessKey: "N"}); - -merge(config.macros.newJournal,{ - label: "new journal", - prompt: "Create a new tiddler from the current date and time", - accessKey: "J"}); - -merge(config.macros.plugins,{ - skippedText: "(This plugin has not been executed because it was added since startup)", - noPluginText: "There are no plugins installed", - confirmDeleteText: "Are you sure you want to delete these tiddlers:\n\n%0", - listViewTemplate : { - columns: [ - {name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'}, - {name: 'Title', field: 'title', tiddlerLink: 'title', title: "Title", type: 'TiddlerLink'}, - {name: 'Forced', field: 'forced', title: "Forced", tag: 'systemConfigForce', type: 'TagCheckbox'}, - {name: 'Disabled', field: 'disabled', title: "Disabled", tag: 'systemConfigDisable', type: 'TagCheckbox'}, - {name: 'Executed', field: 'executed', title: "Loaded", type: 'Boolean', trueText: "Yes", falseText: "No"}, - {name: 'Error', field: 'error', title: "Status", type: 'Boolean', trueText: "Error", falseText: "OK"}, - {name: 'Log', field: 'log', title: "Log", type: 'StringList'} - ], - rowClasses: [ - {className: 'error', field: 'error'}, - {className: 'warning', field: 'warning'} - ], - actions: [ - {caption: "More actions...", name: ''}, - {caption: "Remove systemConfig tag", name: 'remove'}, - {caption: "Delete these tiddlers forever", name: 'delete'} - ]} - }); - -merge(config.macros.refreshDisplay,{ - label: "refresh", - prompt: "Redraw the entire TiddlyWiki display" - }); - -merge(config.macros.importTiddlers,{ - readOnlyWarning: "You cannot import tiddlers into a read-only TiddlyWiki. Try opening the TiddlyWiki file from a file:// URL", - defaultPath: "http://www.tiddlywiki.com/index.html", - fetchLabel: "fetch", - fetchPrompt: "Fetch the tiddlywiki file", - fetchError: "There were problems fetching the tiddlywiki file", - confirmOverwriteText: "Are you sure you want to overwrite these tiddlers:\n\n%0", - wizardTitle: "Import tiddlers from another TiddlyWiki file", - step1: "Step 1: Locate the TiddlyWiki file", - step1prompt: "Enter the URL or pathname here: ", - step1promptFile: "...or browse for a file: ", - step1promptFeeds: "...or select a pre-defined feed: ", - step1feedPrompt: "Choose...", - step2: "Step 2: Loading TiddlyWiki file", - step2Text: "Please wait while the file is loaded from: %0", - step3: "Step 3: Choose the tiddlers to import", - step4: "%0 tiddler(s) imported", - step5: "Done", - listViewTemplate: { - columns: [ - {name: 'Selected', field: 'Selected', rowName: 'title', type: 'Selector'}, - {name: 'Title', field: 'title', title: "Title", type: 'String'}, - {name: 'Snippet', field: 'text', title: "Snippet", type: 'String'}, - {name: 'Tags', field: 'tags', title: "Tags", type: 'Tags'} - ], - rowClasses: [ - ], - actions: [ - {caption: "More actions...", name: ''}, - {caption: "Import these tiddlers", name: 'import'} - ]} - }); - -merge(config.commands.closeTiddler,{ - text: "close", - tooltip: "Close this tiddler"}); - -merge(config.commands.closeOthers,{ - text: "close others", - tooltip: "Close all other tiddlers"}); - -merge(config.commands.editTiddler,{ - text: "edit", - tooltip: "Edit this tiddler", - readOnlyText: "view", - readOnlyTooltip: "View the source of this tiddler"}); - -merge(config.commands.saveTiddler,{ - text: "done", - tooltip: "Save changes to this tiddler"}); - -merge(config.commands.cancelTiddler,{ - text: "cancel", - tooltip: "Undo changes to this tiddler", - warning: "Are you sure you want to abandon your changes to '%0'?", - readOnlyText: "done", - readOnlyTooltip: "View this tiddler normally"}); - -merge(config.commands.deleteTiddler,{ - text: "delete", - tooltip: "Delete this tiddler", - warning: "Are you sure you want to delete '%0'?"}); - -merge(config.commands.permalink,{ - text: "permalink", - tooltip: "Permalink for this tiddler"}); - -merge(config.commands.references,{ - text: "references", - tooltip: "Show tiddlers that link to this one", - popupNone: "No references"}); - -merge(config.commands.jump,{ - text: "jump", - tooltip: "Jump to another open tiddler"}); - -merge(config.shadowTiddlers,{ - DefaultTiddlers: "GettingStarted", - MainMenu: "GettingStarted", - SiteTitle: "My TiddlyWiki", - SiteSubtitle: "a reusable non-linear personal web notebook", - SiteUrl: "http://www.tiddlywiki.com/", - GettingStarted: "To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:\n* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)\n* MainMenu: The menu (usually on the left)\n* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened\nYou'll also need to enter your username for signing your edits: <<option txtUserName>>", - SideBarOptions: "<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal 'DD MMM YYYY'>><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel 'options »' 'Change TiddlyWiki advanced options'>>", - OptionsPanel: "These InterfaceOptions for customising TiddlyWiki are saved in your browser\n\nYour username for signing your edits. Write it as a WikiWord (eg JoeBloggs)\n\n<<option txtUserName>>\n<<option chkSaveBackups>> SaveBackups\n<<option chkAutoSave>> AutoSave\n<<option chkRegExpSearch>> RegExpSearch\n<<option chkCaseSensitiveSearch>> CaseSensitiveSearch\n<<option chkAnimate>> EnableAnimations\n\n----\nAdvancedOptions\nPluginManager\nImportTiddlers", - AdvancedOptions: "<<option chkGenerateAnRssFeed>> GenerateAnRssFeed\n<<option chkOpenInNewWindow>> OpenLinksInNewWindow\n<<option chkSaveEmptyTemplate>> SaveEmptyTemplate\n<<option chkToggleLinks>> Clicking on links to tiddlers that are already open causes them to close\n^^(override with Control or other modifier key)^^\n<<option chkHttpReadOnly>> HideEditingFeatures when viewed over HTTP\n<<option chkForceMinorUpdate>> Treat edits as MinorChanges by preserving date and time\n^^(override with Shift key when clicking 'done' or by pressing Ctrl-Shift-Enter^^\n<<option chkConfirmDelete>> ConfirmBeforeDeleting\nMaximum number of lines in a tiddler edit box: <<option txtMaxEditRows>>\nFolder name for backup files: <<option txtBackupFolder>>\n<<option chkInsertTabs>> Use tab key to insert tab characters instead of jumping to next field", - SideBarTabs: "<<tabs txtMainTab Timeline Timeline TabTimeline All 'All tiddlers' TabAll Tags 'All tags' TabTags More 'More lists' TabMore>>", - TabTimeline: "<<timeline>>", - TabAll: "<<list all>>", - TabTags: "<<allTags>>", - TabMore: "<<tabs txtMoreTab Missing 'Missing tiddlers' TabMoreMissing Orphans 'Orphaned tiddlers' TabMoreOrphans Shadowed 'Shadowed tiddlers' TabMoreShadowed>>", - TabMoreMissing: "<<list missing>>", - TabMoreOrphans: "<<list orphans>>", - TabMoreShadowed: "<<list shadowed>>", - PluginManager: "<<plugins>>", - ImportTiddlers: "<<importTiddlers>>"}); - -// --------------------------------------------------------------------------------- -// Main -// --------------------------------------------------------------------------------- - -var params = null; // Command line parameters -var store = null; // TiddlyWiki storage -var story = null; // Main story -var formatter = null; // Default formatters for the wikifier -config.parsers = {}; // Hashmap of alternative parsers for the wikifier -var anim = new Animator(); // Animation engine -var readOnly = false; // Whether we're in readonly mode -var highlightHack = null; // Embarrassing hack department... -var hadConfirmExit = false; // Don't warn more than once -var safeMode = false; // Disable all plugins and cookies -var installedPlugins = []; // Information filled in when plugins are executed -var startingUp = false; // Whether we're in the process of starting up -var pluginInfo,tiddler; // Used to pass information to plugins in loadPlugins() - -// Whether to use the JavaSaver applet -var useJavaSaver = config.browser.isSafari || config.browser.isOpera; - -// Starting up -function main() -{ - var now, then = new Date(); - startingUp = true; - window.onbeforeunload = function(e) {if(window.confirmExit) return confirmExit();}; - params = getParameters(); - if(params) - params = params.parseParams("open",null,false); - store = new TiddlyWiki(); - invokeParamifier(params,"oninit"); - story = new Story("tiddlerDisplay","tiddler"); - addEvent(document,"click",Popup.onDocumentClick); - saveTest(); - loadOptionsCookie(); - for(var s=0; s<config.notifyTiddlers.length; s++) - store.addNotification(config.notifyTiddlers[s].name,config.notifyTiddlers[s].notify); - store.loadFromDiv("storeArea","store",true); - invokeParamifier(params,"onload"); - var pluginProblem = loadPlugins(); - formatter = new Formatter(config.formatters); - readOnly = (window.location.protocol == "file:") ? false : config.options.chkHttpReadOnly; - invokeParamifier(params,"onconfig"); - store.notifyAll(); - restart(); - if(pluginProblem) - { - story.displayTiddler(null,"PluginManager"); - displayMessage(config.messages.customConfigError); - } - now = new Date(); - if(config.displayStartupTime) - displayMessage("TiddlyWiki startup in " + (now-then)/1000 + " seconds"); - startingUp = false; -} - -// Restarting -function restart() -{ - invokeParamifier(params,"onstart"); - if(story.isEmpty()) - { - var defaultParams = store.getTiddlerText("DefaultTiddlers").parseParams("open",null,false); - invokeParamifier(defaultParams,"onstart"); - } - window.scrollTo(0,0); -} - -function saveTest() -{ - var saveTest = document.getElementById("saveTest"); - if(saveTest.hasChildNodes()) - alert(config.messages.savedSnapshotError); - saveTest.appendChild(document.createTextNode("savetest")); -} - -function loadPlugins() -{ - if(safeMode) - return false; - var configTiddlers = store.getTaggedTiddlers("systemConfig"); - installedPlugins = []; - var hadProblem = false; - for(var t=0; t<configTiddlers.length; t++) - { - tiddler = configTiddlers[t]; - pluginInfo = getPluginInfo(tiddler); - if(isPluginExecutable(pluginInfo)) - { - pluginInfo.executed = true; - pluginInfo.error = false; - try - { - if(tiddler.text && tiddler.text != "") - window.eval(tiddler.text); - } - catch(e) - { - pluginInfo.log.push(config.messages.pluginError.format([exceptionText(e)])); - pluginInfo.error = true; - hadProblem = true; - } - } - else - pluginInfo.warning = true; - installedPlugins.push(pluginInfo); - } - return hadProblem; -} - -function getPluginInfo(tiddler) -{ - var p = store.getTiddlerSlices(tiddler.title,["Name","Description","Version","CoreVersion","Date","Source","Author","License","Browsers"]); - p.tiddler = tiddler; - p.title = tiddler.title; - p.log = []; - return p; -} - -// Check that a particular plugin is valid for execution -function isPluginExecutable(plugin) -{ - if(plugin.tiddler.isTagged("systemConfigDisable")) - return verifyTail(plugin,false,config.messages.pluginDisabled); - if(plugin.tiddler.isTagged("systemConfigForce")) - return verifyTail(plugin,true,config.messages.pluginForced); - if(plugin["CoreVersion"]) - { - var coreVersion = plugin["CoreVersion"].split("."); - var w = parseInt(coreVersion[0]) - version.major; - if(w == 0 && coreVersion[1]) - w = parseInt(coreVersion[1]) - version.minor; - if(w == 0 && coreVersion[2]) - w = parseInt(coreVersion[2]) - version.revision; - if(w > 0) - return verifyTail(plugin,false,config.messages.pluginVersionError); - } - return true; -} - -function verifyTail(plugin,result,message) -{ - plugin.log.push(message); - return result; -} - -function invokeMacro(place,macro,params,wikifier,tiddler) -{ - try - { - var m = config.macros[macro]; - if(m && m.handler) - m.handler(place,macro,params.readMacroParams(),wikifier,params,tiddler); - else - createTiddlyError(place,config.messages.macroError.format([macro]),config.messages.macroErrorDetails.format([macro,config.messages.missingMacro])); - } - catch(ex) - { - createTiddlyError(place,config.messages.macroError.format([macro]),config.messages.macroErrorDetails.format([macro,ex.toString()])); - } -} - -// --------------------------------------------------------------------------------- -// Paramifiers -// --------------------------------------------------------------------------------- - -function getParameters() -{ - var p = null; - if(window.location.hash) - { - p = decodeURI(window.location.hash.substr(1)); - if(config.browser.firefoxDate != null && config.browser.firefoxDate[1] < "20051111") - p = convertUTF8ToUnicode(p); - } - return p; -} - -function invokeParamifier(params,handler) -{ - if(!params || params.length == undefined || params.length <= 1) - return; - for(var t=1; t<params.length; t++) - { - var p = config.paramifiers[params[t].name]; - if(p && p[handler] instanceof Function) - p[handler](params[t].value); - } -} - -config.paramifiers = {}; - -config.paramifiers.start = { - oninit: function(v) { - safeMode = v.toLowerCase() == "safe"; - } -}; - -config.paramifiers.open = { - onstart: function(v) { - story.displayTiddler("bottom",v,null,false,false); - } -}; - -config.paramifiers.story = { - onstart: function(v) { - var list = store.getTiddlerText(v,"").parseParams("open",null,false); - invokeParamifier(list,"onstart"); - } -}; - -config.paramifiers.search = { - onstart: function(v) { - story.search(v,false,false); - } -}; - -config.paramifiers.searchRegExp = { - onstart: function(v) { - story.prototype.search(v,false,true); - } -}; - -config.paramifiers.tag = { - onstart: function(v) { - var tagged = store.getTaggedTiddlers(v,"title"); - for(var t=0; t<tagged.length; t++) - story.displayTiddler("bottom",tagged[t].title,null,false,false); - } -}; - -config.paramifiers.newTiddler = { - onstart: function(v) { - if(!readOnly) - { - story.displayTiddler(null,v,DEFAULT_EDIT_TEMPLATE); - story.focusTiddler(v,"text"); - } - } -}; - -config.paramifiers.newJournal = { - onstart: function(v) { - if(!readOnly) - { - var now = new Date(); - var title = now.formatString(v.trim()); - story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE); - story.focusTiddler(title,"text"); - } - } -}; - -// --------------------------------------------------------------------------------- -// Formatter helpers -// --------------------------------------------------------------------------------- - -function Formatter(formatters) -{ - this.formatters = []; - var pattern = []; - for(var n=0; n<formatters.length; n++) - { - pattern.push("(" + formatters[n].match + ")"); - this.formatters.push(formatters[n]); - } - this.formatterRegExp = new RegExp(pattern.join("|"),"mg"); -} - -config.formatterHelpers = { - - createElementAndWikify: function(w) - { - w.subWikifyTerm(createTiddlyElement(w.output,this.element),this.termRegExp); - }, - - inlineCssHelper: function(w) - { - var styles = []; - config.textPrimitives.cssLookaheadRegExp.lastIndex = w.nextMatch; - var lookaheadMatch = config.textPrimitives.cssLookaheadRegExp.exec(w.source); - while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) - { - var s,v; - if(lookaheadMatch[1]) - { - s = lookaheadMatch[1].unDash(); - v = lookaheadMatch[2]; - } - else - { - s = lookaheadMatch[3].unDash(); - v = lookaheadMatch[4]; - } - if (s=="bgcolor") - s = "backgroundColor"; - styles.push({style: s, value: v}); - w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length; - config.textPrimitives.cssLookaheadRegExp.lastIndex = w.nextMatch; - lookaheadMatch = config.textPrimitives.cssLookaheadRegExp.exec(w.source); - } - return styles; - }, - - applyCssHelper: function(e,styles) - { - for(var t=0; t< styles.length; t++) - { - try - { - e.style[styles[t].style] = styles[t].value; - } - catch (ex) - { - } - } - }, - - enclosedTextHelper: function(w) - { - this.lookaheadRegExp.lastIndex = w.matchStart; - var lookaheadMatch = this.lookaheadRegExp.exec(w.source); - if(lookaheadMatch && lookaheadMatch.index == w.matchStart) - { - var text = lookaheadMatch[1]; - if(config.browser.isIE) - text = text.replace(/\n/g,"\r"); - createTiddlyElement(w.output,this.element,null,null,text); - w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length; - } - }, - - isExternalLink: function(link) - { - if(store.tiddlerExists(link) || store.isShadowTiddler(link)) - { - //# Definitely not an external link - return false; - } - var urlRegExp = new RegExp(config.textPrimitives.urlPattern,"mg"); - if(urlRegExp.exec(link)) - { - // Definitely an external link - return true; - } - if (link.indexOf(".")!=-1 || link.indexOf("\\")!=-1 || link.indexOf("/")!=-1) - { - //# Link contains . / or \ so is probably an external link - return true; - } - //# Otherwise assume it is not an external link - return false; - } - -}; - -// --------------------------------------------------------------------------------- -// Standard formatters -// --------------------------------------------------------------------------------- - -config.formatters = [ -{ - name: "table", - match: "^\\|(?:[^\\n]*)\\|(?:[fhck]?)$", - lookaheadRegExp: /^\|([^\n]*)\|([fhck]?)$/mg, - rowTermRegExp: /(\|(?:[fhck]?)$\n?)/mg, - cellRegExp: /(?:\|([^\n\|]*)\|)|(\|[fhck]?$\n?)/mg, - cellTermRegExp: /((?:\x20*)\|)/mg, - rowTypes: {"c":"caption", "h":"thead", "":"tbody", "f":"tfoot"}, - - handler: function(w) - { - var table = createTiddlyElement(w.output,"table"); - var prevColumns = []; - var currRowType = null; - var rowContainer; - var rowCount = 0; - w.nextMatch = w.matchStart; - this.lookaheadRegExp.lastIndex = w.nextMatch; - var lookaheadMatch = this.lookaheadRegExp.exec(w.source); - while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) - { - var nextRowType = lookaheadMatch[2]; - if(nextRowType == "k") - { - table.className = lookaheadMatch[1]; - w.nextMatch += lookaheadMatch[0].length+1; - } - else - { - if(nextRowType != currRowType) - { - rowContainer = createTiddlyElement(table,this.rowTypes[nextRowType]); - currRowType = nextRowType; - } - if(currRowType == "c") - { - // Caption - w.nextMatch++; - if(rowContainer != table.firstChild) - table.insertBefore(rowContainer,table.firstChild); - rowContainer.setAttribute("align",rowCount == 0?"top":"bottom"); - w.subWikifyTerm(rowContainer,this.rowTermRegExp); - } - else - { - this.rowHandler(w,createTiddlyElement(rowContainer,"tr",null,(rowCount&1)?"oddRow":"evenRow"),prevColumns); - rowCount++; - } - } - this.lookaheadRegExp.lastIndex = w.nextMatch; - lookaheadMatch = this.lookaheadRegExp.exec(w.source); - } - }, - rowHandler: function(w,e,prevColumns) - { - var col = 0; - var colSpanCount = 1; - var prevCell = null; - this.cellRegExp.lastIndex = w.nextMatch; - var cellMatch = this.cellRegExp.exec(w.source); - while(cellMatch && cellMatch.index == w.nextMatch) - { - if(cellMatch[1] == "~") - { - // Rowspan - var last = prevColumns[col]; - if(last) - { - last.rowSpanCount++; - last.element.setAttribute("rowspan",last.rowSpanCount); - last.element.setAttribute("rowSpan",last.rowSpanCount); // Needed for IE - last.element.valign = "center"; - } - w.nextMatch = this.cellRegExp.lastIndex-1; - } - else if(cellMatch[1] == ">") - { - // Colspan - colSpanCount++; - w.nextMatch = this.cellRegExp.lastIndex-1; - } - else if(cellMatch[2]) - { - // End of row - if(prevCell && colSpanCount > 1) - { - prevCell.setAttribute("colspan",colSpanCount); - prevCell.setAttribute("colSpan",colSpanCount); // Needed for IE - } - w.nextMatch = this.cellRegExp.lastIndex; - break; - } - else - { - // Cell - w.nextMatch++; - var styles = config.formatterHelpers.inlineCssHelper(w); - var spaceLeft = false; - var chr = w.source.substr(w.nextMatch,1); - while(chr == " ") - { - spaceLeft = true; - w.nextMatch++; - chr = w.source.substr(w.nextMatch,1); - } - var cell; - if(chr == "!") - { - cell = createTiddlyElement(e,"th"); - w.nextMatch++; - } - else - cell = createTiddlyElement(e,"td"); - prevCell = cell; - prevColumns[col] = {rowSpanCount:1, element:cell}; - if(colSpanCount > 1) - { - cell.setAttribute("colspan",colSpanCount); - cell.setAttribute("colSpan",colSpanCount); // Needed for IE - colSpanCount = 1; - } - config.formatterHelpers.applyCssHelper(cell,styles); - w.subWikifyTerm(cell,this.cellTermRegExp); - if(w.matchText.substr(w.matchText.length-2,1) == " ") // spaceRight - cell.align = spaceLeft ? "center" : "left"; - else if(spaceLeft) - cell.align = "right"; - w.nextMatch--; - } - col++; - this.cellRegExp.lastIndex = w.nextMatch; - cellMatch = this.cellRegExp.exec(w.source); - } - } -}, - -{ - name: "heading", - match: "^!{1,5}", - termRegExp: /(\n)/mg, - handler: function(w) - { - w.subWikifyTerm(createTiddlyElement(w.output,"h" + w.matchLength),this.termRegExp); - } -}, - -{ - name: "list", - match: "^(?:(?:(?:\\*)|(?:#)|(?:;)|(?::))+)", - lookaheadRegExp: /^(?:(?:(\*)|(#)|(;)|(:))+)/mg, - termRegExp: /(\n)/mg, - handler: function(w) - { - var placeStack = [w.output]; - var currLevel = 0, currType = null; - var listLevel, listType, itemType; - w.nextMatch = w.matchStart; - this.lookaheadRegExp.lastIndex = w.nextMatch; - var lookaheadMatch = this.lookaheadRegExp.exec(w.source); - while(lookaheadMatch && lookaheadMatch.index == w.nextMatch) - { - if(lookaheadMatch[1]) - { - listType = "ul"; - itemType = "li"; - } - else if(lookaheadMatch[2]) - { - listType = "ol"; - itemType = "li"; - } - else if(lookaheadMatch[3]) - { - listType = "dl"; - itemType = "dt"; - } - else if(lookaheadMatch[4]) - { - listType = "dl"; - itemType = "dd"; - } - listLevel = lookaheadMatch[0].length; - w.nextMatch += lookaheadMatch[0].length; - if(listLevel > currLevel) - { - for(var t=currLevel; t<listLevel; t++) - placeStack.push(createTiddlyElement(placeStack[placeStack.length-1],listType)); - } - else if(listLevel < currLevel) - { - for(var t=currLevel; t>listLevel; t--) - placeStack.pop(); - } - else if(listLevel == currLevel && listType != currType) - { - placeStack.pop(); - placeStack.push(createTiddlyElement(placeStack[placeStack.length-1],listType)); - } - currLevel = listLevel; - currType = listType; - var e = createTiddlyElement(placeStack[placeStack.length-1],itemType); - w.subWikifyTerm(e,this.termRegExp); - this.lookaheadRegExp.lastIndex = w.nextMatch; - lookaheadMatch = this.lookaheadRegExp.exec(w.source); - } - } -}, - -{ - name: "quoteByBlock", - match: "^<<<\\n", - termRegExp: /(^<<<(\n|$))/mg, - element: "blockquote", - handler: config.formatterHelpers.createElementAndWikify -}, - -{ - name: "quoteByLine", - match: "^>+", - lookaheadRegExp: /^>+/mg, - termRegExp: /(\n)/mg, - element: "blockquote", - handler: function(w) - { - var placeStack = [w.output]; - var currLevel = 0; - var newLevel = w.matchLength; - var t; - do { - if(newLevel > currLevel) - { - for(t=currLevel; t<newLevel; t++) - placeStack.push(createTiddlyElement(placeStack[placeStack.length-1],this.element)); - } - else if(newLevel < currLevel) - { - for(t=currLevel; t>newLevel; t--) - placeStack.pop(); - } - currLevel = newLevel; - w.subWikifyTerm(placeStack[placeStack.length-1],this.termRegExp); - createTiddlyElement(placeStack[placeStack.length-1],"br"); - this.lookaheadRegExp.lastIndex = w.nextMatch; - var lookaheadMatch = this.lookaheadRegExp.exec(w.source); - var matched = lookaheadMatch && lookaheadMatch.index == w.nextMatch; - if(matched) - { - newLevel = lookaheadMatch[0].length; - w.nextMatch += lookaheadMatch[0].length; - } - } while(matched); - } -}, - -{ - name: "rule", - match: "^----+$\\n?", - handler: function(w) - { - createTiddlyElement(w.output,"hr"); - } -}, - -{ - name: "monospacedByLine", - match: "^\\{\\{\\{\\n", - lookaheadRegExp: /^\{\{\{\n((?:^[^\n]*\n)+?)(^\}\}\}$\n?)/mg, - element: "pre", - handler: config.formatterHelpers.enclosedTextHelper -}, - -{ - name: "monospacedByLineForCSS", - match: "^/\\*[\\{]{3}\\*/\\n", - lookaheadRegExp: /\/\*[\{]{3}\*\/\n*((?:^[^\n]*\n)+?)(\n*^\/\*[\}]{3}\*\/$\n?)/mg, - element: "pre", - handler: config.formatterHelpers.enclosedTextHelper -}, - -{ - name: "monospacedByLineForPlugin", - match: "^//\\{\\{\\{\\n", - lookaheadRegExp: /^\/\/\{\{\{\n\n*((?:^[^\n]*\n)+?)(\n*^\/\/\}\}\}$\n?)/mg, - element: "pre", - handler: config.formatterHelpers.enclosedTextHelper -}, - -{ - name: "monospacedByLineForTemplate", - match: "^<!--[\\{]{3}-->\\n", - lookaheadRegExp: /<!--[\{]{3}-->\n*((?:^[^\n]*\n)+?)(\n*^<!--[\}]{3}-->$\n?)/mg, - element: "pre", - handler: config.formatterHelpers.enclosedTextHelper -}, - -{ - name: "wikifyCommentForPlugin", - match: "^/\\*\\*\\*\\n", - termRegExp: /(^\*\*\*\/\n)/mg, - handler: function(w) - { - w.subWikifyTerm(w.output,this.termRegExp); - } -}, - -{ - name: "wikifyCommentForTemplate", - match: "^<!---\\n", - termRegExp: /(^--->\n)/mg, - handler: function(w) - { - w.subWikifyTerm(w.output,this.termRegExp); - } -}, - -{ - name: "macro", - match: "<<", - lookaheadRegExp: /<<([^>\s]+)(?:\s*)((?:[^>]|(?:>(?!>)))*)>>/mg, - handler: function(w) - { - this.lookaheadRegExp.lastIndex = w.matchStart; - var lookaheadMatch = this.lookaheadRegExp.exec(w.source); - if(lookaheadMatch && lookaheadMatch.index == w.matchStart && lookaheadMatch[1]) - { - w.nextMatch = this.lookaheadRegExp.lastIndex; - invokeMacro(w.output,lookaheadMatch[1],lookaheadMatch[2],w,w.tiddler); - } - } -}, - -{ - name: "prettyLink", - match: "\\[\\[", - lookaheadRegExp: /\[\[(.*?)(?:\|(~)?(.*?))?\]\]/mg, - handler: function(w) - { - this.lookaheadRegExp.lastIndex = w.matchStart; - var lookaheadMatch = this.lookaheadRegExp.exec(w.source); - if(lookaheadMatch && lookaheadMatch.index == w.matchStart) - { - var e; - var text = lookaheadMatch[1]; - if(lookaheadMatch[3]) - { - // Pretty bracketted link - var link = lookaheadMatch[3]; - e = (!lookaheadMatch[2] && config.formatterHelpers.isExternalLink(link)) - ? createExternalLink(w.output,link) - : createTiddlyLink(w.output,link,false,null,w.isStatic); - } - else - { - // Simple bracketted link - e = createTiddlyLink(w.output,text,false,null,w.isStatic); - } - createTiddlyText(e,text); - w.nextMatch = this.lookaheadRegExp.lastIndex; - } - } -}, - -{ - name: "unWikiLink", - match: config.textPrimitives.unWikiLink+config.textPrimitives.wikiLink, - handler: function(w) - { - w.outputText(w.output,w.matchStart+1,w.nextMatch); - } -}, - -{ - name: "wikiLink", - match: config.textPrimitives.wikiLink, - handler: function(w) - { - if(w.matchStart > 0) - { - var preRegExp = new RegExp(config.textPrimitives.anyLetterStrict,"mg"); - preRegExp.lastIndex = w.matchStart-1; - var preMatch = preRegExp.exec(w.source); - if(preMatch.index == w.matchStart-1) - { - w.outputText(w.output,w.matchStart,w.nextMatch); - return; - } - } - if(w.autoLinkWikiWords == true || store.isShadowTiddler(w.matchText)) - { - var link = createTiddlyLink(w.output,w.matchText,false,null,w.isStatic); - w.outputText(link,w.matchStart,w.nextMatch); - } - else - { - w.outputText(w.output,w.matchStart,w.nextMatch); - } - } -}, - -{ - name: "urlLink", - match: config.textPrimitives.urlPattern, - handler: function(w) - { - w.outputText(createExternalLink(w.output,w.matchText),w.matchStart,w.nextMatch); - } -}, - -{ - name: "image", - match: "\\[[<>]?[Ii][Mm][Gg]\\[", - lookaheadRegExp: /\[(<?)(>?)[Ii][Mm][Gg]\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg, - handler: function(w) - { - this.lookaheadRegExp.lastIndex = w.matchStart; - var lookaheadMatch = this.lookaheadRegExp.exec(w.source); - if(lookaheadMatch && lookaheadMatch.index == w.matchStart) // Simple bracketted link - { - var e = w.output; - if(lookaheadMatch[5]) - { - var link = lookaheadMatch[5]; - e = config.formatterHelpers.isExternalLink(link) ? createExternalLink(w.output,link) : createTiddlyLink(w.output,link,false,null,w.isStatic); - addClass(e,"imageLink"); - } - var img = createTiddlyElement(e,"img"); - if(lookaheadMatch[1]) - img.align = "left"; - else if(lookaheadMatch[2]) - img.align = "right"; - if(lookaheadMatch[3]) - img.title = lookaheadMatch[3]; - img.src = lookaheadMatch[4]; - w.nextMatch = this.lookaheadRegExp.lastIndex; - } - } -}, - -{ - name: "html", - match: "<[Hh][Tt][Mm][Ll]>", - lookaheadRegExp: /<[Hh][Tt][Mm][Ll]>((?:.|\n)*?)<\/[Hh][Tt][Mm][Ll]>/mg, - handler: function(w) - { - this.lookaheadRegExp.lastIndex = w.matchStart; - var lookaheadMatch = this.lookaheadRegExp.exec(w.source) - if(lookaheadMatch && lookaheadMatch.index == w.matchStart) - { - createTiddlyElement(w.output,"span").innerHTML = lookaheadMatch[1]; - w.nextMatch = this.lookaheadRegExp.lastIndex; - } - } -}, - -{ - name: "commentByBlock", - match: "/%", - lookaheadRegExp: /\/%((?:.|\n)*?)%\//mg, - handler: function(w) - { - this.lookaheadRegExp.lastIndex = w.matchStart; - var lookaheadMatch = this.lookaheadRegExp.exec(w.source) - if(lookaheadMatch && lookaheadMatch.index == w.matchStart) - w.nextMatch = this.lookaheadRegExp.lastIndex; - } -}, - -{ - name: "boldByChar", - match: "''", - termRegExp: /('')/mg, - element: "strong", - handler: config.formatterHelpers.createElementAndWikify -}, - -{ - name: "italicByChar", - match: "//", - termRegExp: /(\/\/)/mg, - element: "em", - handler: config.formatterHelpers.createElementAndWikify -}, - -{ - name: "underlineByChar", - match: "__", - termRegExp: /(__)/mg, - element: "u", - handler: config.formatterHelpers.createElementAndWikify -}, - -{ - name: "strikeByChar", - match: "--(?!\\s|$)", - termRegExp: /((?!\s)--|(?=\n\n))/mg, - element: "strike", - handler: config.formatterHelpers.createElementAndWikify -}, - -{ - name: "superscriptByChar", - match: "\\^\\^", - termRegExp: /(\^\^)/mg, - element: "sup", - handler: config.formatterHelpers.createElementAndWikify -}, - -{ - name: "subscriptByChar", - match: "~~", - termRegExp: /(~~)/mg, - element: "sub", - handler: config.formatterHelpers.createElementAndWikify -}, - -{ - name: "monospacedByChar", - match: "\\{\\{\\{", - lookaheadRegExp: /\{\{\{((?:.|\n)*?)\}\}\}/mg, - handler: function(w) - { - this.lookaheadRegExp.lastIndex = w.matchStart; - var lookaheadMatch = this.lookaheadRegExp.exec(w.source) - if(lookaheadMatch && lookaheadMatch.index == w.matchStart) - { - createTiddlyElement(w.output,"code",null,null,lookaheadMatch[1]); - w.nextMatch = this.lookaheadRegExp.lastIndex; - } - } -}, - -{ - name: "styleByChar", - match: "@@", - termRegExp: /(@@)/mg, - handler: function(w) - { - var e = createTiddlyElement(w.output,"span"); - var styles = config.formatterHelpers.inlineCssHelper(w); - if(styles.length == 0) - e.className = "marked"; - else - config.formatterHelpers.applyCssHelper(e,styles); - w.subWikifyTerm(e,this.termRegExp); - } -}, - -{ - name: "lineBreak", - match: "\\n|<br ?/?>", - handler: function(w) - { - createTiddlyElement(w.output,"br"); - } -}, - -{ - name: "rawText", - match: "\\\"{3}|<nowiki>", - lookaheadRegExp: /(?:\"{3}|<nowiki>)((?:.|\n)*?)(?:\"{3}|<\/nowiki>)/mg, - handler: function(w) - { - this.lookaheadRegExp.lastIndex = w.matchStart; - var lookaheadMatch = this.lookaheadRegExp.exec(w.source) - if(lookaheadMatch && lookaheadMatch.index == w.matchStart) - { - createTiddlyElement(w.output,"span",null,null,lookaheadMatch[1]); - w.nextMatch = this.lookaheadRegExp.lastIndex; - } - } -}, - -{ - name: "mdash", - match: "--", - handler: function(w) - { - createTiddlyElement(w.output,"span").innerHTML = "—"; - } -}, - -{ - name: "htmlEntitiesEncoding", - match: "(?:(?:&#?[a-zA-Z0-9]{2,8};|.)(?:&#?(?:x0*(?:3[0-6][0-9a-fA-F]|1D[c-fC-F][0-9a-fA-F]|20[d-fD-F][0-9a-fA-F]|FE2[0-9a-fA-F])|0*(?:76[89]|7[7-9][0-9]|8[0-7][0-9]|761[6-9]|76[2-7][0-9]|84[0-3][0-9]|844[0-7]|6505[6-9]|6506[0-9]|6507[0-1]));)+|&#?[a-zA-Z0-9]{2,8};)", - handler: function(w) - { - createTiddlyElement(w.output,"span").innerHTML = w.matchText; - } -}, - -{ - name: "customClasses", - match: "\\{\\{", - termRegExp: /(\}\}\})/mg, - lookaheadRegExp: /\{\{[\s]*([\w]+[\s\w]*)[\s]*\{(\n?)/mg, - handler: function(w) - { - this.lookaheadRegExp.lastIndex = w.matchStart; - var lookaheadMatch = this.lookaheadRegExp.exec(w.source); - if(lookaheadMatch) - { - var e = createTiddlyElement(w.output,lookaheadMatch[2] == "\n" ? "div" : "span",null,lookaheadMatch[1]); - w.nextMatch = this.lookaheadRegExp.lastIndex; - w.subWikifyTerm(e,this.termRegExp); - } - } -} - -]; - -// --------------------------------------------------------------------------------- -// Wikifier -// --------------------------------------------------------------------------------- - -function getParser(tiddler) -{ - var f = formatter; - if(tiddler!=null) - { - for(var i in config.parsers) - { - if(tiddler.isTagged(config.parsers[i].formatTag)) - { - f = config.parsers[i]; - break; - } - } - } - return f; -} - -function wikify(source,output,highlightRegExp,tiddler) -{ - if(source && source != "") - { - var wikifier = new Wikifier(source,getParser(tiddler),highlightRegExp,tiddler); - wikifier.subWikifyUnterm(output); - } -} - -function wikifyStatic(source,highlightRegExp,tiddler) -{ - var e = createTiddlyElement(document.body,"div"); - e.style.display = "none"; - var html = ""; - if(source && source != "") - { - var wikifier = new Wikifier(source,getParser(tiddler),highlightRegExp,tiddler); - wikifier.isStatic = true; - wikifier.subWikifyUnterm(e); - html = e.innerHTML; - e.parentNode.removeChild(e); - } - return html; -} - -// Wikify a named tiddler to plain text -function wikifyPlain(title) -{ - if(store.tiddlerExists(title) || store.isShadowTiddler(title)) - { - var wikifier = new Wikifier(store.getTiddlerText(title),formatter,null,store.getTiddler(title)); - return wikifier.wikifyPlain(); - } - else - return ""; -} - -// Highlight plain text into an element -function highlightify(source,output,highlightRegExp) -{ - if(source && source != "") - { - var wikifier = new Wikifier(source,formatter,highlightRegExp); - wikifier.outputText(output,0,source.length); - } -} - -// Construct a wikifier object -// source - source string that's going to be wikified -// formatter - Formatter() object containing the list of formatters to be used -// highlightRegExp - regular expression of the text string to highlight -// tiddler - reference to the tiddler that's taken to be the container for this wikification -function Wikifier(source,formatter,highlightRegExp,tiddler) -{ - this.source = source; - this.output = null; - this.formatter = formatter; - this.nextMatch = 0; - this.autoLinkWikiWords = tiddler && tiddler.autoLinkWikiWords() == false ? false : true; - this.highlightRegExp = highlightRegExp; - this.highlightMatch = null; - this.isStatic = false; - if(highlightRegExp) - { - highlightRegExp.lastIndex = 0; - this.highlightMatch = highlightRegExp.exec(source); - } - this.tiddler = tiddler; -} - -Wikifier.prototype.wikifyPlain = function() -{ - var e = createTiddlyElement(document.body,"div"); - e.style.display = "none"; - this.subWikify(e); - var text = getPlainText(e); - e.parentNode.removeChild(e); - return text; -} - -Wikifier.prototype.subWikify = function(output,terminator) -{ - // Handle the terminated and unterminated cases separately - if (terminator) - this.subWikifyTerm(output,new RegExp("(" + terminator + ")","mg")); - else - this.subWikifyUnterm(output); -} - -Wikifier.prototype.subWikifyUnterm = function(output) -{ - // subWikify() can be indirectly recursive, so we need to save the old output pointer - var oldOutput = this.output; - this.output = output; - // Get the first match - this.formatter.formatterRegExp.lastIndex = this.nextMatch; - var formatterMatch = this.formatter.formatterRegExp.exec(this.source); - while(formatterMatch) - { - // Output any text before the match - if(formatterMatch.index > this.nextMatch) - this.outputText(this.output,this.nextMatch,formatterMatch.index); - // Set the match parameters for the handler - this.matchStart = formatterMatch.index; - this.matchLength = formatterMatch[0].length; - this.matchText = formatterMatch[0]; - this.nextMatch = this.formatter.formatterRegExp.lastIndex; - // Figure out which formatter matched and call its handler - for(var t=1; t<formatterMatch.length; t++) - { - if(formatterMatch[t]) - { - this.formatter.formatters[t-1].handler(this); - this.formatter.formatterRegExp.lastIndex = this.nextMatch; - break; - } - } - // Get the next match - formatterMatch = this.formatter.formatterRegExp.exec(this.source); - } - // Output any text after the last match - if(this.nextMatch < this.source.length) - { - this.outputText(this.output,this.nextMatch,this.source.length); - this.nextMatch = this.source.length; - } - // Restore the output pointer - this.output = oldOutput; -} - -Wikifier.prototype.subWikifyTerm = function(output,terminatorRegExp) -{ - // subWikify() can be indirectly recursive, so we need to save the old output pointer - var oldOutput = this.output; - this.output = output; - // Get the first matches for the formatter and terminator RegExps - terminatorRegExp.lastIndex = this.nextMatch; - var terminatorMatch = terminatorRegExp.exec(this.source); - this.formatter.formatterRegExp.lastIndex = this.nextMatch; - var formatterMatch = this.formatter.formatterRegExp.exec(terminatorMatch ? this.source.substr(0,terminatorMatch.index) : this.source); - while(terminatorMatch || formatterMatch) - { - // Check for a terminator match before the next formatter match - if(terminatorMatch && (!formatterMatch || terminatorMatch.index <= formatterMatch.index)) - { - // Output any text before the match - if(terminatorMatch.index > this.nextMatch) - this.outputText(this.output,this.nextMatch,terminatorMatch.index); - // Set the match parameters - this.matchText = terminatorMatch[1]; - this.matchLength = terminatorMatch[1].length; - this.matchStart = terminatorMatch.index; - this.nextMatch = this.matchStart + this.matchLength; - // Restore the output pointer - this.output = oldOutput; - return; - } - // It must be a formatter match; output any text before the match - if(formatterMatch.index > this.nextMatch) - this.outputText(this.output,this.nextMatch,formatterMatch.index); - // Set the match parameters - this.matchStart = formatterMatch.index; - this.matchLength = formatterMatch[0].length; - this.matchText = formatterMatch[0]; - this.nextMatch = this.formatter.formatterRegExp.lastIndex; - // Figure out which formatter matched and call its handler - for(var t=1; t<formatterMatch.length; t++) - { - if(formatterMatch[t]) - { - this.formatter.formatters[t-1].handler(this); - this.formatter.formatterRegExp.lastIndex = this.nextMatch; - break; - } - } - // Get the next match - terminatorRegExp.lastIndex = this.nextMatch; - terminatorMatch = terminatorRegExp.exec(this.source); - formatterMatch = this.formatter.formatterRegExp.exec(terminatorMatch ? this.source.substr(0,terminatorMatch.index) : this.source); - } - // Output any text after the last match - if(this.nextMatch < this.source.length) - { - this.outputText(this.output,this.nextMatch,this.source.length); - this.nextMatch = this.source.length; - } - // Restore the output pointer - this.output = oldOutput; -} - -Wikifier.prototype.outputText = function(place,startPos,endPos) -{ - // Check for highlights - while(this.highlightMatch && (this.highlightRegExp.lastIndex > startPos) && (this.highlightMatch.index < endPos) && (startPos < endPos)) - { - // Deal with any plain text before the highlight - if(this.highlightMatch.index > startPos) - { - createTiddlyText(place,this.source.substring(startPos,this.highlightMatch.index)); - startPos = this.highlightMatch.index; - } - // Deal with the highlight - var highlightEnd = Math.min(this.highlightRegExp.lastIndex,endPos); - var theHighlight = createTiddlyElement(place,"span",null,"highlight",this.source.substring(startPos,highlightEnd)); - startPos = highlightEnd; - // Nudge along to the next highlight if we're done with this one - if(startPos >= this.highlightRegExp.lastIndex) - this.highlightMatch = this.highlightRegExp.exec(this.source); - } - // Do the unhighlighted text left over - if(startPos < endPos) - { - createTiddlyText(place,this.source.substring(startPos,endPos)); - } -} - -// --------------------------------------------------------------------------------- -// Macro definitions -// --------------------------------------------------------------------------------- - -config.macros.today.handler = function(place,macroName,params) -{ - var now = new Date(); - var text; - if(params[0]) - text = now.formatString(params[0].trim()); - else - text = now.toLocaleString(); - createTiddlyElement(place,"span",null,null,text); -} - -config.macros.version.handler = function(place) -{ - createTiddlyElement(place,"span",null,null,version.major + "." + version.minor + "." + version.revision + (version.beta ? " (beta " + version.beta + ")" : "")); -} - -config.macros.list.handler = function(place,macroName,params) -{ - var type = params[0] ? params[0] : "all"; - var theList = document.createElement("ul"); - place.appendChild(theList); - if(this[type].prompt) - createTiddlyElement(theList,"li",null,"listTitle",this[type].prompt); - var results; - if(this[type].handler) - results = this[type].handler(params); - for(var t = 0; t < results.length; t++) - { - var theListItem = document.createElement("li") - theList.appendChild(theListItem); - if(typeof results[t] == "string") - createTiddlyLink(theListItem,results[t],true); - else - createTiddlyLink(theListItem,results[t].title,true); - } -} - -config.macros.list.all.handler = function(params) -{ - return store.reverseLookup("tags","excludeLists",false,"title"); -} - -config.macros.list.missing.handler = function(params) -{ - return store.getMissingLinks(); -} - -config.macros.list.orphans.handler = function(params) -{ - return store.getOrphans(); -} - -config.macros.list.shadowed.handler = function(params) -{ - return store.getShadowed(); -} - -config.macros.allTags.handler = function(place,macroName,params) -{ - var tags = store.getTags(); - var theDateList = createTiddlyElement(place,"ul"); - if(tags.length == 0) - createTiddlyElement(theDateList,"li",null,"listTitle",this.noTags); - for(var t=0; t<tags.length; t++) - { - var theListItem =createTiddlyElement(theDateList,"li"); - var theTag = createTiddlyButton(theListItem,tags[t][0] + " (" + tags[t][1] + ")",this.tooltip.format([tags[t][0]]),onClickTag); - theTag.setAttribute("tag",tags[t][0]); - } -} - -config.macros.timeline.handler = function(place,macroName,params) -{ - var field = params[0] ? params[0] : "modified"; - var tiddlers = store.reverseLookup("tags","excludeLists",false,field); - var lastDay = ""; - var last = params[1] ? tiddlers.length-Math.min(tiddlers.length,parseInt(params[1])) : 0; - for(var t=tiddlers.length-1; t>=last; t--) - { - var tiddler = tiddlers[t]; - var theDay = tiddler[field].convertToLocalYYYYMMDDHHMM().substr(0,8); - if(theDay != lastDay) - { - var theDateList = document.createElement("ul"); - place.appendChild(theDateList); - createTiddlyElement(theDateList,"li",null,"listTitle",tiddler[field].formatString(this.dateFormat)); - lastDay = theDay; - } - var theDateListItem = createTiddlyElement(theDateList,"li",null,"listLink"); - theDateListItem.appendChild(createTiddlyLink(place,tiddler.title,true)); - } -} - -config.macros.search.handler = function(place,macroName,params) -{ - var searchTimeout = null; - var btn = createTiddlyButton(place,this.label,this.prompt,this.onClick); - var txt = createTiddlyElement(place,"input",null,"txtOptionInput"); - if(params[0]) - txt.value = params[0]; - txt.onkeyup = this.onKeyPress; - txt.onfocus = this.onFocus; - txt.setAttribute("size",this.sizeTextbox); - txt.setAttribute("accessKey",this.accessKey); - txt.setAttribute("autocomplete","off"); - txt.setAttribute("lastSearchText",""); - if(config.browser.isSafari) - { - txt.setAttribute("type","search"); - txt.setAttribute("results","5"); - } - else - txt.setAttribute("type","text"); -} - -// Global because there's only ever one outstanding incremental search timer -config.macros.search.timeout = null; - -config.macros.search.doSearch = function(txt) -{ - if(txt.value.length > 0) - { - story.search(txt.value,config.options.chkCaseSensitiveSearch,config.options.chkRegExpSearch); - txt.setAttribute("lastSearchText",txt.value); - } -} - -config.macros.search.onClick = function(e) -{ - config.macros.search.doSearch(this.nextSibling); - return false; -} - -config.macros.search.onKeyPress = function(e) -{ - if(!e) var e = window.event; - switch(e.keyCode) - { - case 13: // Ctrl-Enter - case 10: // Ctrl-Enter on IE PC - config.macros.search.doSearch(this); - break; - case 27: // Escape - this.value = ""; - clearMessage(); - break; - } - if(this.value.length > 2) - { - if(this.value != this.getAttribute("lastSearchText")) - { - if(config.macros.search.timeout) - clearTimeout(config.macros.search.timeout); - var txt = this; - config.macros.search.timeout = setTimeout(function() {config.macros.search.doSearch(txt);},500); - } - } - else - { - if(config.macros.search.timeout) - clearTimeout(config.macros.search.timeout); - } -} - -config.macros.search.onFocus = function(e) -{ - this.select(); -} - -config.macros.tiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler) -{ - params = paramString.parseParams("name",null,true,false,true); - var names = params[0]["name"]; - var tiddlerName = names[0]; - var className = names[1] ? names[1] : null; - var args = params[0]["with"]; - var wrapper = createTiddlyElement(place,"span",null,className); - if(!args) - { - wrapper.setAttribute("refresh","content"); - wrapper.setAttribute("tiddler",tiddlerName); - } - var text = store.getTiddlerText(tiddlerName); - if(text) - { - var stack = config.macros.tiddler.tiddlerStack; - if(stack.indexOf(tiddlerName) !== -1) - return; - stack.push(tiddlerName); - try - { - var n = args ? Math.min(args.length,9) : 0; - for(var i=0; i<n; i++) - { - var placeholderRE = new RegExp("\\$" + (i + 1),"mg"); - text = text.replace(placeholderRE,args[i]); - } - config.macros.tiddler.renderText(wrapper,text,tiddlerName,params); - } - finally - { - stack.pop(); - } - } -} - -config.macros.tiddler.renderText = function(place,text,tiddlerName,params) -{ - wikify(text,place,null,store.getTiddler(tiddlerName)); -} - -config.macros.tiddler.tiddlerStack = []; - -config.macros.tag.handler = function(place,macroName,params) -{ - createTagButton(place,params[0]); -} - -config.macros.tags.handler = function(place,macroName,params,wikifier,paramString,tiddler) -{ - params = paramString.parseParams("anon",null,true,false,false); - var theList = createTiddlyElement(place,"ul"); - var title = getParam(params,"anon",""); - if(title && store.tiddlerExists(title)) - tiddler = store.getTiddler(title); - var sep = getParam(params,"sep"," "); - var lingo = config.views.wikified.tag; - var prompt = tiddler.tags.length == 0 ? lingo.labelNoTags : lingo.labelTags; - createTiddlyElement(theList,"li",null,"listTitle",prompt.format([tiddler.title])); - for(var t=0; t<tiddler.tags.length; t++) - { - createTagButton(createTiddlyElement(theList,"li"),tiddler.tags[t],tiddler.title); - if(t<tiddler.tags.length-1) - createTiddlyText(theList,sep); - } -} - -config.macros.tagging.handler = function(place,macroName,params,wikifier,paramString,tiddler) -{ - params = paramString.parseParams("anon",null,true,false,false); - var theList = createTiddlyElement(place,"ul"); - var title = getParam(params,"anon",""); - if(title == "" && tiddler instanceof Tiddler) - title = tiddler.title; - var sep = getParam(params,"sep"," "); - theList.setAttribute("title",this.tooltip.format([title])); - var tagged = store.getTaggedTiddlers(title); - var prompt = tagged.length == 0 ? this.labelNotTag : this.label; - createTiddlyElement(theList,"li",null,"listTitle",prompt.format([title,tagged.length])); - for(var t=0; t<tagged.length; t++) - { - createTiddlyLink(createTiddlyElement(theList,"li"),tagged[t].title,true); - if(t<tagged.length-1) - createTiddlyText(theList,sep); - } -} - -config.macros.closeAll.handler = function(place) -{ - createTiddlyButton(place,this.label,this.prompt,this.onClick); -} - -config.macros.closeAll.onClick = function(e) -{ - story.closeAllTiddlers(); - return false; -} - -config.macros.permaview.handler = function(place) -{ - createTiddlyButton(place,this.label,this.prompt,this.onClick); -} - -config.macros.permaview.onClick = function(e) -{ - story.permaView(); - return false; -} - -config.macros.saveChanges.handler = function(place) -{ - if(!readOnly) - createTiddlyButton(place,this.label,this.prompt,this.onClick,null,null,this.accessKey); -} - -config.macros.saveChanges.onClick = function(e) -{ - saveChanges(); - return false; -} - -config.macros.slider.onClickSlider = function(e) -{ - if(!e) var e = window.event; - var n = this.nextSibling; - var cookie = n.getAttribute("cookie"); - var isOpen = n.style.display != "none"; - if(anim && config.options.chkAnimate) - anim.startAnimating(new Slider(n,!isOpen,e.shiftKey || e.altKey,"none")); - else - n.style.display = isOpen ? "none" : "block"; - config.options[cookie] = !isOpen; - saveOptionCookie(cookie); - return false; -} - -config.macros.slider.createSlider = function(place,cookie,title,tooltip) -{ - var cookie = cookie ? cookie : ""; - var btn = createTiddlyButton(place,title,tooltip,this.onClickSlider); - var panel = createTiddlyElement(null,"div",null,"sliderPanel"); - panel.setAttribute("cookie",cookie); - panel.style.display = config.options[cookie] ? "block" : "none"; - place.appendChild(panel); - return panel; -} - -config.macros.slider.handler = function(place,macroName,params) -{ - var panel = this.createSlider(place,params[0],params[2],params[3]); - var text = store.getTiddlerText(params[1]); - panel.setAttribute("refresh", "content"); - panel.setAttribute("tiddler", params[1]); - if(text) - wikify(text,panel,null,store.getTiddler(params[1])); -} - -config.macros.option.onChangeOption = function(e) -{ - var opt = this.getAttribute("option"); - var elementType,valueField; - if(opt) - { - switch(opt.substr(0,3)) - { - case "txt": - elementType = "input"; - valueField = "value"; - break; - case "chk": - elementType = "input"; - valueField = "checked"; - break; - } - config.options[opt] = this[valueField]; - saveOptionCookie(opt); - var nodes = document.getElementsByTagName(elementType); - for(var t=0; t<nodes.length; t++) - { - var optNode = nodes[t].getAttribute("option"); - if(opt == optNode) - nodes[t][valueField] = this[valueField]; - } - } - return(true); -} - -config.macros.option.handler = function(place,macroName,params) -{ - var opt = params[0]; - if(config.options[opt] == undefined) - return; - var c; - switch(opt.substr(0,3)) - { - case "txt": - c = document.createElement("input"); - c.onkeyup = this.onChangeOption; - c.setAttribute("option",opt); - c.className = "txtOptionInput"; - place.appendChild(c); - c.value = config.options[opt]; - break; - case "chk": - c = document.createElement("input"); - c.setAttribute("type","checkbox"); - c.onclick = this.onChangeOption; - c.setAttribute("option",opt); - c.className = "chkOptionInput"; - place.appendChild(c); - c.checked = config.options[opt]; - break; - } -} - - - -config.macros.newTiddler.createNewTiddlerButton = function(place,title,params,label,prompt,accessKey,newFocus,isJournal) -{ - var tags = []; - for(var t=1; t<params.length; t++) - if((params[t].name == "anon" && t != 1) || (params[t].name == "tag")) - tags.push(params[t].value); - label = getParam(params,"label",label); - prompt = getParam(params,"prompt",prompt); - accessKey = getParam(params,"accessKey",accessKey); - newFocus = getParam(params,"focus",newFocus); - var btn = createTiddlyButton(place,label,prompt,this.onClickNewTiddler,null,null,accessKey); - btn.setAttribute("newTitle",title); - btn.setAttribute("isJournal",isJournal); - btn.setAttribute("params",tags.join("|")); - btn.setAttribute("newFocus",newFocus); - btn.setAttribute("newTemplate",getParam(params,"template",DEFAULT_EDIT_TEMPLATE)); - var text = getParam(params,"text"); - if(text !== undefined) - btn.setAttribute("newText",text); - return btn; -} - -config.macros.newTiddler.onClickNewTiddler = function() -{ - var title = this.getAttribute("newTitle"); - if(this.getAttribute("isJournal")) - { - var now = new Date(); - title = now.formatString(title.trim()); - } - var params = this.getAttribute("params").split("|"); - var focus = this.getAttribute("newFocus"); - var template = this.getAttribute("newTemplate"); - story.displayTiddler(null,title,template); - var text = this.getAttribute("newText"); - if(typeof text == "string") - story.getTiddlerField(title,"text").value = text.format([title]); - for(var t=0;t<params.length;t++) - story.setTiddlerTag(title,params[t],+1); - story.focusTiddler(title,focus); - return false; -} - -config.macros.newTiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler) -{ - if(!readOnly) - { - params = paramString.parseParams("anon",null,true,false,false); - var title = params[1] && params[1].name == "anon" ? params[1].value : this.title; - title = getParam(params,"title",title); - this.createNewTiddlerButton(place,title,params,this.label,this.prompt,this.accessKey,"title",false); - } -} - -config.macros.newJournal.handler = function(place,macroName,params,wikifier,paramString,tiddler) -{ - if(!readOnly) - { - params = paramString.parseParams("anon",null,true,false,false); - var title = params[1] && params[1].name == "anon" ? params[1].value : ""; - title = getParam(params,"title",title); - config.macros.newTiddler.createNewTiddlerButton(place,title,params,this.label,this.prompt,this.accessKey,"text",true); - } -} - -config.macros.sparkline.handler = function(place,macroName,params) -{ - var data = []; - var min = 0; - var max = 0; - for(var t=0; t<params.length; t++) - { - var v = parseInt(params[t]); - if(v < min) - min = v; - if(v > max) - max = v; - data.push(v); - } - if(data.length < 1) - return; - var box = createTiddlyElement(place,"span",null,"sparkline",String.fromCharCode(160)); - box.title = data.join(","); - var w = box.offsetWidth; - var h = box.offsetHeight; - box.style.paddingRight = (data.length * 2 - w) + "px"; - box.style.position = "relative"; - for(var d=0; d<data.length; d++) - { - var tick = document.createElement("img"); - tick.border = 0; - tick.className = "sparktick"; - tick.style.position = "absolute"; - tick.src = "data:image/gif,GIF89a%01%00%01%00%91%FF%00%FF%FF%FF%00%00%00%C0%C0%C0%00%00%00!%F9%04%01%00%00%02%00%2C%00%00%00%00%01%00%01%00%40%02%02T%01%00%3B"; - tick.style.left = d*2 + "px"; - tick.style.width = "2px"; - var v = Math.floor(((data[d] - min)/(max-min)) * h); - tick.style.top = (h-v) + "px"; - tick.style.height = v + "px"; - box.appendChild(tick); - } -} - -config.macros.tabs.handler = function(place,macroName,params) -{ - var cookie = params[0]; - var numTabs = (params.length-1)/3; - var wrapper = createTiddlyElement(null,"div",null,cookie); - var tabset = createTiddlyElement(wrapper,"div",null,"tabset"); - tabset.setAttribute("cookie",cookie); - var validTab = false; - for(var t=0; t<numTabs; t++) - { - var label = params[t*3+1]; - var prompt = params[t*3+2]; - var content = params[t*3+3]; - var tab = createTiddlyButton(tabset,label,prompt,this.onClickTab,"tab tabUnselected"); - tab.setAttribute("tab",label); - tab.setAttribute("content",content); - tab.title = prompt; - if(config.options[cookie] == label) - validTab = true; - } - if(!validTab) - config.options[cookie] = params[1]; - place.appendChild(wrapper); - this.switchTab(tabset,config.options[cookie]); -} - -config.macros.tabs.onClickTab = function(e) -{ - config.macros.tabs.switchTab(this.parentNode,this.getAttribute("tab")); - return false; -} - -config.macros.tabs.switchTab = function(tabset,tab) -{ - var cookie = tabset.getAttribute("cookie"); - var theTab = null - var nodes = tabset.childNodes; - for(var t=0; t<nodes.length; t++) - if(nodes[t].getAttribute && nodes[t].getAttribute("tab") == tab) - { - theTab = nodes[t]; - theTab.className = "tab tabSelected"; - } - else - nodes[t].className = "tab tabUnselected" - if(theTab) - { - if(tabset.nextSibling && tabset.nextSibling.className == "tabContents") - tabset.parentNode.removeChild(tabset.nextSibling); - var tabContent = createTiddlyElement(null,"div",null,"tabContents"); - tabset.parentNode.insertBefore(tabContent,tabset.nextSibling); - var contentTitle = theTab.getAttribute("content"); - wikify(store.getTiddlerText(contentTitle),tabContent,null,store.getTiddler(contentTitle)); - if(cookie) - { - config.options[cookie] = tab; - saveOptionCookie(cookie); - } - } -} - -// <<gradient [[tiddler name]] vert|horiz rgb rgb rgb rgb... >> -config.macros.gradient.handler = function(place,macroName,params,wikifier) -{ - var terminator = ">>"; - var panel; - if(wikifier) - panel = createTiddlyElement(place,"div",null,"gradient"); - else - panel = place; - panel.style.position = "relative"; - panel.style.overflow = "hidden"; - panel.style.zIndex = "0"; - var t; - if(wikifier) - { - var styles = config.formatterHelpers.inlineCssHelper(wikifier); - config.formatterHelpers.applyCssHelper(panel,styles); - } - var colours = []; - for(t=1; t<params.length; t++) - { - var c = new RGB(params[t]); - if(c) - colours.push(c); - } - drawGradient(panel,params[0] != "vert",colours); - if(wikifier) - wikifier.subWikify(panel,terminator); - if(document.all) - { - panel.style.height = "100%"; - panel.style.width = "100%"; - } -} - -config.macros.message.handler = function(place,macroName,params) -{ - if(params[0]) - { - var m = config; - var p = params[0].split("."); - for(var t=0; t<p.length; t++) - { - if(p[t] in m) - m = m[p[t]]; - else - break; - } - createTiddlyText(place,m.toString().format(params.splice(1))); - } -} - -config.macros.view.handler = function(place,macroName,params,wikifier,paramString,tiddler) -{ - if((tiddler instanceof Tiddler) && params[0]) - { - var value = store.getValue(tiddler,params[0]); - if(value != undefined) - switch(params[1]) - { - case undefined: - highlightify(value,place,highlightHack); - break; - case "link": - createTiddlyLink(place,value,true); - break; - case "wikified": - wikify(value,place,highlightHack,tiddler); - break; - case "date": - value = Date.convertFromYYYYMMDDHHMM(value); - if(params[2]) - createTiddlyText(place,value.formatString(params[2])); - else - createTiddlyText(place,value); - break; - } - } -} - -config.macros.edit.handler = function(place,macroName,params,wikifier,paramString,tiddler) -{ - var field = params[0]; - if((tiddler instanceof Tiddler) && field) - { - story.setDirty(tiddler.title,true); - if(field != "text") - { - var e = createTiddlyElement(null,"input"); - if(tiddler.isReadOnly()) - e.setAttribute("readOnly","readOnly"); - e.setAttribute("edit",field); - e.setAttribute("type","text"); - var v = store.getValue(tiddler,field); - if(!v) - v = ""; - e.value = v; - e.setAttribute("size","40"); - e.setAttribute("autocomplete","off"); - place.appendChild(e); - } - else - { - var wrapper1 = createTiddlyElement(null,"fieldset",null,"fieldsetFix"); - var wrapper2 = createTiddlyElement(wrapper1,"div"); - var e = createTiddlyElement(wrapper2,"textarea"); - if(tiddler.isReadOnly()) - e.setAttribute("readOnly","readOnly"); - var v = store.getValue(tiddler,field); - if(!v) - v = ""; - e.value = v; - var rows = 10; - var lines = v.match(/\n/mg); - var maxLines = Math.max(parseInt(config.options.txtMaxEditRows),5); - if(lines != null && lines.length > rows) - rows = lines.length + 5; - rows = Math.min(rows,maxLines); - e.setAttribute("rows",rows); - e.setAttribute("edit",field); - place.appendChild(wrapper1); - } - } -} - -config.macros.tagChooser.onClick = function(e) -{ - if(!e) var e = window.event; - var lingo = config.views.editor.tagChooser; - var popup = Popup.create(this); - var tags = store.getTags(); - if(tags.length == 0) - createTiddlyText(createTiddlyElement(popup,"li"),lingo.popupNone); - for(var t=0; t<tags.length; t++) - { - var theTag = createTiddlyButton(createTiddlyElement(popup,"li"),tags[t][0],lingo.tagTooltip.format([tags[t][0]]),config.macros.tagChooser.onTagClick); - theTag.setAttribute("tag",tags[t][0]); - theTag.setAttribute("tiddler", this.getAttribute("tiddler")); - } - Popup.show(popup,false); - e.cancelBubble = true; - if(e.stopPropagation) e.stopPropagation(); - return(false); -} - -config.macros.tagChooser.onTagClick = function(e) -{ - if(!e) var e = window.event; - var tag = this.getAttribute("tag"); - var title = this.getAttribute("tiddler"); - if(!readOnly) - story.setTiddlerTag(title,tag,0); - return(false); -} - -config.macros.tagChooser.handler = function(place,macroName,params,wikifier,paramString,tiddler) -{ - if(tiddler instanceof Tiddler) - { - var title = tiddler.title; - var lingo = config.views.editor.tagChooser; - var btn = createTiddlyButton(place,lingo.text,lingo.tooltip,this.onClick); - btn.setAttribute("tiddler", title); - } -} - -// Create a toolbar command button -// place - parent DOM element -// command - reference to config.commands[] member -or- name of member -// tiddler - reference to tiddler that toolbar applies to -// theClass - the class to give the button -config.macros.toolbar.createCommand = function(place,commandName,tiddler,theClass) -{ - if(typeof commandName != "string") - { - var c = null; - for(var t in config.commands) - if(config.commands[t] == commandName) - c = t; - commandName = c; - } - if((tiddler instanceof Tiddler) && (typeof commandName == "string")) - { - var title = tiddler.title; - var command = config.commands[commandName]; - var ro = tiddler.isReadOnly(); - var shadow = store.isShadowTiddler(title) && !store.tiddlerExists(title); - var text = ro && command.readOnlyText ? command.readOnlyText : command.text; - var tooltip = ro && command.readOnlyTooltip ? command.readOnlyTooltip : command.tooltip; - if((!ro || (ro && !command.hideReadOnly)) && !(shadow && command.hideShadow)) - - { - var btn = createTiddlyButton(null,text,tooltip,this.onClickCommand); - btn.setAttribute("commandName", commandName); - btn.setAttribute("tiddler", title); - if(theClass) - addClass(btn,theClass); - place.appendChild(btn); - } - } -} - -config.macros.toolbar.onClickCommand = function(e) -{ - if(!e) var e = window.event; - var command = config.commands[this.getAttribute("commandName")]; - return command.handler(e,this,this.getAttribute("tiddler")); -} - -// Invoke the first command encountered from a given place that is tagged with a specified class -config.macros.toolbar.invokeCommand = function(place,theClass,event) -{ - var children = place.getElementsByTagName("a") - for(var t=0; t<children.length; t++) - { - var c = children[t]; - if(hasClass(c,theClass) && c.getAttribute && c.getAttribute("commandName")) - { - if(c.onclick instanceof Function) - c.onclick.call(c,event); - break; - } - } -} - -config.macros.toolbar.handler = function(place,macroName,params,wikifier,paramString,tiddler) -{ - for(var t=0; t<params.length; t++) - { - var c = params[t]; - var theClass = ""; - switch(c.substr(0,1)) - { - case "+": - theClass = "defaultCommand"; - c = c.substr(1); - break; - case "-": - theClass = "cancelCommand"; - c = c.substr(1); - break; - } - if(c in config.commands) - this.createCommand(place,c,tiddler,theClass); - } -} - -config.macros.plugins.handler = function(place,macroName,params,wikifier,paramString,tiddler) -{ - var e = createTiddlyElement(place,"div"); - e.setAttribute("refresh","macro"); - e.setAttribute("macroName","plugins"); - e.setAttribute("params",paramString); - this.refresh(e,paramString); -} - -config.macros.plugins.refresh = function(place,params) -{ - var selectedRows = []; - ListView.forEachSelector(place,function(e,rowName) { - if(e.checked) - selectedRows.push(e.getAttribute("rowName")); - }); - removeChildren(place); - params = params.parseParams("anon"); - var plugins = installedPlugins.slice(0); - var t,tiddler,p; - var configTiddlers = store.getTaggedTiddlers("systemConfig"); - for(t=0; t<configTiddlers.length; t++) - { - tiddler = configTiddlers[t]; - if(plugins.findByField("title",tiddler.title) == null) - { - p = getPluginInfo(tiddler); - p.executed = false; - p.log.splice(0,0,this.skippedText); - plugins.push(p); - } - } - for(t=0; t<plugins.length; t++) - { - var p = plugins[t]; - p.forced = p.tiddler.isTagged("systemConfigForce"); - p.disabled = p.tiddler.isTagged("systemConfigDisable"); - p.Selected = selectedRows.indexOf(plugins[t].title) != -1; - } - if(plugins.length == 0) - createTiddlyElement(place,"em",null,null,this.noPluginText); - else - ListView.create(place,plugins,this.listViewTemplate,this.onSelectCommand); -} - -config.macros.plugins.onSelectCommand = function(command,rowNames) -{ - var t; - switch(command) - { - case "remove": - for(t=0; t<rowNames.length; t++) - store.setTiddlerTag(rowNames[t],false,"systemConfig"); - break; - case "delete": - if(rowNames.length > 0 && confirm(config.macros.plugins.confirmDeleteText.format([rowNames.join(", ")]))) - { - for(t=0; t<rowNames.length; t++) - { - store.removeTiddler(rowNames[t]); - story.closeTiddler(rowNames[t],true,false); - } - } - break; - } - if(config.options.chkAutoSave) - saveChanges(true); -} - -config.macros.refreshDisplay.handler = function(place) -{ - createTiddlyButton(place,this.label,this.prompt,this.onClick); -} - -config.macros.refreshDisplay.onClick = function(e) -{ - refreshAll(); - return false; -} - -config.macros.importTiddlers.handler = function(place,macroName,params,wikifier,paramString,tiddler) -{ - if(readOnly) - { - createTiddlyElement(place,"div",null,"marked",this.readOnlyWarning); - return; - } - var importer = createTiddlyElement(null,"div",null,"importTiddler wizard"); - createTiddlyElement(importer,"h1",null,null,this.wizardTitle); - createTiddlyElement(importer,"h2",null,"step1",this.step1); - var step = createTiddlyElement(importer,"div",null,"wizardStep"); - createTiddlyText(step,this.step1prompt); - var input = createTiddlyElement(null,"input",null,"txtOptionInput"); - input.type = "text"; - input.size = 50; - step.appendChild(input); - importer.inputBox = input; - createTiddlyElement(step,"br"); - createTiddlyText(step,this.step1promptFile); - var fileInput = createTiddlyElement(null,"input",null,"txtOptionInput"); - fileInput.type = "file"; - fileInput.size = 50; - fileInput.onchange = this.onBrowseChange; - fileInput.onkeyup = this.onBrowseChange; - step.appendChild(fileInput); - createTiddlyElement(step,"br"); - createTiddlyText(step,this.step1promptFeeds); - var feeds = this.getFeeds([{caption: this.step1feedPrompt, name: ""}]); - createTiddlyDropDown(step,this.onFeedChange,feeds); - createTiddlyElement(step,"br"); - createTiddlyButton(step,this.fetchLabel,this.fetchPrompt,this.onFetch,null,null,null); - place.appendChild(importer); -} - -config.macros.importTiddlers.getFeeds = function(feeds) -{ - var tagged = store.getTaggedTiddlers("contentPublisher","title"); - for(var t=0; t<tagged.length; t++) - feeds.push({caption: tagged[t].title, name: store.getTiddlerSlice(tagged[t].title,"URL")}); - return feeds; -} - -config.macros.importTiddlers.onFeedChange = function(e) -{ - var importer = findRelated(this,"importTiddler","className","parentNode"); - importer.inputBox.value = this.value; - this.selectedIndex = 0; -} - -config.macros.importTiddlers.onBrowseChange = function(e) -{ - var importer = findRelated(this,"importTiddler","className","parentNode"); - importer.inputBox.value = "file://" + this.value; -} - -config.macros.importTiddlers.onFetch = function(e) -{ - var importer = findRelated(this,"importTiddler","className","parentNode"); - var url = importer.inputBox.value; - var cutoff = findRelated(importer.firstChild,"step2","className","nextSibling"); - while(cutoff) - { - var temp = cutoff.nextSibling; - cutoff.parentNode.removeChild(cutoff); - cutoff = temp; - } - createTiddlyElement(importer,"h2",null,"step2",config.macros.importTiddlers.step2); - var step = createTiddlyElement(importer,"div",null,"wizardStep",config.macros.importTiddlers.step2Text.format([url])); - loadRemoteFile(url,config.macros.importTiddlers.onLoad,importer); -} - -config.macros.importTiddlers.onLoad = function(status,params,responseText,url,xhr) -{ - if(!status) - { - displayMessage(this.fetchError); - return; - } - var importer = params; - // Check that the tiddler we're in hasn't been closed - doesn't work on IE -// var p = importer; -// while(p.parentNode) -// p = p.parentNode; -// if(!(p instanceof HTMLDocument)) -// return; - // Crack out the content - (should be refactored) - var posOpeningDiv = responseText.indexOf(startSaveArea); - var limitClosingDiv = responseText.indexOf("<!--POST-BODY-START--"+">"); - var posClosingDiv = responseText.lastIndexOf(endSaveArea,limitClosingDiv == -1 ? responseText.length : limitClosingDiv); - if((posOpeningDiv == -1) || (posClosingDiv == -1)) - { - alert(config.messages.invalidFileError.format([url])); - return; - } - var content = "<html><body>" + responseText.substring(posOpeningDiv,posClosingDiv + endSaveArea.length) + "</body></html>"; - // Create the iframe - var iframe = document.createElement("iframe"); - iframe.style.display = "none"; - importer.insertBefore(iframe,importer.firstChild); - var doc = iframe.document; - if(iframe.contentDocument) - doc = iframe.contentDocument; // For NS6 - else if(iframe.contentWindow) - doc = iframe.contentWindow.document; // For IE5.5 and IE6 - // Put the content in the iframe - doc.open(); - doc.writeln(content); - doc.close(); - // Load the content into a TiddlyWiki() object - var storeArea = doc.getElementById("storeArea"); - var importStore = new TiddlyWiki(); - importStore.loadFromDiv(storeArea,"store"); - // Get rid of the iframe - iframe.parentNode.removeChild(iframe); - // Extract data for the listview - var tiddlers = []; - importStore.forEachTiddler(function(title,tiddler) - { - var t = {}; - t.title = title; - t.modified = tiddler.modified; - t.modifier = tiddler.modifier; - t.text = tiddler.text.substr(0,50); - t.tags = tiddler.tags; - tiddlers.push(t); - }); - // Display the listview - createTiddlyElement(importer,"h2",null,"step3",config.macros.importTiddlers.step3); - var step = createTiddlyElement(importer,"div",null,"wizardStep"); - ListView.create(step,tiddlers,config.macros.importTiddlers.listViewTemplate,config.macros.importTiddlers.onSelectCommand); - // Save the importer - importer.store = importStore; -} - -config.macros.importTiddlers.onSelectCommand = function(listView,command,rowNames) -{ - var importer = findRelated(listView,"importTiddler","className","parentNode"); - switch(command) - { - case "import": - config.macros.importTiddlers.doImport(importer,rowNames); - break; - } - if(config.options.chkAutoSave) - saveChanges(true); -} - -config.macros.importTiddlers.doImport = function(importer,rowNames) -{ - var theStore = importer.store; - var overwrite = new Array(); - var t; - for(t=0; t<rowNames.length; t++) - { - if(store.tiddlerExists(rowNames[t])) - overwrite.push(rowNames[t]); - } - if(overwrite.length > 0) - if(!confirm(this.confirmOverwriteText.format([overwrite.join(", ")]))) - return; - for(t=0; t<rowNames.length; t++) - { - var inbound = theStore.fetchTiddler(rowNames[t]); - store.saveTiddler(inbound.title, inbound.title, inbound.text, inbound.modifier, inbound.modified, inbound.tags); - store.fetchTiddler(inbound.title).created = inbound.created; - store.notify(rowNames[t],false); - } - store.notifyAll(); - store.setDirty(true); - createTiddlyElement(importer,"h2",null,"step4",this.step4.format([rowNames.length])); - var step = createTiddlyElement(importer,"div",null,"wizardStep"); - for(t=0; t<rowNames.length; t++) - { - createTiddlyLink(step,rowNames[t],true); - createTiddlyElement(step,"br"); - } - createTiddlyElement(importer,"h2",null,"step5",this.step5); -} -// --------------------------------------------------------------------------------- -// Menu and toolbar commands -// --------------------------------------------------------------------------------- - -config.commands.closeTiddler.handler = function(event,src,title) -{ - story.closeTiddler(title,true,event.shiftKey || event.altKey); - return false; -} - -config.commands.closeOthers.handler = function(event,src,title) -{ - story.closeAllTiddlers(title); - return false; -} - -config.commands.editTiddler.handler = function(event,src,title) -{ - clearMessage(); - story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE); - story.focusTiddler(title,"text"); - return false; -} - -config.commands.saveTiddler.handler = function(event,src,title) -{ - var newTitle = story.saveTiddler(title,event.shiftKey); - if(newTitle) - story.displayTiddler(null,newTitle); - return false; -} - -config.commands.cancelTiddler.handler = function(event,src,title) -{ - if(story.hasChanges(title) && !readOnly) - if(!confirm(this.warning.format([title]))) - return false; - story.setDirty(title,false); - story.displayTiddler(null,title); - return false; -} - -config.commands.deleteTiddler.handler = function(event,src,title) -{ - var deleteIt = true; - if (config.options.chkConfirmDelete) - deleteIt = confirm(this.warning.format([title])); - if (deleteIt) - { - store.removeTiddler(title); - story.closeTiddler(title,true,event.shiftKey || event.altKey); - if(config.options.chkAutoSave) - saveChanges(); - } - return false; -} - -config.commands.permalink.handler = function(event,src,title) -{ - var t = encodeURIComponent(String.encodeTiddlyLink(title)); - if(window.location.hash != t) - window.location.hash = t; - return false; -} - -config.commands.references.handler = function(event,src,title) -{ - var popup = Popup.create(src); - if(popup) - { - var references = store.getReferringTiddlers(title); - var c = false; - for(var r=0; r<references.length; r++) - if(references[r].title != title && !references[r].isTagged("excludeLists")) - { - createTiddlyLink(createTiddlyElement(popup,"li"),references[r].title,true); - c = true; - } - if(!c) - createTiddlyText(createTiddlyElement(popup,"li",null,"disabled"),this.popupNone); - } - Popup.show(popup,false); - event.cancelBubble = true; - if (event.stopPropagation) event.stopPropagation(); - return false; -} - -config.commands.jump.handler = function(event,src,title) -{ - var popup = Popup.create(src); - if(popup) - { - story.forEachTiddler(function(title,element) { - createTiddlyLink(createTiddlyElement(popup,"li"),title,true); - }); - } - Popup.show(popup,false); - event.cancelBubble = true; - if (event.stopPropagation) event.stopPropagation(); - return false; -} - -// --------------------------------------------------------------------------------- -// Tiddler() object -// --------------------------------------------------------------------------------- - -function Tiddler() -{ - this.title = null; - this.text = null; - this.modifier = null; - this.modified = new Date(); - this.created = new Date(); - this.links = []; - this.linksUpdated = false; - this.tags = []; - return this; -} - -Tiddler.prototype.getLinks = function() -{ - if(this.linksUpdated==false) - this.changed(); - return this.links; -} - -// Format the text for storage in an RSS item -Tiddler.prototype.saveToRss = function(url) -{ - var s = []; - s.push("<item>"); - s.push("<title" + ">" + this.title.htmlEncode() + "</title" + ">"); - s.push("<description>" + wikifyStatic(this.text,null,this).htmlEncode() + "</description>"); - for(var t=0; t<this.tags.length; t++) - s.push("<category>" + this.tags[t] + "</category>"); - s.push("<link>" + url + "#" + encodeURIComponent(String.encodeTiddlyLink(this.title)) + "</link>"); - s.push("<pubDate>" + this.modified.toGMTString() + "</pubDate>"); - s.push("</item>"); - return(s.join("\n")); -} - -// Change the text and other attributes of a tiddler -Tiddler.prototype.set = function(title,text,modifier,modified,tags,created,fields) -{ - this.assign(title,text,modifier,modified,tags,created,fields); - this.changed(); - return this; -} - -// Change the text and other attributes of a tiddler without triggered a tiddler.changed() call -Tiddler.prototype.assign = function(title,text,modifier,modified,tags,created,fields) -{ - if(title != undefined) - this.title = title; - if(text != undefined) - this.text = text; - if(modifier != undefined) - this.modifier = modifier; - if(modified != undefined) - this.modified = modified; - if(created != undefined) - this.created = created; - if(fields != undefined) - this.fields = fields; - if(tags != undefined) - this.tags = (typeof tags == "string") ? tags.readBracketedList() : tags; - else if(this.tags == undefined) - this.tags = []; - return this; -} - -// Get the tags for a tiddler as a string (space delimited, using [[brackets]] for tags containing spaces) -Tiddler.prototype.getTags = function() -{ - return String.encodeTiddlyLinkList(this.tags); -} - -// Test if a tiddler carries a tag -Tiddler.prototype.isTagged = function(tag) -{ - return this.tags.indexOf(tag) != -1; -} - -// Static method to convert "\n" to newlines, "\s" to "\" -Tiddler.unescapeLineBreaks = function(text) -{ - return text ? text.unescapeLineBreaks() : ""; -} - -// Convert newlines to "\n", "\" to "\s" -Tiddler.prototype.escapeLineBreaks = function() -{ - return this.text.escapeLineBreaks(); -} - -// Updates the secondary information (like links[] array) after a change to a tiddler -Tiddler.prototype.changed = function() -{ - this.links = []; - var t = this.autoLinkWikiWords() ? 0 : 1; - var tiddlerLinkRegExp = t==0 ? config.textPrimitives.tiddlerAnyLinkRegExp : config.textPrimitives.tiddlerForcedLinkRegExp; - tiddlerLinkRegExp.lastIndex = 0; - var formatMatch = tiddlerLinkRegExp.exec(this.text); - while(formatMatch) - { - if(t==0 && formatMatch[1] && formatMatch[1] != this.title) // wikiWordLink - { - if(formatMatch.index > 0) - { - var preRegExp = new RegExp(config.textPrimitives.unWikiLink+"|"+config.textPrimitives.anyLetter,"mg"); - preRegExp.lastIndex = formatMatch.index-1; - var preMatch = preRegExp.exec(this.text); - if(preMatch.index != formatMatch.index-1) - this.links.pushUnique(formatMatch[1]); - } - else - this.links.pushUnique(formatMatch[1]); - } - else if(formatMatch[2-t] && (store.tiddlerExists(formatMatch[3-t]) || store.isShadowTiddler(formatMatch[3-t]))) // titledBrackettedLink - this.links.pushUnique(formatMatch[3-t]); - else if(formatMatch[4-t] && formatMatch[4-t] != this.title) // brackettedLink - this.links.pushUnique(formatMatch[4-t]); - // Do not add link if match urlPattern (formatMatch[5-t]) - formatMatch = tiddlerLinkRegExp.exec(this.text); - } - this.linksUpdated = true; - return; -} - -Tiddler.prototype.getSubtitle = function() -{ - var theModifier = this.modifier; - if(!theModifier) - theModifier = config.messages.subtitleUnknown; - var theModified = this.modified; - if(theModified) - theModified = theModified.toLocaleString(); - else - theModified = config.messages.subtitleUnknown; - return(config.messages.tiddlerLinkTooltip.format([this.title,theModifier,theModified])); -} - -Tiddler.prototype.isReadOnly = function() -{ - return readOnly; -} - -Tiddler.prototype.autoLinkWikiWords = function() -{ - return !(this.isTagged("systemConfig") || this.isTagged("excludeMissing")); -} - -Tiddler.prototype.generateFingerprint = function() -{ - return "0x" + Crypto.hexSha1Str(this.text); -} - -// --------------------------------------------------------------------------------- -// TiddlyWiki() object contains Tiddler()s -// --------------------------------------------------------------------------------- - -function TiddlyWiki() -{ - var tiddlers = {}; // Hashmap by name of tiddlers - this.tiddlersUpdated = false; - this.namedNotifications = []; // Array of {name:,notify:} of notification functions - this.notificationLevel = 0; - this.slices = {}; // map tiddlerName->(map sliceName->sliceValue). Lazy. - this.clear = function() { - tiddlers = {}; - this.setDirty(false); - }; - this.fetchTiddler = function(title) { - return tiddlers[title]; - }; - this.deleteTiddler = function(title) { - delete this.slices[title]; - delete tiddlers[title]; - }; - this.addTiddler = function(tiddler) { - delete this.slices[tiddler.title]; - tiddlers[tiddler.title] = tiddler; - }; - this.forEachTiddler = function(callback) { - for(var t in tiddlers) - { - var tiddler = tiddlers[t]; - if(tiddler instanceof Tiddler) - callback.call(this,t,tiddler); - } - }; -} - -// Set the dirty flag -TiddlyWiki.prototype.setDirty = function(dirty) -{ - this.dirty = dirty; -} - -TiddlyWiki.prototype.isDirty = function() -{ - return this.dirty; -} - -TiddlyWiki.prototype.suspendNotifications = function() -{ - this.notificationLevel--; -} - -TiddlyWiki.prototype.resumeNotifications = function() -{ - this.notificationLevel++; -} - -// Invoke the notification handlers for a particular tiddler -TiddlyWiki.prototype.notify = function(title,doBlanket) -{ - if(!this.notificationLevel) - for(var t=0; t<this.namedNotifications.length; t++) - { - var n = this.namedNotifications[t]; - if((n.name == null && doBlanket) || (n.name == title)) - n.notify(title); - } -} - -// Invoke the notification handlers for all tiddlers -TiddlyWiki.prototype.notifyAll = function() -{ - if(!this.notificationLevel) - for(var t=0; t<this.namedNotifications.length; t++) - { - var n = this.namedNotifications[t]; - if(n.name) - n.notify(n.name); - } -} - -// Add a notification handler to a tiddler -TiddlyWiki.prototype.addNotification = function(title,fn) -{ - for (var i=0; i<this.namedNotifications.length; i++) - if((this.namedNotifications[i].name == title) && (this.namedNotifications[i].notify == fn)) - return this; - this.namedNotifications.push({name: title, notify: fn}); - return this; -} - -TiddlyWiki.prototype.removeTiddler = function(title) -{ - var tiddler = this.fetchTiddler(title); - if(tiddler) - { - this.deleteTiddler(title); - this.notify(title,true); - this.setDirty(true); - } -} - -TiddlyWiki.prototype.tiddlerExists = function(title) -{ - var t = this.fetchTiddler(title); - return (t != undefined); -} - -TiddlyWiki.prototype.isShadowTiddler = function(title) -{ - return typeof config.shadowTiddlers[title] == "string"; -} - -TiddlyWiki.prototype.getTiddler = function(title) -{ - var t = this.fetchTiddler(title); - if(t != undefined) - return t; - else - return null; -} - -TiddlyWiki.prototype.getTiddlerText = function(title,defaultText) -{ - var tiddler = this.fetchTiddler(title); - if(tiddler) - return tiddler.text; - if(!title) - return defaultText; - var pos = title.indexOf(config.textPrimitives.sliceSeparator); - if(pos != -1) - { - var slice = this.getTiddlerSlice(title.substr(0,pos),title.substr(pos + config.textPrimitives.sliceSeparator.length)); - if(slice) - return slice; - } - if(this.isShadowTiddler(title)) - return config.shadowTiddlers[title]; - if(defaultText != undefined) - return defaultText; - return null; -} - -TiddlyWiki.prototype.slicesRE = /(?:[\'\/]*~?(\w+)[\'\/]*\:[\'\/]*\s*(.*?)\s*$)|(?:\|[\'\/]*~?(\w+)\:?[\'\/]*\|\s*(.*?)\s*\|)/gm - -// @internal -TiddlyWiki.prototype.calcAllSlices = function(title) -{ - var slices = {}; - var text = this.getTiddlerText(title,""); - this.slicesRE.lastIndex = 0; - do - { - var m = this.slicesRE.exec(text); - if (m) - { - if (m[1]) - slices[m[1]] = m[2]; - else - slices[m[3]] = m[4]; - } - } - while(m); - return slices; -} - -// Returns the slice of text of the given name -//# -//# A text slice is a substring in the tiddler's text that is defined -//# either like this -//# aName: textSlice -//# or -//# |aName:| textSlice | -//# or -//# |aName| textSlice | -//# -//# In the text the name (or name:) may be decorated with '' or //. I.e. -//# this would also a possible text slice: -//# -//# |''aName:''| textSlice | -//# -//# @param name should only contain "word characters" (i.e. "a-ZA-Z_0-9") -//# @return [may be undefined] the (trimmed) text of the specified slice. -TiddlyWiki.prototype.getTiddlerSlice = function(title,sliceName) -{ - var slices = this.slices[title]; - if (!slices) { - slices = this.calcAllSlices(title); - this.slices[title] = slices; - } - return slices[sliceName]; -} - -// Build an hashmap of the specified named slices of a tiddler -TiddlyWiki.prototype.getTiddlerSlices = function(title,sliceNames) -{ - var r = {}; - for(var t=0; t<sliceNames.length; t++) - { - var slice = this.getTiddlerSlice(title,sliceNames[t]); - if(slice) - r[sliceNames[t]] = slice; - } - return r; -} - -TiddlyWiki.prototype.getRecursiveTiddlerText = function(title,defaultText,depth) -{ - var bracketRegExp = new RegExp("(?:\\[\\[([^\\]]+)\\]\\])","mg"); - var text = this.getTiddlerText(title,null); - if(text == null) - return defaultText; - var textOut = []; - var lastPos = 0; - do { - var match = bracketRegExp.exec(text); - if(match) - { - textOut.push(text.substr(lastPos,match.index-lastPos)); - if(match[1]) - { - if(depth <= 0) - textOut.push(match[1]); - else - textOut.push(this.getRecursiveTiddlerText(match[1],"[[" + match[1] + "]]",depth-1)); - } - lastPos = match.index + match[0].length; - } - else - textOut.push(text.substr(lastPos)); - } while(match); - return(textOut.join("")); -} - -TiddlyWiki.prototype.setTiddlerTag = function(title,status,tag) -{ - var tiddler = this.fetchTiddler(title); - if(tiddler) - { - var t = tiddler.tags.indexOf(tag); - if(t != -1) - tiddler.tags.splice(t,1); - if(status) - tiddler.tags.push(tag); - tiddler.changed(); - this.notify(title,true); - this.setDirty(true); - } -} - -TiddlyWiki.prototype.saveTiddler = function(title,newTitle,newBody,modifier,modified,tags,fields) -{ - var tiddler = this.fetchTiddler(title); - var created; - if(tiddler) - { - created = tiddler.created; // Preserve created date - this.deleteTiddler(title); - } - else - { - tiddler = new Tiddler(); - created = modified; - } - tiddler.set(newTitle,newBody,modifier,modified,tags,created,fields); - this.addTiddler(tiddler); - if(title != newTitle) - this.notify(title,true); - this.notify(newTitle,true); - this.setDirty(true); - return tiddler; -} - -TiddlyWiki.prototype.createTiddler = function(title) -{ - var tiddler = this.fetchTiddler(title); - if(!tiddler) - { - tiddler = new Tiddler(); - tiddler.title = title; - this.addTiddler(tiddler); - this.setDirty(true); - } - return tiddler; -} - -// Load contents of a tiddlywiki from an HTML DIV -TiddlyWiki.prototype.loadFromDiv = function(src,idPrefix,noUpdate) -{ - this.idPrefix = idPrefix; - var storeElem = (typeof src == "string") ? document.getElementById(src) : src; - var tiddlers = this.getLoader().loadTiddlers(this,storeElem.childNodes); - this.setDirty(false); - if(!noUpdate) - { - for(var i = 0;i<tiddlers.length; i++) - tiddlers[i].changed(); - } -} - -TiddlyWiki.prototype.updateTiddlers = function() -{ - this.tiddlersUpdated = true; - this.forEachTiddler(function(title,tiddler) { - tiddler.changed(); - }); -} - -// Return all tiddlers formatted as an HTML string -TiddlyWiki.prototype.allTiddlersAsHtml = function() -{ - return store.getSaver().externalize(store); -} - -// Return an array of tiddlers matching a search regular expression -TiddlyWiki.prototype.search = function(searchRegExp,sortField,excludeTag) -{ - var candidates = this.reverseLookup("tags",excludeTag,false); - var results = []; - for(var t=0; t<candidates.length; t++) - { - if((candidates[t].title.search(searchRegExp) != -1) || (candidates[t].text.search(searchRegExp) != -1)) - results.push(candidates[t]); - } - if(!sortField) - sortField = "title"; - results.sort(function(a,b) {return a[sortField] < b[sortField] ? -1 : (a[sortField] == b[sortField] ? 0 : +1);}); - return results; -} - -// Return an array of all the tags in use. Each member of the array is another array where [0] is the name of the tag and [1] is the number of occurances -TiddlyWiki.prototype.getTags = function() -{ - var results = []; - this.forEachTiddler(function(title,tiddler) { - for(var g=0; g<tiddler.tags.length; g++) - { - var tag = tiddler.tags[g]; - var f = false; - for(var c=0; c<results.length; c++) - if(results[c][0] == tag) - { - f = true; - results[c][1]++; - } - if(!f) - results.push([tag,1]); - } - }); - results.sort(function(a,b) {return a[0].toLowerCase() < b[0].toLowerCase() ? -1 : (a[0].toLowerCase() == b[0].toLowerCase() ? 0 : +1);}); - return results; -} - -// Return an array of the tiddlers that are tagged with a given tag -TiddlyWiki.prototype.getTaggedTiddlers = function(tag,sortField) -{ - return this.reverseLookup("tags",tag,true,sortField); -} - -// Return an array of the tiddlers that link to a given tiddler -TiddlyWiki.prototype.getReferringTiddlers = function(title,unusedParameter,sortField) -{ - if(!this.tiddlersUpdated) - this.updateTiddlers(); - return this.reverseLookup("links",title,true,sortField); -} - -// Return an array of the tiddlers that do or do not have a specified entry in the specified storage array (ie, "links" or "tags") -// lookupMatch == true to match tiddlers, false to exclude tiddlers -TiddlyWiki.prototype.reverseLookup = function(lookupField,lookupValue,lookupMatch,sortField) -{ - var results = []; - this.forEachTiddler(function(title,tiddler) { - var f = !lookupMatch; - for(var lookup=0; lookup<tiddler[lookupField].length; lookup++) - if(tiddler[lookupField][lookup] == lookupValue) - f = lookupMatch; - if(f) - results.push(tiddler); - }); - if(!sortField) - sortField = "title"; - results.sort(function(a,b) {return a[sortField] < b[sortField] ? -1 : (a[sortField] == b[sortField] ? 0 : +1);}); - return results; -} - -// Return the tiddlers as a sorted array -TiddlyWiki.prototype.getTiddlers = function(field,excludeTag) -{ - var results = []; - this.forEachTiddler(function(title,tiddler) { - if(excludeTag == undefined || !tiddler.isTagged(excludeTag)) - results.push(tiddler); - }); - if(field) - results.sort(function(a,b) {return a[field] < b[field] ? -1 : (a[field] == b[field] ? 0 : +1);}); - return results; -} - -// Return array of names of tiddlers that are referred to but not defined -TiddlyWiki.prototype.getMissingLinks = function(sortField) -{ - if(!this.tiddlersUpdated) - this.updateTiddlers(); - var results = []; - this.forEachTiddler(function (title,tiddler) { - for(var n=0; n<tiddler.links.length;n++) - { - var link = tiddler.links[n]; - if(this.fetchTiddler(link) == null && !this.isShadowTiddler(link)) - results.pushUnique(link); - } - }); - results.sort(); - return results; -} - -// Return an array of names of tiddlers that are defined but not referred to -TiddlyWiki.prototype.getOrphans = function() -{ - var results = []; - this.forEachTiddler(function (title,tiddler) { - if(this.getReferringTiddlers(title).length == 0 && !tiddler.isTagged("excludeLists")) - results.push(title); - }); - results.sort(); - return results; -} - -// Return an array of names of all the shadow tiddlers -TiddlyWiki.prototype.getShadowed = function() -{ - var results = []; - for(var t in config.shadowTiddlers) - if(typeof config.shadowTiddlers[t] == "string") - results.push(t); - results.sort(); - return results; -} - -// Resolves a Tiddler reference or tiddler title into a Tiddler object, or null if it doesn't exist -TiddlyWiki.prototype.resolveTiddler = function(tiddler) -{ - var t = (typeof tiddler == 'string') ? this.getTiddler(tiddler) : tiddler; - return t instanceof Tiddler ? t : null; -} - -TiddlyWiki.prototype.getLoader = function() -{ - if (!this.loader) - this.loader = new TW21Loader(); - return this.loader; -} - -TiddlyWiki.prototype.getSaver = function() -{ - if (!this.saver) - this.saver = new TW21Saver(); - return this.saver; -} - -// Returns true if path is a valid field name (path), -// i.e. a sequence of identifiers, separated by '.' -TiddlyWiki.isValidFieldName = function (name) { - var match = /[a-zA-Z_]\w*(\.[a-zA-Z_]\w*)*/.exec(name); - return match && (match[0] == name); -} - -// Throws an exception when name is not a valid field name. -TiddlyWiki.checkFieldName = function(name) { - if (!TiddlyWiki.isValidFieldName(name)) - throw config.messages.invalidFieldName.format([name]); -} - -function StringFieldAccess(n, readOnly) { - this.set = readOnly - ? function(t,v) {if (v != t[n]) throw config.messages.fieldCannotBeChanged.format([n]);} - : function(t,v) {if (v != t[n]) {t[n] = v; return true;}}; - this.get = function(t) {return t[n];}; -} - -function DateFieldAccess(n) { - this.set = function(t,v) { - var d = v instanceof Date ? v : Date.convertFromYYYYMMDDHHMM(v); - if (d != t[n]) { - t[n] = d; return true; - } - }; - this.get = function(t) {return t[n].convertToYYYYMMDDHHMM();} -} - -function LinksFieldAccess(n) { - this.set = function(t,v) { - var s = (typeof v == "string") ? v.readBracketedList() : v; - if (s.toString() != t[n].toString()) { - t[n] = s; return true; - } - }; - this.get = function(t) {return String.encodeTiddlyLinkList(t[n]);} -} - -TiddlyWiki.standardFieldAccess = { - // The set functions return true when setting the data has changed the value. - - "title": new StringFieldAccess("title", true), - // Handle the "tiddler" field name as the title - "tiddler": new StringFieldAccess("title", true), - - "text": new StringFieldAccess("text"), - "modifier": new StringFieldAccess("modifier"), - "modified": new DateFieldAccess("modified"), - "created": new DateFieldAccess("created"), - "tags": new LinksFieldAccess("tags") -}; - -TiddlyWiki.isStandardField = function(name) { - return TiddlyWiki.standardFieldAccess[name] != undefined; -} - -// Sets the value of the given field of the tiddler to the value. -// Setting an ExtendedField's value to null or undefined removes the field. -// Setting a namespace to undefined removes all fields of that namespace. -// The fieldName is case-insensitive. -// All values will be converted to a string value. -TiddlyWiki.prototype.setValue = function(tiddler, fieldName, value) { - TiddlyWiki.checkFieldName(fieldName); - var t = this.resolveTiddler(tiddler); - if (!t) - return; - - fieldName = fieldName.toLowerCase(); - - var isRemove = (value === undefined) || (value === null); - - if (!t.fields) - t.fields = {}; - - var accessor = TiddlyWiki.standardFieldAccess[fieldName]; - if (accessor) { - if (isRemove) - // don't remove StandardFields - return; - var h = TiddlyWiki.standardFieldAccess[fieldName]; - if (!h.set(t, value)) - return; - - } else { - var oldValue = t.fields[fieldName]; - - if (isRemove) { - if (oldValue !== undefined) { - // deletes a single field - delete t.fields[fieldName]; - } else { - // no concrete value is defined for the fieldName - // so we guess this is a namespace path. - - // delete all fields in a namespace - var re = new RegExp('^'+fieldName+'\\.'); - var dirty = false; - for (var n in t.fields) { - if (n.match(re)) { - delete t.fields[n]; - dirty = true; - } - } - if (!dirty) - return - } - - } else { - // the "normal" set case. value is defined (not null/undefined) - // For convenience provide a nicer conversion Date->String - value = value instanceof Date - ? value.convertToYYYYMMDDHHMMSSMMM() - : String(value); - if (oldValue == value) - return; - t.fields[fieldName] = value; - } - } - - // When we are here the tiddler/store really was changed. - this.notify(t.title,true); - if (!fieldName.match(/^temp\./)) - this.setDirty(true); -} - -// Returns the value of the given field of the tiddler. -// The fieldName is case-insensitive. -// Will only return String values (or undefined). -TiddlyWiki.prototype.getValue = function(tiddler, fieldName) { - var t = this.resolveTiddler(tiddler); - if (!t) - return undefined; - - fieldName = fieldName.toLowerCase(); - - var accessor = TiddlyWiki.standardFieldAccess[fieldName]; - if (accessor) { - return accessor.get(t); - } - - return t.fields ? t.fields[fieldName] : undefined; -} - -// Calls the callback function for every field in the tiddler. -// -// When callback function returns a non-false value the iteration stops -// and that value is returned. -// -// The order of the fields is not defined. -// -// @param callback a function(tiddler, fieldName, value). -// -TiddlyWiki.prototype.forEachField = function(tiddler, callback, onlyExtendedFields) { - var t = this.resolveTiddler(tiddler); - if (!t) - return undefined; - - if (t.fields) { - for (var n in t.fields) { - var result = callback(t, n, t.fields[n]); - if (result) - return result; - } - } - - if (onlyExtendedFields) - return undefined; - - for (var n in TiddlyWiki.standardFieldAccess) { - if (n == "tiddler") - // even though the "title" field can also be referenced through the name "tiddler" - // we only visit this field once. - continue; - - var result = callback(t, n, TiddlyWiki.standardFieldAccess[n].get(t)); - if (result) - return result; - } - - return undefined; -}; -// --------------------------------------------------------------------------------- -// Story functions -// --------------------------------------------------------------------------------- - -// A story is a HTML div containing a sequence of tiddlers that can be manipulated -// container - id of containing element -// idPrefix - string prefix prepended to title to make ids for tiddlers in this story -function Story(container,idPrefix) -{ - this.container = container; - this.idPrefix = idPrefix; - this.highlightRegExp = null; -} - -// Iterate through all the tiddlers in a story -// fn - callback function to be called for each tiddler. Arguments are: -// tiddler - reference to Tiddler object -// element - reference to tiddler display element -Story.prototype.forEachTiddler = function(fn) -{ - var place = document.getElementById(this.container); - if(!place) - return; - var e = place.firstChild; - while(e) - { - var n = e.nextSibling; - var title = e.getAttribute("tiddler"); - fn.call(this,title,e); - e = n; - } -} - -// Display several tiddlers given their titles in an array. Parameters same as displayTiddler(), except: -// titles - array of string titles -Story.prototype.displayTiddlers = function(srcElement,titles,template,animate,slowly) -{ - for(var t = titles.length-1;t>=0;t--) - this.displayTiddler(srcElement,titles[t],template,animate,slowly); -} - -// Display a given tiddler with a given template. If the tiddler is already displayed but with a different -// template, it is switched to the specified template -// srcElement - reference to element from which this one is being opened -or- -// special positions "top", "bottom" -// title - title of tiddler to display -// template - the name of the tiddler containing the template -or- -// one of the constants DEFAULT_VIEW_TEMPLATE and DEFAULT_EDIT_TEMPLATE -or- -// null or undefined to indicate the current template if there is one, DEFAULT_VIEW_TEMPLATE if not -// animate - whether to perform animations -// slowly - whether to perform animations in slomo -Story.prototype.displayTiddler = function(srcElement,title,template,animate,slowly) -{ - var place = document.getElementById(this.container); - var tiddlerElem = document.getElementById(this.idPrefix + title); - if(tiddlerElem) - this.refreshTiddler(title,template); - else - { - var before = this.positionTiddler(srcElement); - tiddlerElem = this.createTiddler(place,before,title,template); - } - if(srcElement && typeof srcElement !== "string") - { - if(anim && config.options.chkAnimate && (animate == undefined || animate == true)) - anim.startAnimating(new Cascade(title,srcElement,tiddlerElem,slowly),new Scroller(tiddlerElem,slowly)); - else - window.scrollTo(0,ensureVisible(tiddlerElem)); - } -} - -// Figure out the appropriate position for a newly opened tiddler -// srcElement - reference to the element containing the link to the tiddler -or- -// special positions "top", "bottom" -// returns - reference to the tiddler that the new one should appear before (null for the bottom of the story) -Story.prototype.positionTiddler = function(srcElement) -{ - var place = document.getElementById(this.container); - var before; - if(typeof srcElement == "string") - { - switch(srcElement) - { - case "top": - before = place.firstChild; - break; - case "bottom": - before = null; - break; - } - } - else - { - var after = this.findContainingTiddler(srcElement); - if(after == null) - before = place.firstChild; - else if(after.nextSibling) - before = after.nextSibling; - else - before = null; - } - return before; -} - -// Create a tiddler frame at the appropriate place in a story column -// place - reference to parent element -// before - null, or reference to element before which to insert new tiddler -// title - title of new tiddler -// template - the name of the tiddler containing the template or one of the constants DEFAULT_VIEW_TEMPLATE and DEFAULT_EDIT_TEMPLATE -Story.prototype.createTiddler = function(place,before,title,template) -{ - var tiddlerElem = createTiddlyElement(null,"div",this.idPrefix + title,"tiddler"); - tiddlerElem.setAttribute("refresh","tiddler"); - place.insertBefore(tiddlerElem,before); - this.refreshTiddler(title,template); - return tiddlerElem; -} - -// Overridable for choosing the name of the template to apply for a tiddler -Story.prototype.chooseTemplateForTiddler = function(title,template) -{ - if(!template) - template = DEFAULT_VIEW_TEMPLATE; - if(template == DEFAULT_VIEW_TEMPLATE || template == DEFAULT_EDIT_TEMPLATE) - template = config.tiddlerTemplates[template]; - return template; -} - -// Overridable for extracting the text of a template from a tiddler -Story.prototype.getTemplateForTiddler = function(title,template,tiddler) -{ - return store.getRecursiveTiddlerText(template,null,10); -} - -// Apply a template to an existing tiddler if it is not already displayed using that template -// title - title of tiddler to update -// template - the name of the tiddler containing the template or one of the constants DEFAULT_VIEW_TEMPLATE and DEFAULT_EDIT_TEMPLATE -// force - if true, forces the refresh even if the template hasn't changedd -Story.prototype.refreshTiddler = function(title,template,force) -{ - var tiddlerElem = document.getElementById(this.idPrefix + title); - if(tiddlerElem) - { - if(tiddlerElem.getAttribute("dirty") == "true" && !force) - return tiddlerElem; - template = this.chooseTemplateForTiddler(title,template); - var currTemplate = tiddlerElem.getAttribute("template"); - if((template != currTemplate) || force) - { - var tiddler = store.getTiddler(title); - if(!tiddler) - { - tiddler = new Tiddler(); - if(store.isShadowTiddler(title)) - tiddler.set(title,store.getTiddlerText(title),config.views.wikified.shadowModifier,version.date,[],version.date); - else - { - var text = template=="EditTemplate" - ? config.views.editor.defaultText.format([title]) - : config.views.wikified.defaultText.format([title]); - tiddler.set(title,text,config.views.wikified.defaultModifier,version.date,[],version.date); - } - } - tiddlerElem.setAttribute("tags",tiddler.tags.join(" ")); - tiddlerElem.setAttribute("tiddler",title); - tiddlerElem.setAttribute("template",template); - var me = this; - tiddlerElem.onmouseover = this.onTiddlerMouseOver; - tiddlerElem.onmouseout = this.onTiddlerMouseOut; - tiddlerElem.ondblclick = this.onTiddlerDblClick; - tiddlerElem[window.event?"onkeydown":"onkeypress"] = this.onTiddlerKeyPress; - var html = this.getTemplateForTiddler(title,template,tiddler); - tiddlerElem.innerHTML = html; - applyHtmlMacros(tiddlerElem,tiddler); - if(store.getTaggedTiddlers(title).length > 0) - addClass(tiddlerElem,"isTag"); - else - removeClass(tiddlerElem,"isTag"); - if(!store.tiddlerExists(title)) - { - if(store.isShadowTiddler(title)) - addClass(tiddlerElem,"shadow"); - else - addClass(tiddlerElem,"missing"); - } - else - { - removeClass(tiddlerElem,"shadow"); - removeClass(tiddlerElem,"missing"); - } - } - } - return tiddlerElem; -} - -// Refresh all tiddlers in the Story -Story.prototype.refreshAllTiddlers = function() -{ - var place = document.getElementById(this.container); - var e = place.firstChild; - if(!e) - return; - this.refreshTiddler(e.getAttribute("tiddler"),e.getAttribute("template"),true); - while((e = e.nextSibling) != null) - this.refreshTiddler(e.getAttribute("tiddler"),e.getAttribute("template"),true); -} - -// Default tiddler onmouseover/out event handlers -Story.prototype.onTiddlerMouseOver = function(e) -{ - if(window.addClass instanceof Function) - addClass(this,"selected"); -} - -Story.prototype.onTiddlerMouseOut = function(e) -{ - if(window.removeClass instanceof Function) - removeClass(this,"selected"); -} - -// Default tiddler ondblclick event handler -Story.prototype.onTiddlerDblClick = function(e) -{ - if(!e) var e = window.event; - var theTarget = resolveTarget(e); - if(theTarget && theTarget.nodeName.toLowerCase() != "input" && theTarget.nodeName.toLowerCase() != "textarea") - { - if(document.selection && document.selection.empty) - document.selection.empty(); - config.macros.toolbar.invokeCommand(this,"defaultCommand",e); - e.cancelBubble = true; - if (e.stopPropagation) e.stopPropagation(); - return true; - } - else - return false; -} - -Story.prototype.onTiddlerKeyPress = function(e) -{ - if(!e) var e = window.event; - clearMessage(); - var consume = false; - var title = this.getAttribute("tiddler"); - var target = resolveTarget(e); - switch(e.keyCode) - { - case 9: // Tab - if(config.options.chkInsertTabs && target.tagName.toLowerCase() == "textarea") - { - replaceSelection(target,String.fromCharCode(9)); - consume = true; - } - if(config.isOpera) - { - target.onblur = function() - { - this.focus(); - this.onblur = null; - } - } - break; - case 13: // Ctrl-Enter - case 10: // Ctrl-Enter on IE PC - case 77: // Ctrl-Enter is "M" on some platforms - if(e.ctrlKey) - { - blurElement(this); - config.macros.toolbar.invokeCommand(this,"defaultCommand",e); - consume = true; - } - break; - case 27: // Escape - blurElement(this); - config.macros.toolbar.invokeCommand(this,"cancelCommand",e); - consume = true; - break; - } - e.cancelBubble = consume; - if(consume) - { - if(e.stopPropagation) e.stopPropagation(); // Stop Propagation - e.returnValue = true; // Cancel The Event in IE - if(e.preventDefault ) e.preventDefault(); // Cancel The Event in Moz - } - return(!consume); -}; - -// Returns the specified field (input or textarea element) in a tiddler, otherwise the first edit field it finds -// or null if it found no edit field at all -Story.prototype.getTiddlerField = function(title,field) -{ - var tiddlerElem = document.getElementById(this.idPrefix + title); - var e = null; - if(tiddlerElem != null) - { - var children = tiddlerElem.getElementsByTagName("*"); - for (var t=0; t<children.length; t++) - { - var c = children[t]; - if(c.tagName.toLowerCase() == "input" || c.tagName.toLowerCase() == "textarea") - { - if(!e) - e = c; - if(c.getAttribute("edit") == field) - e = c; - } - } - } - return e; -} - -// Focus a specified tiddler. Attempts to focus the specified field, otherwise the first edit field it finds -Story.prototype.focusTiddler = function(title,field) -{ - var e = this.getTiddlerField(title,field); - if(e) - { - e.focus(); - e.select(); - } -} - -// Ensures that a specified tiddler does not have the focus -Story.prototype.blurTiddler = function(title) -{ - var tiddlerElem = document.getElementById(this.idPrefix + title); - if(tiddlerElem != null && tiddlerElem.focus && tiddlerElem.blur) - { - tiddlerElem.focus(); - tiddlerElem.blur(); - } -} - -// Adds a specified value to the edit controls (if any) of a particular -// array-formatted field of a particular tiddler (eg "tags") -// title - name of tiddler -// tag - value of field, without any [[brackets]] -// mode - +1 to add the tag, -1 to remove it, 0 to toggle it -// field - name of field (eg "tags") -Story.prototype.setTiddlerField = function(title,tag,mode,field) -{ - var c = story.getTiddlerField(title,field); - - var tags = c.value.readBracketedList(); - tags.setItem(tag,mode); - c.value = String.encodeTiddlyLinkList(tags); -} - -// The same as setTiddlerField but preset to the "tags" field -Story.prototype.setTiddlerTag = function(title,tag,mode) -{ - Story.prototype.setTiddlerField(title,tag,mode,"tags"); -} - -// Close a specified tiddler -// title - name of tiddler to close -// animate - whether to perform animations -// slowly - whether to perform animations in slomo -Story.prototype.closeTiddler = function(title,animate,slowly) -{ - var tiddlerElem = document.getElementById(this.idPrefix + title); - if(tiddlerElem != null) - { - clearMessage(); - this.scrubTiddler(tiddlerElem); - if(anim && config.options.chkAnimate && animate) - anim.startAnimating(new Slider(tiddlerElem,false,slowly,"all")); - else - tiddlerElem.parentNode.removeChild(tiddlerElem); - } -} - -// Scrub IDs from a tiddler. This is so that the 'ghost' of a tiddler while it is being closed -// does not interfere with things -// tiddler - reference to the tiddler element -Story.prototype.scrubTiddler = function(tiddlerElem) -{ - tiddlerElem.id = null; -} - -// Set the 'dirty' flag of a tiddler -// title - title of tiddler to change -// dirty - new boolean status of flag -Story.prototype.setDirty = function(title,dirty) -{ - var tiddlerElem = document.getElementById(this.idPrefix + title); - if(tiddlerElem != null) - tiddlerElem.setAttribute("dirty",dirty ? "true" : "false"); -} - -// Is a particular tiddler dirty (with unsaved changes)? -Story.prototype.isDirty = function(title) -{ - var tiddlerElem = document.getElementById(this.idPrefix + title); - if(tiddlerElem != null) - return tiddlerElem.getAttribute("dirty") == "true"; - return null; -} - -// Determine whether any open tiddler are dirty -Story.prototype.areAnyDirty = function() -{ - var r = false; - this.forEachTiddler(function(title,element) { - if(this.isDirty(title)) - r = true; - }); - return r; -} - -// Close all tiddlers in the story -Story.prototype.closeAllTiddlers = function(exclude) -{ - clearMessage(); - this.forEachTiddler(function(title,element) { - if((title != exclude) && element.getAttribute("dirty") != "true") - this.closeTiddler(title); - }); - window.scrollTo(0,0); -} - -// Check if there are any tiddlers in the story -Story.prototype.isEmpty = function() -{ - var place = document.getElementById(this.container); - return(place && place.firstChild == null); -} - -// Perform a search and display the result -// text - text to search for -// useCaseSensitive - true for case sensitive matching -// useRegExp - true to interpret text as a RegExp -Story.prototype.search = function(text,useCaseSensitive,useRegExp) -{ - this.closeAllTiddlers(); - highlightHack = new RegExp(useRegExp ? text : text.escapeRegExp(),useCaseSensitive ? "mg" : "img"); - var matches = store.search(highlightHack,"title","excludeSearch"); - var titles = []; - for(var t=matches.length-1; t>=0; t--) - titles.push(matches[t].title); - this.displayTiddlers(null,titles); - highlightHack = null; - var q = useRegExp ? "/" : "'"; - if(matches.length > 0) - displayMessage(config.macros.search.successMsg.format([titles.length.toString(),q + text + q])); - else - displayMessage(config.macros.search.failureMsg.format([q + text + q])); -} - -// Determine if the specified element is within a tiddler in this story -// e - reference to an element -// returns: reference to a tiddler element or null if none -Story.prototype.findContainingTiddler = function(e) -{ - while(e && !hasClass(e,"tiddler")) - e = e.parentNode; - return(e); -} - -// Gather any saveable fields from a tiddler element -// e - reference to an element to scan recursively -// fields - object to contain gathered field values -Story.prototype.gatherSaveFields = function(e,fields) -{ - if(e && e.getAttribute) - { - var f = e.getAttribute("edit"); - if(f) - fields[f] = e.value.replace(/\r/mg,"");; - if(e.hasChildNodes()) - { - var c = e.childNodes; - for(var t=0; t<c.length; t++) - this.gatherSaveFields(c[t],fields) - } - } -} - -// Determine whether a tiddler has any edit fields, and if so if their values have been changed -// title - name of tiddler -Story.prototype.hasChanges = function(title) -{ - var e = document.getElementById(this.idPrefix + title); - if(e != null) - { - var fields = {}; - this.gatherSaveFields(e,fields); - var tiddler = store.fetchTiddler(title); - if (!tiddler) - return false; - for(var n in fields) - if (store.getValue(title,n) != fields[n]) - return true; - } - return false; -} - -// Save any open edit fields of a tiddler and updates the display as necessary -// title - name of tiddler -// minorUpdate - true if the modified date shouldn't be updated -// returns: title of saved tiddler, or null if not saved -Story.prototype.saveTiddler = function(title,minorUpdate) -{ - var tiddlerElem = document.getElementById(this.idPrefix + title); - if(tiddlerElem != null) - { - var fields = {}; - this.gatherSaveFields(tiddlerElem,fields); - var newTitle = fields.title ? fields.title : title; - if(store.tiddlerExists(newTitle) && newTitle != title) - { - if(confirm(config.messages.overwriteWarning.format([newTitle.toString()]))) - this.closeTiddler(newTitle,false,false); - else - return null; - } - tiddlerElem.id = this.idPrefix + newTitle; - tiddlerElem.setAttribute("tiddler",newTitle); - tiddlerElem.setAttribute("template",DEFAULT_VIEW_TEMPLATE); - tiddlerElem.setAttribute("dirty","false"); - if(config.options.chkForceMinorUpdate) - minorUpdate = !minorUpdate; - var newDate = new Date(); - store.saveTiddler(title,newTitle,fields.text,config.options.txtUserName,minorUpdate ? undefined : newDate,fields.tags); - for (var n in fields) - if (!TiddlyWiki.isStandardField(n)) - store.setValue(newTitle,n,fields[n]); - if(config.options.chkAutoSave) - saveChanges(); - return newTitle; - } - return null; -} - -Story.prototype.permaView = function() -{ - var links = []; - this.forEachTiddler(function(title,element) { - links.push(String.encodeTiddlyLink(title)); - }); - var t = encodeURIComponent(links.join(" ")); - if(t == "") - t = "#"; - if(window.location.hash != t) - window.location.hash = t; -} - -// --------------------------------------------------------------------------------- -// Message area -// --------------------------------------------------------------------------------- - -function getMessageDiv() -{ - var msgArea = document.getElementById("messageArea"); - if(!msgArea) - return null; - if(!msgArea.hasChildNodes()) - createTiddlyButton(createTiddlyElement(msgArea,"div",null,"messageToolbar"), - config.messages.messageClose.text, - config.messages.messageClose.tooltip, - clearMessage); - msgArea.style.display = "block"; - return createTiddlyElement(msgArea,"div"); -} - -function displayMessage(text,linkText) -{ - var e = getMessageDiv(); - if(!e) - { - alert(text); - return; - } - if(linkText) - { - var link = createTiddlyElement(e,"a",null,null,text); - link.href = linkText; - link.target = "_blank"; - } - else - e.appendChild(document.createTextNode(text)); -} - -function clearMessage() -{ - var msgArea = document.getElementById("messageArea"); - if(msgArea) - { - removeChildren(msgArea); - msgArea.style.display = "none"; - } - return false; -} - -// --------------------------------------------------------------------------------- -// Refresh mechanism -// --------------------------------------------------------------------------------- - -config.refreshers = { - link: function(e,changeList) - { - var title = e.getAttribute("tiddlyLink"); - refreshTiddlyLink(e,title); - return true; - }, - - tiddler: function(e,changeList) - { - var title = e.getAttribute("tiddler"); - var template = e.getAttribute("template"); - if(changeList && changeList.indexOf(title) != -1 && !story.isDirty(title)) - story.refreshTiddler(title,template,true); - else - refreshElements(e,changeList); - return true; - }, - - content: function(e,changeList) - { - var title = e.getAttribute("tiddler"); - var force = e.getAttribute("force"); - if(force != null || changeList == null || changeList.indexOf(title) != -1) - { - removeChildren(e); - wikify(store.getTiddlerText(title,title),e); - return true; - } - else - return false; - }, - - macro: function(e,changeList) - { - var macro = e.getAttribute("macroName"); - var params = e.getAttribute("params"); - if(macro) - macro = config.macros[macro]; - if(macro && macro.refresh) - macro.refresh(e,params); - return true; - } -}; - -function refreshElements(root,changeList) -{ - var nodes = root.childNodes; - for(var c=0; c<nodes.length; c++) - { - var e = nodes[c],type; - if(e.getAttribute) - type = e.getAttribute("refresh"); - else - type = null; - var refresher = config.refreshers[type]; - var refreshed = false; - if(refresher != undefined) - refreshed = refresher(e,changeList); - if(e.hasChildNodes() && !refreshed) - refreshElements(e,changeList); - } -} - -function applyHtmlMacros(root,tiddler) -{ - var e = root.firstChild; - while(e) - { - var nextChild = e.nextSibling; - if(e.getAttribute) - { - var macro = e.getAttribute("macro"); - if(macro) - { - var params = ""; - var p = macro.indexOf(" "); - if(p != -1) - { - params = macro.substr(p+1); - macro = macro.substr(0,p); - } - invokeMacro(e,macro,params,null,tiddler); - } - } - if(e.hasChildNodes()) - applyHtmlMacros(e,tiddler); - e = nextChild; - } -} - -function refreshPageTemplate(title) -{ - var stash = createTiddlyElement(document.body,"div"); - stash.style.display = "none"; - var display = document.getElementById("tiddlerDisplay"); - var nodes,t; - if(display) - { - nodes = display.childNodes; - for(t=nodes.length-1; t>=0; t--) - stash.appendChild(nodes[t]); - } - var wrapper = document.getElementById("contentWrapper"); - if(!title) - title = "PageTemplate"; - var html = store.getRecursiveTiddlerText(title,null,10); - wrapper.innerHTML = html; - applyHtmlMacros(wrapper); - refreshElements(wrapper); - display = document.getElementById("tiddlerDisplay"); - removeChildren(display); - if(!display) - display = createTiddlyElement(wrapper,"div","tiddlerDisplay"); - nodes = stash.childNodes; - for(t=nodes.length-1; t>=0; t--) - display.appendChild(nodes[t]); - stash.parentNode.removeChild(stash); -} - -function refreshDisplay(hint) -{ - var e = document.getElementById("contentWrapper"); - if(typeof hint == "string") - hint = [hint]; - refreshElements(e,hint); -} - -function refreshPageTitle() -{ - document.title = wikifyPlain("SiteTitle") + " - " + wikifyPlain("SiteSubtitle"); -} - -function refreshStyles(title) -{ - setStylesheet(title == null ? "" : store.getRecursiveTiddlerText(title,"",10),title); -} - -function refreshColorPalette(title) -{ - if(!startingUp) - refreshAll(); -} - -function refreshAll() -{ - refreshPageTemplate(); - refreshDisplay(); - refreshStyles("StyleSheetLayout"); - refreshStyles("StyleSheetColors"); - refreshStyles("StyleSheet"); - refreshStyles("StyleSheetPrint"); -} - -// --------------------------------------------------------------------------------- -// Options cookie stuff -// --------------------------------------------------------------------------------- - -function loadOptionsCookie() -{ - if(safeMode) - return; - var cookies = document.cookie.split(";"); - for(var c=0; c<cookies.length; c++) - { - var p = cookies[c].indexOf("="); - if(p != -1) - { - var name = cookies[c].substr(0,p).trim(); - var value = cookies[c].substr(p+1).trim(); - switch(name.substr(0,3)) - { - case "txt": - config.options[name] = unescape(value); - break; - case "chk": - config.options[name] = value == "true"; - break; - } - } - } -} - -function saveOptionCookie(name) -{ - if(safeMode) - return; - var c = name + "="; - switch(name.substr(0,3)) - { - case "txt": - c += escape(config.options[name].toString()); - break; - case "chk": - c += config.options[name] ? "true" : "false"; - break; - } - c += "; expires=Fri, 1 Jan 2038 12:00:00 UTC; path=/"; - document.cookie = c; -} - -// --------------------------------------------------------------------------------- -// Saving -// --------------------------------------------------------------------------------- - -var saveUsingSafari = false; - -var startSaveArea = '<div id="' + 'storeArea">'; // Split up into two so that indexOf() of this source doesn't find it -var endSaveArea = '</d' + 'iv>'; - -// If there are unsaved changes, force the user to confirm before exitting -function confirmExit() -{ - hadConfirmExit = true; - if((store && store.isDirty && store.isDirty()) || (story && story.areAnyDirty && story.areAnyDirty())) - return config.messages.confirmExit; -} - -// Give the user a chance to save changes before exitting -function checkUnsavedChanges() -{ - if(store && store.isDirty && store.isDirty() && window.hadConfirmExit === false) - { - if(confirm(config.messages.unsavedChangesWarning)) - saveChanges(); - } -} - -function updateMarkupBlock(s,blockName,tiddlerName) -{ - return s.replaceChunk( - "<!--%0-START-->".format([blockName]), - "<!--%0-END-->".format([blockName]), - "\n" + store.getRecursiveTiddlerText(tiddlerName,"") + "\n"); -} - -// Save this tiddlywiki with the pending changes -function saveChanges(onlyIfDirty) -{ - if(onlyIfDirty && !store.isDirty()) - return; - clearMessage(); - // Get the URL of the document - var originalPath = document.location.toString(); - // Check we were loaded from a file URL - if(originalPath.substr(0,5) != "file:") - { - alert(config.messages.notFileUrlError); - if(store.tiddlerExists(config.messages.saveInstructions)) - story.displayTiddler(null,config.messages.saveInstructions); - return; - } - var localPath = getLocalPath(originalPath); - // Load the original file - var original = loadFile(localPath); - if(original == null) - { - alert(config.messages.cantSaveError); - if(store.tiddlerExists(config.messages.saveInstructions)) - story.displayTiddler(null,config.messages.saveInstructions); - return; - } - // Locate the storeArea div's - var posOpeningDiv = original.indexOf(startSaveArea); - var limitClosingDiv = original.indexOf("<!--POST-BODY-START--"+">"); - var posClosingDiv = original.lastIndexOf(endSaveArea,limitClosingDiv == -1 ? original.length : limitClosingDiv); - if((posOpeningDiv == -1) || (posClosingDiv == -1)) - { - alert(config.messages.invalidFileError.format([localPath])); - return; - } - // Save the backup - if(config.options.chkSaveBackups) - { - var backupPath = getBackupPath(localPath); - var backup = saveFile(backupPath,original); - if(backup) - displayMessage(config.messages.backupSaved,"file://" + backupPath); - else - alert(config.messages.backupFailed); - } - // Save Rss - if(config.options.chkGenerateAnRssFeed) - { - var rssPath = localPath.substr(0,localPath.lastIndexOf(".")) + ".xml"; - var rssSave = saveFile(rssPath,convertUnicodeToUTF8(generateRss())); - if(rssSave) - displayMessage(config.messages.rssSaved,"file://" + rssPath); - else - alert(config.messages.rssFailed); - } - // Save empty template - if(config.options.chkSaveEmptyTemplate) - { - var emptyPath,p; - if((p = localPath.lastIndexOf("/")) != -1) - emptyPath = localPath.substr(0,p) + "/empty.html"; - else if((p = localPath.lastIndexOf("\\")) != -1) - emptyPath = localPath.substr(0,p) + "\\empty.html"; - else - emptyPath = localPath + ".empty.html"; - var empty = original.substr(0,posOpeningDiv + startSaveArea.length) + original.substr(posClosingDiv); - var emptySave = saveFile(emptyPath,empty); - if(emptySave) - displayMessage(config.messages.emptySaved,"file://" + emptyPath); - else - alert(config.messages.emptyFailed); - } - var save; - try - { - // Save new file - var revised = original.substr(0,posOpeningDiv + startSaveArea.length) + "\n" + - convertUnicodeToUTF8(store.allTiddlersAsHtml()) + "\n" + - original.substr(posClosingDiv); - var newSiteTitle = convertUnicodeToUTF8((wikifyPlain("SiteTitle") + " - " + wikifyPlain("SiteSubtitle")).htmlEncode()); - revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " "); - revised = updateMarkupBlock(revised,"PRE-HEAD","MarkupPreHead"); - revised = updateMarkupBlock(revised,"POST-HEAD","MarkupPostHead"); - revised = updateMarkupBlock(revised,"PRE-BODY","MarkupPreBody"); - revised = updateMarkupBlock(revised,"POST-BODY","MarkupPostBody"); - save = saveFile(localPath,revised); - } - catch (e) - { - showException(e); - } - if(save) - { - displayMessage(config.messages.mainSaved,"file://" + localPath); - store.setDirty(false); - } - else - alert(config.messages.mainFailed); -} - -function getLocalPath(originalPath) -{ - // Remove any location or query part of the URL - var argPos = originalPath.indexOf("?"); - if(argPos != -1) - originalPath = originalPath.substr(0,argPos); - var hashPos = originalPath.indexOf("#"); - if(hashPos != -1) - originalPath = originalPath.substr(0,hashPos); - // Convert file://localhost/ to file:/// - if(originalPath.indexOf("file://localhost/") == 0) - originalPath = "file://" + originalPath.substr(16); - // Convert to a native file format assuming - // "file:///x:/path/path/path..." - pc local file --> "x:\path\path\path..." - // "file://///server/share/path/path/path..." - FireFox pc network file --> "\\server\share\path\path\path..." - // "file:///path/path/path..." - mac/unix local file --> "/path/path/path..." - // "file://server/share/path/path/path..." - pc network file --> "\\server\share\path\path\path..." - var localPath; - if(originalPath.charAt(9) == ":") // pc local file - localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\\"); - else if(originalPath.indexOf("file://///") == 0) // FireFox pc network file - localPath = "\\\\" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\\"); - else if(originalPath.indexOf("file:///") == 0) // mac/unix local file - localPath = unescape(originalPath.substr(7)); - else if(originalPath.indexOf("file:/") == 0) // mac/unix local file - localPath = unescape(originalPath.substr(5)); - else // pc network file - localPath = "\\\\" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\\"); - return localPath; -} - -function getBackupPath(localPath) -{ - var backSlash = true; - var dirPathPos = localPath.lastIndexOf("\\"); - if(dirPathPos == -1) - { - dirPathPos = localPath.lastIndexOf("/"); - backSlash = false; - } - var backupFolder = config.options.txtBackupFolder; - if(!backupFolder || backupFolder == "") - backupFolder = "."; - var backupPath = localPath.substr(0,dirPathPos) + (backSlash ? "\\" : "/") + backupFolder + localPath.substr(dirPathPos); - backupPath = backupPath.substr(0,backupPath.lastIndexOf(".")) + "." + (new Date()).convertToYYYYMMDDHHMMSSMMM() + ".html"; - return backupPath; -} - -function generateRss() -{ - var s = []; - var d = new Date(); - var u = store.getTiddlerText("SiteUrl"); - // Assemble the header - s.push("<" + "?xml version=\"1.0\"?" + ">"); - s.push("<rss version=\"2.0\">"); - s.push("<channel>"); - s.push("<title" + ">" + wikifyPlain("SiteTitle").htmlEncode() + "</title" + ">"); - if(u) - s.push("<link>" + u.htmlEncode() + "</link>"); - s.push("<description>" + wikifyPlain("SiteSubtitle").htmlEncode() + "</description>"); - s.push("<language>en-us</language>"); - s.push("<copyright>Copyright " + d.getFullYear() + " " + config.options.txtUserName.htmlEncode() + "</copyright>"); - s.push("<pubDate>" + d.toGMTString() + "</pubDate>"); - s.push("<lastBuildDate>" + d.toGMTString() + "</lastBuildDate>"); - s.push("<docs>http://blogs.law.harvard.edu/tech/rss</docs>"); - s.push("<generator>TiddlyWiki " + version.major + "." + version.minor + "." + version.revision + "</generator>"); - // The body - var tiddlers = store.getTiddlers("modified","excludeLists"); - var n = config.numRssItems > tiddlers.length ? 0 : tiddlers.length-config.numRssItems; - for (var t=tiddlers.length-1; t>=n; t--) - s.push(tiddlers[t].saveToRss(u)); - // And footer - s.push("</channel>"); - s.push("</rss>"); - // Save it all - return s.join("\n"); -} - - -// UTF-8 encoding rules: -// 0x0000 - 0x007F: 0xxxxxxx -// 0x0080 - 0x07FF: 110xxxxx 10xxxxxx -// 0x0800 - 0xFFFF: 1110xxxx 10xxxxxx 10xxxxxx - -function convertUTF8ToUnicode(u) -{ - if(window.netscape == undefined) - return manualConvertUTF8ToUnicode(u); - else - return mozConvertUTF8ToUnicode(u); -} - -function manualConvertUTF8ToUnicode(utf) -{ - var uni = utf; - var src = 0; - var dst = 0; - var b1, b2, b3; - var c; - while(src < utf.length) - { - b1 = utf.charCodeAt(src++); - if(b1 < 0x80) - dst++; - else if(b1 < 0xE0) - { - b2 = utf.charCodeAt(src++); - c = String.fromCharCode(((b1 & 0x1F) << 6) | (b2 & 0x3F)); - uni = uni.substring(0,dst++).concat(c,utf.substr(src)); - } - else - { - b2 = utf.charCodeAt(src++); - b3 = utf.charCodeAt(src++); - c = String.fromCharCode(((b1 & 0xF) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F)); - uni = uni.substring(0,dst++).concat(c,utf.substr(src)); - } - } - return(uni); -} - -function mozConvertUTF8ToUnicode(u) -{ - try - { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); - converter.charset = "UTF-8"; - } - catch(e) - { - return manualConvertUTF8ToUnicode(u); - } // fallback - var s = converter.ConvertToUnicode(u); - var fin = converter.Finish(); - return (fin.length > 0) ? s+fin : s; -} - -function convertUnicodeToUTF8(s) -{ - if(window.netscape == undefined) - return manualConvertUnicodeToUTF8(s); - else - return mozConvertUnicodeToUTF8(s); -} - -function manualConvertUnicodeToUTF8(s) -{ - var re = /[^\u0000-\u007F]/g ; - return s.replace(re, function($0) {return("&#" + $0.charCodeAt(0).toString() + ";");}) -} - -function mozConvertUnicodeToUTF8(s) -{ - try - { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); - converter.charset = "UTF-8"; - } - catch(e) - { - return manualConvertUnicodeToUTF8(s); - } // fallback - var u = converter.ConvertFromUnicode(s); - var fin = converter.Finish(); - if(fin.length > 0) - return u + fin; - else - return u; -} - -function saveFile(fileUrl, content) -{ - var r = null; - if((r == null) || (r == false)) - r = mozillaSaveFile(fileUrl, content); - if((r == null) || (r == false)) - r = ieSaveFile(fileUrl, content); - if((r == null) || (r == false)) - r = javaSaveFile(fileUrl, content); - return(r); -} - -function loadFile(fileUrl) -{ - var r = null; - if((r == null) || (r == false)) - r = mozillaLoadFile(fileUrl); - if((r == null) || (r == false)) - r = ieLoadFile(fileUrl); - if((r == null) || (r == false)) - r = javaLoadFile(fileUrl); - return(r); -} - -// Returns null if it can't do it, false if there's an error, true if it saved OK -function ieSaveFile(filePath, content) -{ - try - { - var fso = new ActiveXObject("Scripting.FileSystemObject"); - } - catch(e) - { - //alert("Exception while attempting to save\n\n" + e.toString()); - return(null); - } - var file = fso.OpenTextFile(filePath,2,-1,0); - file.Write(content); - file.Close(); - return(true); -} - -// Returns null if it can't do it, false if there's an error, or a string of the content if successful -function ieLoadFile(filePath) -{ - try - { - var fso = new ActiveXObject("Scripting.FileSystemObject"); - var file = fso.OpenTextFile(filePath,1); - var content = file.ReadAll(); - file.Close(); - } - catch(e) - { - //alert("Exception while attempting to load\n\n" + e.toString()); - return(null); - } - return(content); -} - -// Returns null if it can't do it, false if there's an error, true if it saved OK -function mozillaSaveFile(filePath, content) -{ - if(window.Components) - try - { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); - file.initWithPath(filePath); - if (!file.exists()) - file.create(0, 0664); - var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream); - out.init(file, 0x20 | 0x02, 00004,null); - out.write(content, content.length); - out.flush(); - out.close(); - return(true); - } - catch(e) - { - //alert("Exception while attempting to save\n\n" + e); - return(false); - } - return(null); -} - -// Returns null if it can't do it, false if there's an error, or a string of the content if successful -function mozillaLoadFile(filePath) -{ - if(window.Components) - try - { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); - file.initWithPath(filePath); - if (!file.exists()) - return(null); - var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream); - inputStream.init(file, 0x01, 00004, null); - var sInputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream); - sInputStream.init(inputStream); - return(sInputStream.read(sInputStream.available())); - } - catch(e) - { - //alert("Exception while attempting to load\n\n" + e); - return(false); - } - return(null); -} - -function javaUrlToFilename(url) -{ - var f = "//localhost"; - if(url.indexOf(f) == 0) - return url.substring(f.length); - var i = url.indexOf(":"); - if(i > 0) - return url.substring(i-1); - return url; -} - -function javaSaveFile(filePath, content) -{ - try - { - if(document.applets["TiddlySaver"]) - return document.applets["TiddlySaver"].saveFile(javaUrlToFilename(filePath),"UTF-8",content); - } - catch(e) - { - } - try - { - var s = new java.io.PrintStream(new java.io.FileOutputStream(javaUrlToFilename(filePath))); - s.print(content); - s.close(); - } - catch(e) - { - return null; - } - return true; -} - -function javaLoadFile(filePath) -{ - try - { - if(document.applets["TiddlySaver"]) - return String(document.applets["TiddlySaver"].loadFile(javaUrlToFilename(filePath),"UTF-8")); - } - catch(e) - { - } - var content = []; - try - { - var r = new java.io.BufferedReader(new java.io.FileReader(javaUrlToFilename(filePath))); - var line; - while ((line = r.readLine()) != null) - content.push(new String(line)); - r.close(); - } - catch(e) - { - return null; - } - return content.join("\n"); -} - - -// --------------------------------------------------------------------------------- -// Remote HTTP requests -// --------------------------------------------------------------------------------- - -// Load a file over http -// url - the source url -// callback - function to call when there's a response -// params - parameter object that gets passed to the callback for storing it's state -// Return value is the underlying XMLHttpRequest object, or 'null' if there was an error -// Callback function is called like this: -// callback(status,params,responseText,xhr) -// status - true if OK, false if error -// params - the parameter object provided to loadRemoteFile() -// responseText - the text of the file -// xhr - the underlying XMLHttpRequest object -function loadRemoteFile(url,callback,params) -{ - // Get an xhr object - var x; - try - { - x = new XMLHttpRequest(); // Modern - } - catch(e) - { - try - { - x = new ActiveXObject("Msxml2.XMLHTTP"); // IE 6 - } - catch (e) - { - return null; - } - } - // Install callback - x.onreadystatechange = function() - { - if (x.readyState == 4) - { - if ((x.status == 0 || x.status == 200) && callback) - { - callback(true,params,x.responseText,url,x); - } - else - callback(false,params,null,url,x); - } - } - // Send request - if(window.netscape && window.netscape.security && document.location.protocol.indexOf("http") == -1) - window.netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); - try - { - url = url + (url.indexOf("?") < 0 ? "?" : "&") + "nocache=" + Math.random(); - x.open("GET",url,true); - if (x.overrideMimeType) - x.overrideMimeType("text/html"); - x.send(null); - } - catch (e) - { - alert("Error in send " + e); - return null; - } - return x; -} -// --------------------------------------------------------------------------------- -// TiddlyWiki-specific utility functions -// --------------------------------------------------------------------------------- - -function createTiddlyButton(theParent,theText,theTooltip,theAction,theClass,theId,theAccessKey) -{ - var theButton = document.createElement("a"); - if(theAction) - { - theButton.onclick = theAction; - theButton.setAttribute("href","javascript:;"); - } - if(theTooltip) - theButton.setAttribute("title",theTooltip); - if(theText) - theButton.appendChild(document.createTextNode(theText)); - if(theClass) - theButton.className = theClass; - else - theButton.className = "button"; - if(theId) - theButton.id = theId; - if(theParent) - theParent.appendChild(theButton); - if(theAccessKey) - theButton.setAttribute("accessKey",theAccessKey); - return(theButton); -} - -function createTiddlyLink(place,title,includeText,theClass,isStatic) -{ - var text = includeText ? title : null; - var i = getTiddlyLinkInfo(title,theClass) - var btn; - if(isStatic) - btn = createExternalLink(place,"#" + title); - else - btn = createTiddlyButton(place,text,i.subTitle,onClickTiddlerLink,i.classes); - btn.setAttribute("refresh","link"); - btn.setAttribute("tiddlyLink",title); - return(btn); -} - -function refreshTiddlyLink(e,title) -{ - var i = getTiddlyLinkInfo(title,e.className); - e.className = i.classes; - e.title = i.subTitle; -} - -function getTiddlyLinkInfo(title,currClasses) -{ - var classes = currClasses ? currClasses.split(" ") : []; - classes.pushUnique("tiddlyLink"); - var tiddler = store.fetchTiddler(title); - var subTitle; - if(tiddler) - { - subTitle = tiddler.getSubtitle(); - classes.pushUnique("tiddlyLinkExisting"); - classes.remove("tiddlyLinkNonExisting"); - classes.remove("shadow"); - } - else - { - classes.remove("tiddlyLinkExisting"); - classes.pushUnique("tiddlyLinkNonExisting"); - if(store.isShadowTiddler(title)) - { - subTitle = config.messages.shadowedTiddlerToolTip.format([title]); - classes.pushUnique("shadow"); - } - else - { - subTitle = config.messages.undefinedTiddlerToolTip.format([title]); - classes.remove("shadow"); - } - } - return {classes: classes.join(" "), subTitle: subTitle}; -} - -function createExternalLink(place,url) -{ - var theLink = document.createElement("a"); - theLink.className = "externalLink"; - theLink.href = url; - theLink.title = config.messages.externalLinkTooltip.format([url]); - if(config.options.chkOpenInNewWindow) - theLink.target = "_blank"; - place.appendChild(theLink); - return(theLink); -} - -// Event handler for clicking on a tiddly link -function onClickTiddlerLink(e) -{ - if (!e) var e = window.event; - var theTarget = resolveTarget(e); - var theLink = theTarget; - var title = null; - do { - title = theLink.getAttribute("tiddlyLink"); - theLink = theLink.parentNode; - } while(title == null && theLink != null); - if(title) - { - var toggling = e.metaKey || e.ctrlKey; - if(config.options.chkToggleLinks) - toggling = !toggling; - var opening; - if(toggling && document.getElementById("tiddler" + title)) - story.closeTiddler(title,true,e.shiftKey || e.altKey); - else - story.displayTiddler(theTarget,title,null,true,e.shiftKey || e.altKey); - } - clearMessage(); - return(false); -} - -// Create a button for a tag with a popup listing all the tiddlers that it tags -function createTagButton(place,tag,excludeTiddler) -{ - var theTag = createTiddlyButton(place,tag,config.views.wikified.tag.tooltip.format([tag]),onClickTag); - theTag.setAttribute("tag",tag); - if(excludeTiddler) - theTag.setAttribute("tiddler",excludeTiddler); - return(theTag); -} - -// Event handler for clicking on a tiddler tag -function onClickTag(e) -{ - if (!e) var e = window.event; - var theTarget = resolveTarget(e); - var popup = Popup.create(this); - var tag = this.getAttribute("tag"); - var title = this.getAttribute("tiddler"); - if(popup && tag) - { - var tagged = store.getTaggedTiddlers(tag); - var titles = []; - var li,r; - for(r=0;r<tagged.length;r++) - if(tagged[r].title != title) - titles.push(tagged[r].title); - var lingo = config.views.wikified.tag; - if(titles.length > 0) - { - var openAll = createTiddlyButton(createTiddlyElement(popup,"li"),lingo.openAllText.format([tag]),lingo.openAllTooltip,onClickTagOpenAll); - openAll.setAttribute("tag",tag); - createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div"); - for(r=0; r<titles.length; r++) - { - createTiddlyLink(createTiddlyElement(popup,"li"),titles[r],true); - } - } - else - createTiddlyText(createTiddlyElement(popup,"li",null,"disabled"),lingo.popupNone.format([tag])); - createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div"); - var h = createTiddlyLink(createTiddlyElement(popup,"li"),tag,false); - createTiddlyText(h,lingo.openTag.format([tag])); - } - Popup.show(popup,false); - e.cancelBubble = true; - if (e.stopPropagation) e.stopPropagation(); - return(false); -} - -// Event handler for 'open all' on a tiddler popup -function onClickTagOpenAll(e) -{ - if (!e) var e = window.event; - var tag = this.getAttribute("tag"); - var tagged = store.getTaggedTiddlers(tag); - var titles = []; - for(var t=0; t<tagged.length; t++) - titles.push(tagged[t].title); - story.displayTiddlers(this,titles); - return(false); -} - -function onClickError(e) -{ - if (!e) var e = window.event; - var popup = Popup.create(this); - var lines = this.getAttribute("errorText").split("\n"); - for(var t=0; t<lines.length; t++) - createTiddlyElement(popup,"li",null,null,lines[t]); - Popup.show(popup,false); - e.cancelBubble = true; - if (e.stopPropagation) e.stopPropagation(); - return false; -} - -function createTiddlyDropDown(place,onchange,options) -{ - var sel = createTiddlyElement(place,"select"); - sel.onchange = onchange; - for(var t=0; t<options.length; t++) - { - var e = createTiddlyElement(sel,"option",null,null,options[t].caption); - e.value = options[t].name; - } -} - -function createTiddlyError(place,title,text) -{ - var btn = createTiddlyButton(place,title,null,onClickError,"errorButton"); - if (text) btn.setAttribute("errorText",text); -} - -function merge(dst,src,preserveExisting) -{ - for (p in src) - if (!preserveExisting || dst[p] === undefined) - dst[p] = src[p]; - return dst; -} - -// Returns a string containing the description of an exception, optionally prepended by a message -function exceptionText(e, message) -{ - var s = e.description ? e.description : e.toString(); - return message ? "%0:\n%1".format([message, s]) : s; -} - -// Displays an alert of an exception description with optional message -function showException(e, message) -{ - alert(exceptionText(e, message)); -} - -// --------------------------------------------------------------------------------- -// Animation engine -// --------------------------------------------------------------------------------- - -function Animator() -{ - this.running = 0; // Incremented at start of each animation, decremented afterwards. If zero, the interval timer is disabled - this.timerID = 0; // ID of the timer used for animating - this.animations = []; // List of animations in progress - return this; -} - -// Start animation engine -Animator.prototype.startAnimating = function() // Variable number of arguments -{ - for(var t=0; t<arguments.length; t++) - this.animations.push(arguments[t]); - if(this.running == 0) - { - var me = this; - this.timerID = window.setInterval(function() {me.doAnimate(me);},5); - } - this.running += arguments.length; -} - -// Perform an animation engine tick, calling each of the known animation modules -Animator.prototype.doAnimate = function(me) -{ - var a = 0; - while(a < me.animations.length) - { - var animation = me.animations[a]; - if(animation.tick()) - a++; - else - { - me.animations.splice(a,1); - if(--me.running == 0) - window.clearInterval(me.timerID); - } - } -} - -// Map a 0..1 value to 0..1, but slow down at the start and end -Animator.slowInSlowOut = function(progress) -{ - return(1-((Math.cos(progress * Math.PI)+1)/2)); -} - -// --------------------------------------------------------------------------------- -// Cascade animation -// --------------------------------------------------------------------------------- - -function Cascade(text,startElement,targetElement,slowly) -{ - var winWidth = findWindowWidth(); - var winHeight = findWindowHeight(); - this.elements = []; - this.startElement = startElement; - this.startLeft = findPosX(this.startElement); - this.startTop = findPosY(this.startElement); - this.startWidth = Math.min(this.startElement.offsetWidth,winWidth); - this.startHeight = Math.min(this.startElement.offsetHeight,winHeight); - this.targetElement = targetElement; - targetElement.style.position = "relative"; - targetElement.style.zIndex = 2; - this.targetLeft = findPosX(this.targetElement); - this.targetTop = findPosY(this.targetElement); - this.targetWidth = Math.min(this.targetElement.offsetWidth,winWidth); - this.targetHeight = Math.min(this.targetElement.offsetHeight,winHeight); - this.progress = -1; - this.steps = slowly ? config.cascadeSlow : config.cascadeFast; - this.text = text; - this.tick(); - return this; -} - -Cascade.prototype.tick = function() -{ - this.progress++; - if(this.progress >= this.steps) - { - while(this.elements.length > 0) - this.removeTail(); - this.targetElement.style.position = "static"; - this.targetElement.style.zIndex = ""; - return false; - } - else - { - if(this.elements.length > 0 && this.progress > config.cascadeDepth) - this.removeTail(); - if(this.progress < (this.steps - config.cascadeDepth)) - { - var f = Animator.slowInSlowOut(this.progress/(this.steps - config.cascadeDepth - 1)); - var e = createTiddlyElement(document.body,"div",null,"cascade",this.text); - e.style.zIndex = 1; - e.style.left = this.startLeft + (this.targetLeft-this.startLeft) * f + "px"; - e.style.top = this.startTop + (this.targetTop-this.startTop) * f + "px"; - e.style.width = this.startWidth + (this.targetWidth-this.startWidth) * f + "px"; - e.style.height = this.startHeight + (this.targetHeight-this.startHeight) * f + "px"; - e.style.display = "block"; - this.elements.push(e); - } - return true; - } -} - -Cascade.prototype.removeTail = function() -{ - var e = this.elements[0]; - e.parentNode.removeChild(e); - this.elements.shift(); -} - -// --------------------------------------------------------------------------------- -// Scroller animation -// --------------------------------------------------------------------------------- - -function Scroller(targetElement,slowly) -{ - this.targetElement = targetElement; - this.startScroll = findScrollY(); - this.targetScroll = ensureVisible(targetElement); - this.progress = 0; - this.step = slowly ? config.animSlow : config.animFast; - return this; -} - -Scroller.prototype.tick = function() -{ - this.progress += this.step; - if(this.progress > 1) - { - window.scrollTo(0,this.targetScroll); - return false; - } - else - { - var f = Animator.slowInSlowOut(this.progress); - window.scrollTo(0,this.startScroll + (this.targetScroll-this.startScroll) * f); - return true; - } -} - -// --------------------------------------------------------------------------------- -// Slider animation -// --------------------------------------------------------------------------------- - -// deleteMode - "none", "all" [delete target element and it's children], [only] "children" [but not the target element] -function Slider(element,opening,slowly,deleteMode) -{ - this.element = element; - element.style.display = "block"; - this.deleteMode = deleteMode; - this.element.style.height = "auto"; - this.realHeight = element.offsetHeight; - this.opening = opening; - this.step = slowly ? config.animSlow : config.animFast; - if(opening) - { - this.progress = 0; - element.style.height = "0px"; - element.style.display = "block"; - } - else - { - this.progress = 1; - this.step = -this.step; - } - element.style.overflow = "hidden"; - return this; -} - -Slider.prototype.stop = function() -{ - if(this.opening) - { - this.element.style.height = "auto"; - this.element.style.opacity = 1; - this.element.style.filter = "alpha(opacity:100)"; - } - else - { - switch(this.deleteMode) - { - case "none": - this.element.style.display = "none"; - break; - case "all": - this.element.parentNode.removeChild(this.element); - break; - case "children": - removeChildren(this.element); - break; - } - } -} - -Slider.prototype.tick = function() -{ - this.progress += this.step; - if(this.progress < 0 || this.progress > 1) - { - this.stop(); - return false; - } - else - { - var f = Animator.slowInSlowOut(this.progress); - var h = this.realHeight * f; - this.element.style.height = h + "px"; - this.element.style.opacity = f; - this.element.style.filter = "alpha(opacity:" + f * 100 +")"; - return true; - } -} - -// --------------------------------------------------------------------------------- -// Popup menu -// --------------------------------------------------------------------------------- - -var Popup = { - stack: [] // Array of objects with members root: and popup: - }; - -Popup.create = function(root) -{ - Popup.remove(); - var popup = createTiddlyElement(document.body,"ol","popup","popup"); - Popup.stack.push({root: root, popup: popup}); - return popup; -} - -Popup.onDocumentClick = function(e) -{ - if (!e) var e = window.event; - var target = resolveTarget(e); - if(e.eventPhase == undefined) - Popup.remove(); - else if(e.eventPhase == Event.BUBBLING_PHASE || e.eventPhase == Event.AT_TARGET) - Popup.remove(); - return true; -} - -Popup.show = function(unused,slowly) -{ - var curr = Popup.stack[Popup.stack.length-1]; - var rootLeft = findPosX(curr.root); - var rootTop = findPosY(curr.root); - var rootHeight = curr.root.offsetHeight; - var popupLeft = rootLeft; - var popupTop = rootTop + rootHeight; - var popupWidth = curr.popup.offsetWidth; - var winWidth = findWindowWidth(); - if(popupLeft + popupWidth > winWidth) - popupLeft = winWidth - popupWidth; - curr.popup.style.left = popupLeft + "px"; - curr.popup.style.top = popupTop + "px"; - curr.popup.style.display = "block"; - addClass(curr.root,"highlight"); - if(anim && config.options.chkAnimate) - anim.startAnimating(new Scroller(curr.popup,slowly)); - else - window.scrollTo(0,ensureVisible(curr.popup)); -} - -Popup.remove = function() -{ - if(Popup.stack.length > 0) - { - Popup.removeFrom(0); - } -} - -Popup.removeFrom = function(from) -{ - for(var t=Popup.stack.length-1; t>=from; t--) - { - var p = Popup.stack[t]; - removeClass(p.root,"highlight"); - p.popup.parentNode.removeChild(p.popup); - } - Popup.stack = Popup.stack.slice(0,from); -} - -// --------------------------------------------------------------------------------- -// ListView gadget -// --------------------------------------------------------------------------------- - -var ListView = {}; - -// Create a listview -// place - where in the DOM tree to insert the listview -// listObject - array of objects to be included in the listview -// listTemplate - template for the listview -// callback - callback for a command being selected -// className - optional classname for the <table> element -ListView.create = function(place,listObject,listTemplate,callback,className) -{ - var table = createTiddlyElement(place,"table",null,className ? className : "listView"); - var thead = createTiddlyElement(table,"thead"); - var r = createTiddlyElement(thead,"tr"); - for(var t=0; t<listTemplate.columns.length; t++) - { - var columnTemplate = listTemplate.columns[t]; - var c = createTiddlyElement(r,"th"); - var colType = ListView.columnTypes[columnTemplate.type]; - if(colType && colType.createHeader) - colType.createHeader(c,columnTemplate,t); - } - var tbody = createTiddlyElement(table,"tbody"); - for(var rc=0; rc<listObject.length; rc++) - { - rowObject = listObject[rc]; - r = createTiddlyElement(tbody,"tr"); - for(var c=0; c<listTemplate.rowClasses.length; c++) - { - if(rowObject[listTemplate.rowClasses[c].field]) - addClass(r,listTemplate.rowClasses[c].className); - } - rowObject.rowElement = rowObject; - rowObject.colElements = {}; - for(var cc=0; cc<listTemplate.columns.length; cc++) - { - var c = createTiddlyElement(r,"td"); - var columnTemplate = listTemplate.columns[cc]; - var field = columnTemplate.field; - var colType = ListView.columnTypes[columnTemplate.type]; - if(colType && colType.createItem) - colType.createItem(c,rowObject,field,columnTemplate,cc,rc); - rowObject.colElements[field] = c; - } - } - if(callback && listTemplate.actions) - createTiddlyDropDown(place,ListView.getCommandHandler(callback),listTemplate.actions); - if(callback && listTemplate.buttons) - { - for(t=0; t<listTemplate.buttons.length; t++) - { - var a = listTemplate.buttons[t]; - if(a && a.name != "") - createTiddlyButton(place,a.caption,null,ListView.getCommandHandler(callback,a.name,a.allowEmptySelection)); - } - } - return table; -} - -ListView.getCommandHandler = function(callback,name,allowEmptySelection) -{ - return function(e) - { - var view = findRelated(this,"TABLE",null,"previousSibling"); - var tiddlers = []; - ListView.forEachSelector(view,function(e,rowName) { - if(e.checked) - tiddlers.push(rowName); - }); - if(tiddlers.length == 0 && !allowEmptySelection) - alert(config.messages.nothingSelected); - else - { - if(this.nodeName.toLowerCase() == "select") - { - callback(view,this.value,tiddlers); - this.selectedIndex = 0; - } - else - callback(view,name,tiddlers); - } - }; -} - -// Invoke a callback for each selector checkbox in the listview -// view - <table> element of listView -// callback(checkboxElement,rowName) -// where -// checkboxElement - DOM element of checkbox -// rowName - name of this row as assigned by the column template -// result: true if at least one selector was checked -ListView.forEachSelector = function(view,callback) -{ - var checkboxes = view.getElementsByTagName("input"); - var hadOne = false; - for(var t=0; t<checkboxes.length; t++) - { - var cb = checkboxes[t]; - if(cb.getAttribute("type") == "checkbox") - { - var rn = cb.getAttribute("rowName"); - if(rn) - { - callback(cb,rn); - hadOne = true; - } - } - } - return hadOne; -} - -ListView.columnTypes = {}; - -ListView.columnTypes.String = { - createHeader: function(place,columnTemplate,col) - { - createTiddlyText(place,columnTemplate.title); - }, - createItem: function(place,listObject,field,columnTemplate,col,row) - { - var v = listObject[field]; - if(v != undefined) - createTiddlyText(place,v); - } -}; - -ListView.columnTypes.Date = { - createHeader: ListView.columnTypes.String.createHeader, - createItem: function(place,listObject,field,columnTemplate,col,row) - { - var v = listObject[field]; - if(v != undefined) - createTiddlyText(place,v.formatString(columnTemplate.dateFormat)); - } -}; - -ListView.columnTypes.StringList = { - createHeader: ListView.columnTypes.String.createHeader, - createItem: function(place,listObject,field,columnTemplate,col,row) - { - var v = listObject[field]; - if(v != undefined) - { - for(var t=0; t<v.length; t++) - { - createTiddlyText(place,v[t]); - createTiddlyElement(place,"br"); - } - } - } -}; - -ListView.columnTypes.Selector = { - createHeader: function(place,columnTemplate,col) - { - createTiddlyCheckbox(place,null,false,this.onHeaderChange); - }, - createItem: function(place,listObject,field,columnTemplate,col,row) - { - var e = createTiddlyCheckbox(place,null,listObject[field],null); - e.setAttribute("rowName",listObject[columnTemplate.rowName]); - }, - onHeaderChange: function(e) - { - var state = this.checked; - var view = findRelated(this,"TABLE"); - if(!view) - return; - ListView.forEachSelector(view,function(e,rowName) { - e.checked = state; - }); - } -}; - -ListView.columnTypes.Tags = { - createHeader: ListView.columnTypes.String.createHeader, - createItem: function(place,listObject,field,columnTemplate,col,row) - { - var tags = listObject[field]; - createTiddlyText(place,String.encodeTiddlyLinkList(tags)); - } -}; - -ListView.columnTypes.Boolean = { - createHeader: ListView.columnTypes.String.createHeader, - createItem: function(place,listObject,field,columnTemplate,col,row) - { - if(listObject[field] == true) - createTiddlyText(place,columnTemplate.trueText); - if(listObject[field] == false) - createTiddlyText(place,columnTemplate.falseText); - } -}; - -ListView.columnTypes.TagCheckbox = { - createHeader: ListView.columnTypes.String.createHeader, - createItem: function(place,listObject,field,columnTemplate,col,row) - { - var e = createTiddlyCheckbox(place,null,listObject[field],this.onChange); - e.setAttribute("tiddler",listObject.title); - e.setAttribute("tag",columnTemplate.tag); - }, - onChange : function(e) - { - var tag = this.getAttribute("tag"); - var tiddler = this.getAttribute("tiddler"); - store.setTiddlerTag(tiddler,this.checked,tag); - } -}; - -ListView.columnTypes.TiddlerLink = { - createHeader: ListView.columnTypes.String.createHeader, - createItem: function(place,listObject,field,columnTemplate,col,row) - { - var v = listObject[field]; - if(v != undefined) - { - var link = createTiddlyLink(place,listObject[columnTemplate.tiddlerLink],false,null); - createTiddlyText(link,listObject[field]); - } - } -}; -// --------------------------------------------------------------------------------- -// Augmented methods for the JavaScript Number(), Array(), String() and Date() objects -// --------------------------------------------------------------------------------- - -// Clamp a number to a range -Number.prototype.clamp = function(min,max) -{ - var c = this; - if(c < min) - c = min; - if(c > max) - c = max; - return c; -} - -// Add indexOf function if browser does not support it -if(!Array.indexOf) { -Array.prototype.indexOf = function(item,from) -{ - if(!from) - from = 0; - for(var i=from; i<this.length; i++) - if(this[i] === item) - return i; - return -1; -}} - -// Find an entry in a given field of the members of an array -Array.prototype.findByField = function(field,value) -{ - for(var t=0; t<this.length; t++) - if(this[t][field] == value) - return t; - return null; -} - -// Return whether an entry exists in an array -Array.prototype.contains = function(item) -{ - return this.indexOf(item) != -1; -}; - -// Adds, removes or toggles a particular value within an array -// value - value to add -// mode - +1 to add value, -1 to remove value, 0 to toggle it -Array.prototype.setItem = function(value,mode) -{ - var p = this.indexOf(value); - if(mode == 0) - mode = (p == -1) ? +1 : -1; - if(mode == +1) - { - if(p == -1) - this.push(value); - } - else if(mode == -1) - { - if(p != -1) - this.splice(p,1); - } -} - -// Return whether one of a list of values exists in an array -Array.prototype.containsAny = function(items) -{ - for(var i=0; i<items.length; i++) - if (this.indexOf(items[i]) != -1) - return true; - return false; -}; - -// Return whether all of a list of values exists in an array -Array.prototype.containsAll = function(items) -{ - for (var i = 0; i<items.length; i++) - if (this.indexOf(items[i]) == -1) - return false; - return true; -}; - -// Push a new value into an array only if it is not already present in the array. If the optional unique parameter is false, it reverts to a normal push -Array.prototype.pushUnique = function(item,unique) -{ - if(unique != undefined && unique == false) - this.push(item); - else - { - if(this.indexOf(item) == -1) - this.push(item); - } -} - -Array.prototype.remove = function(item) -{ - var p = this.indexOf(item); - if(p != -1) - this.splice(p,1); -} - -// Get characters from the right end of a string -String.prototype.right = function(n) -{ - if(n < this.length) - return this.slice(this.length-n); - else - return this; -} - -// Trim whitespace from both ends of a string -String.prototype.trim = function() -{ - return this.replace(/^\s*|\s*$/g,""); -} - -// Convert a string from a CSS style property name to a JavaScript style name ("background-color" -> "backgroundColor") -String.prototype.unDash = function() -{ - var s = this.split("-"); - if(s.length > 1) - for(var t=1; t<s.length; t++) - s[t] = s[t].substr(0,1).toUpperCase() + s[t].substr(1); - return s.join(""); -} - -// Substitute substrings from an array into a format string that includes '%1'-type specifiers -String.prototype.format = function(substrings) -{ - var subRegExp = /(?:%(\d+))/mg; - var currPos = 0; - var r = []; - do { - var match = subRegExp.exec(this); - if(match && match[1]) - { - if(match.index > currPos) - r.push(this.substring(currPos,match.index)); - r.push(substrings[parseInt(match[1])]); - currPos = subRegExp.lastIndex; - } - } while(match); - if(currPos < this.length) - r.push(this.substring(currPos,this.length)); - return r.join(""); -} - -// Escape any special RegExp characters with that character preceded by a backslash -String.prototype.escapeRegExp = function() -{ - var s = "\\^$*+?()=!|,{}[]."; - var c = this; - for(var t=0; t<s.length; t++) - c = c.replace(new RegExp("\\" + s.substr(t,1),"g"),"\\" + s.substr(t,1)); - return c; -} - -// Convert "\" to "\s", newlines to "\n" (and remove carriage returns) -String.prototype.escapeLineBreaks = function() -{ - return this.replace(/\\/mg,"\\s").replace(/\n/mg,"\\n").replace(/\r/mg,""); -} - -// Convert "\n" to newlines, "\b" to " ", "\s" to "\" (and remove carriage returns) -String.prototype.unescapeLineBreaks = function() -{ - return this.replace(/\\n/mg,"\n").replace(/\\b/mg," ").replace(/\\s/mg,"\\").replace(/\r/mg,""); -} - -// Convert & to "&", < to "<", > to ">" and " to """ -String.prototype.htmlEncode = function() -{ - return(this.replace(/&/mg,"&").replace(/</mg,"<").replace(/>/mg,">").replace(/\"/mg,""")); -} - -// Convert "&" to &, "<" to <, ">" to > and """ to " -String.prototype.htmlDecode = function() -{ - return(this.replace(/&/mg,"&").replace(/</mg,"<").replace(/>/mg,">").replace(/"/mg,"\"")); -} - -// Parse a space-separated string of name:value parameters where: -// - the name or the value can be optional (in which case separate defaults are used instead) -// - in case of ambiguity, a lone word is taken to be a value -// - if 'cascadeDefaults' is set to true, then the defaults are modified by updated by each specified name or value -// - name prefixes are not allowed if the 'noNames' parameter is true -// - if both the name and value are present they must be separated by a colon -// - the name and the value may both be quoted with single- or double-quotes, double-square brackets -// - names or values quoted with {{double-curly braces}} are evaluated as a JavaScript expression -// - as long as the 'allowEval' parameter is true -// The result is an array of objects: -// result[0] = object with a member for each parameter name, value of that member being an array of values -// result[1..n] = one object for each parameter, with 'name' and 'value' members -String.prototype.parseParams = function(defaultName,defaultValue,allowEval,noNames,cascadeDefaults) -{ - var parseToken = function(match,p) - { - var n; - if(match[p]) // Double quoted - n = match[p]; - else if(match[p+1]) // Single quoted - n = match[p+1]; - else if(match[p+2]) // Double-square-bracket quoted - n = match[p+2]; - else if(match[p+3]) // Double-brace quoted - try - { - n = match[p+3]; - if(allowEval) - n = window.eval(n); - } - catch(e) - { - throw "Unable to evaluate {{" + match[p+3] + "}}: " + exceptionText(e); - } - else if(match[p+4]) // Unquoted - n = match[p+4]; - else if(match[p+5]) // empty quote - n = ""; - return n; - }; - var r = [{}]; - var dblQuote = "(?:\"((?:(?:\\\\\")|[^\"])+)\")"; - var sngQuote = "(?:'((?:(?:\\\\\')|[^'])+)')"; - var dblSquare = "(?:\\[\\[((?:\\s|\\S)*?)\\]\\])"; - var dblBrace = "(?:\\{\\{((?:\\s|\\S)*?)\\}\\})"; - var unQuoted = noNames ? "([^\"'\\s]\\S*)" : "([^\"':\\s][^\\s:]*)"; - var emptyQuote = "((?:\"\")|(?:''))"; - var skipSpace = "(?:\\s*)"; - var token = "(?:" + dblQuote + "|" + sngQuote + "|" + dblSquare + "|" + dblBrace + "|" + unQuoted + "|" + emptyQuote + ")"; - var re = noNames - ? new RegExp(token,"mg") - : new RegExp(skipSpace + token + skipSpace + "(?:(\\:)" + skipSpace + token + ")?","mg"); - var params = []; - do { - var match = re.exec(this); - if(match) - { - var n = parseToken(match,1); - if(noNames) - r.push({name: "", value: n}); - else - { - var v = parseToken(match,8); - if(v == null && defaultName) - { - v = n; - n = defaultName; - } - else if(v == null && defaultValue) - v = defaultValue; - r.push({name: n, value: v}); - if(cascadeDefaults) - { - defaultName = n; - defaultValue = v; - } - } - } - } while(match); - // Summarise parameters into first element - for(var t=1; t<r.length; t++) - { - if(r[0][r[t].name]) - r[0][r[t].name].push(r[t].value); - else - r[0][r[t].name] = [r[t].value]; - } - return r; -} - -// Process a string list of macro parameters into an array. Parameters can be quoted with "", '', -// [[]], {{ }} or left unquoted (and therefore space-separated). Double-braces {{}} results in -// an *evaluated* parameter: e.g. {{config.options.txtUserName}} results in the current user's name. -String.prototype.readMacroParams = function() -{ - var p = this.parseParams("list",null,true,true); - var n = []; - for(var t=1; t<p.length; t++) - n.push(p[t].value); - return n; -} - -// Process a string list of unique tiddler names into an array. Tiddler names that have spaces in them must be [[bracketed]] -String.prototype.readBracketedList = function(unique) -{ - var p = this.parseParams("list",null,false,true); - var n = []; - for(var t=1; t<p.length; t++) - n.pushUnique(p[t].value,unique); - return n; -} - -// Returns array with start and end index of chunk between given start and end marker, or undefined. -String.prototype.getChunkRange = function(start,end) -{ - var s = this.indexOf(start); - if(s != -1) - { - s += start.length; - var e = this.indexOf(end,s); - if(e != -1) - return [s, e]; - } -} - -// Replace a chunk of a string given start and end markers -String.prototype.replaceChunk = function(start,end,sub) -{ - var r = this.getChunkRange(start,end); - return r - ? this.substring(0,r[0]) + sub + this.substring(r[1]) - : this; -} - -// Returns a chunk of a string between start and end markers, or undefined -String.prototype.getChunk = function(start,end) -{ - var r = this.getChunkRange(start,end); - if (r) - return this.substring(r[0],r[1]); -} - - -// Static method to bracket a string with double square brackets if it contains a space -String.encodeTiddlyLink = function(title) -{ - if(title.indexOf(" ") == -1) - return(title); - else - return("[[" + title + "]]"); -} - -// Static method to encodeTiddlyLink for every item in an array and join them with spaces -String.encodeTiddlyLinkList = function(list) -{ - if(list) - { - var results = []; - for(var t=0; t<list.length; t++) - results.push(String.encodeTiddlyLink(list[t])); - return results.join(" "); - } - else - return ""; -} - -// Static method to left-pad a string with 0s to a certain width -String.zeroPad = function(n,d) -{ - var s = n.toString(); - if(s.length < d) - s = "000000000000000000000000000".substr(0,d-s.length) + s; - return(s); -} - -String.prototype.startsWith = function(prefix) -{ - return !prefix || this.substring(0,prefix.length) == prefix; -} - -// Returns the first value of the given named parameter. -//# -//# @param params -//# as returned by parseParams or null/undefined -//# @return [may be null/undefined] -//# -function getParam(params, name, defaultValue) { - if (!params) - return defaultValue; - var p = params[0][name]; - return p ? p[0] : defaultValue; -} - -// Returns the first value of the given boolean named parameter. -//# -//# @param params -//# as returned by parseParams or null/undefined -//# -function getFlag(params, name, defaultValue) { - return !!getParam(params, name, defaultValue); -} - -// Substitute date components into a string -Date.prototype.formatString = function(template) -{ - var t = template.replace(/0hh12/g,String.zeroPad(this.getHours12(),2)); - t = t.replace(/hh12/g,this.getHours12()); - t = t.replace(/0hh/g,String.zeroPad(this.getHours(),2)); - t = t.replace(/hh/g,this.getHours()); - t = t.replace(/0mm/g,String.zeroPad(this.getMinutes(),2)); - t = t.replace(/mm/g,this.getMinutes()); - t = t.replace(/0ss/g,String.zeroPad(this.getSeconds(),2)); - t = t.replace(/ss/g,this.getSeconds()); - t = t.replace(/[ap]m/g,this.getAmPm().toLowerCase()); - t = t.replace(/[AP]M/g,this.getAmPm().toUpperCase()); - t = t.replace(/wYYYY/g,this.getYearForWeekNo()); - t = t.replace(/wYY/g,String.zeroPad(this.getYearForWeekNo()-2000,2)); - t = t.replace(/YYYY/g,this.getFullYear()); - t = t.replace(/YY/g,String.zeroPad(this.getFullYear()-2000,2)); - t = t.replace(/MMM/g,config.messages.dates.months[this.getMonth()]); - t = t.replace(/mmm/g,config.messages.dates.shortMonths[this.getMonth()]); - t = t.replace(/0MM/g,String.zeroPad(this.getMonth()+1,2)); - t = t.replace(/MM/g,this.getMonth()+1); - t = t.replace(/0WW/g,String.zeroPad(this.getWeek(),2)); - t = t.replace(/WW/g,this.getWeek()); - t = t.replace(/DDD/g,config.messages.dates.days[this.getDay()]); - t = t.replace(/ddd/g,config.messages.dates.shortDays[this.getDay()]); - t = t.replace(/0DD/g,String.zeroPad(this.getDate(),2)); - t = t.replace(/DDth/g,this.getDate()+this.daySuffix()); - t = t.replace(/DD/g,this.getDate()); - return t; -} - -Date.prototype.getWeek = function() -{ - var dt = new Date(this.getTime()); - var d = dt.getDay(); - if (d==0) d=7;// JavaScript Sun=0, ISO Sun=7 - dt.setTime(dt.getTime()+(4-d)*86400000);// shift day to Thurs of same week to calculate weekNo - var n = Math.floor((dt.getTime()-new Date(dt.getFullYear(),0,1)+3600000)/86400000); - return Math.floor(n/7)+1; -} - -Date.prototype.getYearForWeekNo = function() -{ - var dt = new Date(this.getTime()); - var d = dt.getDay(); - if (d==0) d=7;// JavaScript Sun=0, ISO Sun=7 - dt.setTime(dt.getTime()+(4-d)*86400000);// shift day to Thurs of same week - return dt.getFullYear(); -} - -Date.prototype.getHours12 = function() -{ - var h = this.getHours(); - return h > 12 ? h-12 : ( h > 0 ? h : 12 ); -} - -Date.prototype.getAmPm = function() -{ - return this.getHours() >= 12 ? "pm" : "am"; -} - -Date.prototype.daySuffix = function() -{ - var num = this.getDate(); - if (num >= 11 && num <= 13) return "th"; - else if (num.toString().substr(-1)=="1") return "st"; - else if (num.toString().substr(-1)=="2") return "nd"; - else if (num.toString().substr(-1)=="3") return "rd"; - return "th"; -} - -// Convert a date to local YYYYMMDDHHMM string format -Date.prototype.convertToLocalYYYYMMDDHHMM = function() -{ - return(String.zeroPad(this.getFullYear(),4) + String.zeroPad(this.getMonth()+1,2) + String.zeroPad(this.getDate(),2) + String.zeroPad(this.getHours(),2) + String.zeroPad(this.getMinutes(),2)); -} - -// Convert a date to UTC YYYYMMDDHHMM string format -Date.prototype.convertToYYYYMMDDHHMM = function() -{ - return(String.zeroPad(this.getUTCFullYear(),4) + String.zeroPad(this.getUTCMonth()+1,2) + String.zeroPad(this.getUTCDate(),2) + String.zeroPad(this.getUTCHours(),2) + String.zeroPad(this.getUTCMinutes(),2)); -} - -// Convert a date to UTC YYYYMMDD.HHMMSSMMM string format -Date.prototype.convertToYYYYMMDDHHMMSSMMM = function() -{ - return(String.zeroPad(this.getUTCFullYear(),4) + String.zeroPad(this.getUTCMonth()+1,2) + String.zeroPad(this.getUTCDate(),2) + "." + String.zeroPad(this.getUTCHours(),2) + String.zeroPad(this.getUTCMinutes(),2) + String.zeroPad(this.getUTCSeconds(),2) + String.zeroPad(this.getUTCMilliseconds(),4)); -} - -// Static method to create a date from a UTC YYYYMMDDHHMM format string -Date.convertFromYYYYMMDDHHMM = function(d) -{ - var theDate = new Date(Date.UTC(parseInt(d.substr(0,4),10), - parseInt(d.substr(4,2),10)-1, - parseInt(d.substr(6,2),10), - parseInt(d.substr(8,2),10), - parseInt(d.substr(10,2),10),0,0)); - return(theDate); -} - -// --------------------------------------------------------------------------------- -// Crypto functions and associated conversion routines -// --------------------------------------------------------------------------------- - -// Crypto "namespace" -function Crypto() {} - -// Convert a string to an array of big-endian 32-bit words -Crypto.strToBe32s = function(str) -{ - var be = Array(); - var len = Math.floor(str.length/4); - var i, j; - for(i=0, j=0; i<len; i++, j+=4) - { - be[i] = ((str.charCodeAt(j)&0xff) << 24)|((str.charCodeAt(j+1)&0xff) << 16)|((str.charCodeAt(j+2)&0xff) << 8)|(str.charCodeAt(j+3)&0xff); - } - while (j<str.length) - { - be[j>>2] |= (str.charCodeAt(j)&0xff)<<(24-(j*8)%32); - j++; - } - return be; -} - -// Convert an array of big-endian 32-bit words to a string -Crypto.be32sToStr = function(be) -{ - var str = ""; - for(var i=0;i<be.length*32;i+=8) - str += String.fromCharCode((be[i>>5]>>>(24-i%32)) & 0xff); - return str; -} - -// Convert an array of big-endian 32-bit words to a hex string -Crypto.be32sToHex = function(be) -{ - var hex = "0123456789ABCDEF"; - var str = ""; - for(var i=0;i<be.length*4;i++) - str += hex.charAt((be[i>>2]>>((3-i%4)*8+4))&0xF) + hex.charAt((be[i>>2]>>((3-i%4)*8))&0xF); - return str; -} - -// Return, in hex, the SHA-1 hash of a string -Crypto.hexSha1Str = function(str) -{ - return Crypto.be32sToHex(Crypto.sha1Str(str)); -} - -// Return the SHA-1 hash of a string -Crypto.sha1Str = function(str) -{ - return Crypto.sha1(Crypto.strToBe32s(str),str.length); -} - -// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words -Crypto.sha1 = function(x,blen) -{ - // Add 32-bit integers, wrapping at 32 bits - //# Uses 16-bit operations internally to work around bugs in some JavaScript interpreters. - add32 = function(a,b) - { - var lsw = (a&0xFFFF)+(b&0xFFFF); - var msw = (a>>16)+(b>>16)+(lsw>>16); - return (msw<<16)|(lsw&0xFFFF); - }; - // Add five 32-bit integers, wrapping at 32 bits - //# Uses 16-bit operations internally to work around bugs in some JavaScript interpreters. - add32x5 = function(a,b,c,d,e) - { - var lsw = (a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF); - var msw = (a>>16)+(b>>16)+(c>>16)+(d>>16)+(e>>16)+(lsw>>16); - return (msw<<16)|(lsw&0xFFFF); - }; - // Bitwise rotate left a 32-bit integer by 1 bit - rol32 = function(n) - { - return (n>>>31)|(n<<1); - }; - - var len = blen*8; - // Append padding so length in bits is 448 mod 512 - x[len>>5] |= 0x80 << (24-len%32); - // Append length - x[((len+64>>9)<<4)+15] = len; - var w = Array(80); - - var k1 = 0x5A827999; - var k2 = 0x6ED9EBA1; - var k3 = 0x8F1BBCDC; - var k4 = 0xCA62C1D6; - - var h0 = 0x67452301; - var h1 = 0xEFCDAB89; - var h2 = 0x98BADCFE; - var h3 = 0x10325476; - var h4 = 0xC3D2E1F0; - - for(var i=0;i<x.length;i+=16) - { - var j,t; - var a = h0; - var b = h1; - var c = h2; - var d = h3; - var e = h4; - for(j = 0;j<16;j++) - { - w[j] = x[i+j]; - t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1); - e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; - } - for(j=16;j<20;j++) - { - w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]); - t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1); - e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; - } - for(j=20;j<40;j++) - { - w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]); - t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k2); - e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; - } - for(j=40;j<60;j++) - { - w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]); - t = add32x5(e,(a>>>27)|(a<<5),(b&c)|(d&(b|c)),w[j],k3); - e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; - } - for(j=60;j<80;j++) - { - w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]); - t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k4); - e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t; - } - - h0 = add32(h0,a); - h1 = add32(h1,b); - h2 = add32(h2,c); - h3 = add32(h3,d); - h4 = add32(h4,e); - } - return Array(h0,h1,h2,h3,h4); -} - -// --------------------------------------------------------------------------------- -// RGB colour object -// --------------------------------------------------------------------------------- - -// Construct an RGB colour object from a '#rrggbb', '#rgb' or 'rgb(n,n,n)' string or from separate r,g,b values -function RGB(r,g,b) -{ - this.r = 0; - this.g = 0; - this.b = 0; - if(typeof r == "string") - { - if(r.substr(0,1) == "#") - { - if(r.length == 7) - { - this.r = parseInt(r.substr(1,2),16)/255; - this.g = parseInt(r.substr(3,2),16)/255; - this.b = parseInt(r.substr(5,2),16)/255; - } - else - { - this.r = parseInt(r.substr(1,1),16)/15; - this.g = parseInt(r.substr(2,1),16)/15; - this.b = parseInt(r.substr(3,1),16)/15; - } - } - else - { - var rgbPattern = /rgb\s*\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/ ; - var c = r.match(rgbPattern); - if (c) - { - this.r = parseInt(c[1],10)/255; - this.g = parseInt(c[2],10)/255; - this.b = parseInt(c[3],10)/255; - } - } - } - else - { - this.r = r; - this.g = g; - this.b = b; - } - return this; -} - -// Mixes this colour with another in a specified proportion -// c = other colour to mix -// f = 0..1 where 0 is this colour and 1 is the new colour -// Returns an RGB object -RGB.prototype.mix = function(c,f) -{ - return new RGB(this.r + (c.r-this.r) * f,this.g + (c.g-this.g) * f,this.b + (c.b-this.b) * f); -} - -// Return an rgb colour as a #rrggbb format hex string -RGB.prototype.toString = function() -{ - var r = this.r.clamp(0,1); - var g = this.g.clamp(0,1); - var b = this.b.clamp(0,1); - return("#" + ("0" + Math.floor(r * 255).toString(16)).right(2) + - ("0" + Math.floor(g * 255).toString(16)).right(2) + - ("0" + Math.floor(b * 255).toString(16)).right(2)); -} - -// --------------------------------------------------------------------------------- -// DOM utilities - many derived from www.quirksmode.org -// --------------------------------------------------------------------------------- - -function drawGradient(place,horiz,colours) -{ - for(var t=0; t<= 100; t+=2) - { - var bar = document.createElement("div"); - place.appendChild(bar); - bar.style.position = "absolute"; - bar.style.left = horiz ? t + "%" : 0; - bar.style.top = horiz ? 0 : t + "%"; - bar.style.width = horiz ? (101-t) + "%" : "100%"; - bar.style.height = horiz ? "100%" : (101-t) + "%"; - bar.style.zIndex = -1; - var f = t/100; - var p = f*(colours.length-1); - bar.style.backgroundColor = colours[Math.floor(p)].mix(colours[Math.ceil(p)],p-Math.floor(p)).toString(); - } -} - -function createTiddlyText(theParent,theText) -{ - return theParent.appendChild(document.createTextNode(theText)); -} - -function createTiddlyCheckbox(theParent,caption,checked,onChange) -{ - var cb = document.createElement("input"); - cb.setAttribute("type","checkbox"); - cb.onclick = onChange; - theParent.appendChild(cb); - cb.checked = checked; - cb.className = "chkOptionInput"; - if(caption) - wikify(caption,theParent); - return cb; -} - -function createTiddlyElement(theParent,theElement,theID,theClass,theText) -{ - var e = document.createElement(theElement); - if(theClass != null) - e.className = theClass; - if(theID != null) - e.setAttribute("id",theID); - if(theText != null) - e.appendChild(document.createTextNode(theText)); - if(theParent != null) - theParent.appendChild(e); - return(e); -} - -// Add an event handler -// Thanks to John Resig, via QuirksMode -function addEvent(obj,type,fn) -{ - if(obj.attachEvent) - { - obj['e'+type+fn] = fn; - obj[type+fn] = function(){obj['e'+type+fn](window.event);} - obj.attachEvent('on'+type,obj[type+fn]); - } - else - obj.addEventListener(type,fn,false); -} - -// Remove an event handler -// Thanks to John Resig, via QuirksMode -function removeEvent(obj,type,fn) -{ - if(obj.detachEvent) - { - obj.detachEvent('on'+type,obj[type+fn]); - obj[type+fn] = null; - } - else - obj.removeEventListener(type,fn,false); -} - -function addClass(e,theClass) -{ - var currClass = e.className.split(" "); - if(currClass.indexOf(theClass) == -1) - e.className += " " + theClass; -} - -function removeClass(e,theClass) -{ - var currClass = e.className.split(" "); - var i = currClass.indexOf(theClass); - while(i != -1) - { - currClass.splice(i,1); - i = currClass.indexOf(theClass); - } - e.className = currClass.join(" "); -} - -function hasClass(e,theClass) -{ - if(e.className) - { - if(e.className.split(" ").indexOf(theClass) != -1) - return true; - } - return false; -} - -// Find the closest relative with a given property value (property defaults to tagName, relative defaults to parentNode) -function findRelated(e,value,name,relative) -{ - name = name ? name : "tagName"; - relative = relative ? relative : "parentNode"; - if(name == "className") - { - while(e && !hasClass(e,value)) - { - e = e[relative]; - } - } - else - { - while(e && e[name] != value) - { - e = e[relative]; - } - } - return e; -} - -// Resolve the target object of an event -function resolveTarget(e) -{ - var obj; - if (e.target) - obj = e.target; - else if (e.srcElement) - obj = e.srcElement; - if (obj.nodeType == 3) // defeat Safari bug - obj = obj.parentNode; - return(obj); -} - -// Return the content of an element as plain text with no formatting -function getPlainText(e) -{ - var text = ""; - if(e.innerText) - text = e.innerText; - else if(e.textContent) - text = e.textContent; - return text; -} - -// Get the scroll position for window.scrollTo necessary to scroll a given element into view -function ensureVisible(e) -{ - var posTop = findPosY(e); - var posBot = posTop + e.offsetHeight; - var winTop = findScrollY(); - var winHeight = findWindowHeight(); - var winBot = winTop + winHeight; - if(posTop < winTop) - return(posTop); - else if(posBot > winBot) - { - if(e.offsetHeight < winHeight) - return(posTop - (winHeight - e.offsetHeight)); - else - return(posTop); - } - else - return(winTop); -} - -// Get the current width of the display window -function findWindowWidth() -{ - return(window.innerWidth ? window.innerWidth : document.documentElement.clientWidth); -} - -// Get the current height of the display window -function findWindowHeight() -{ - return(window.innerHeight ? window.innerHeight : document.documentElement.clientHeight); -} - -// Get the current horizontal page scroll position -function findScrollX() -{ - return(window.scrollX ? window.scrollX : document.documentElement.scrollLeft); -} - -// Get the current vertical page scroll position -function findScrollY() -{ - return(window.scrollY ? window.scrollY : document.documentElement.scrollTop); -} - -function findPosX(obj) -{ - var curleft = 0; - while (obj.offsetParent) - { - curleft += obj.offsetLeft; - obj = obj.offsetParent; - } - return curleft; -} - -function findPosY(obj) -{ - var curtop = 0; - while (obj.offsetParent) - { - curtop += obj.offsetTop; - obj = obj.offsetParent; - } - return curtop; -} - -// Blur a particular element -function blurElement(e) -{ - if(e != null && e.focus && e.blur) - { - e.focus(); - e.blur(); - } -} - -// Create a non-breaking space -function insertSpacer(place) -{ - var e = document.createTextNode(String.fromCharCode(160)); - if(place) - place.appendChild(e); - return e; -} - -// Remove all children of a node -function removeChildren(e) -{ - while(e.hasChildNodes()) - e.removeChild(e.firstChild); -} - -// Add a stylesheet, replacing any previous custom stylesheet -function setStylesheet(s,id) -{ - if(!id) - id = "customStyleSheet"; - var n = document.getElementById(id); - if(document.createStyleSheet) // Test for IE's non-standard createStyleSheet method - { - if(n) - n.parentNode.removeChild(n); - // This failed without the - document.getElementsByTagName("head")[0].insertAdjacentHTML("beforeEnd"," <style id='" + id + "'>" + s + "</style>"); - } - else - { - if(n) - n.replaceChild(document.createTextNode(s),n.firstChild); - else - { - var n = document.createElement("style"); - n.type = "text/css"; - n.id = id; - n.appendChild(document.createTextNode(s)); - document.getElementsByTagName("head")[0].appendChild(n); - } - } -} - -// Replace the current selection of a textarea or text input and scroll it into view - -function replaceSelection(e,text) -{ - if (e.setSelectionRange) - { - var oldpos = e.selectionStart + 1; - e.value = e.value.substr(0,e.selectionStart) + text + e.value.substr(e.selectionStart); - e.setSelectionRange( oldpos, oldpos); - var linecount = e.value.split('\n').length; - var thisline = e.value.substr(0,e.selectionStart).split('\n').length-1; - e.scrollTop = Math.floor((thisline-e.rows/2)*e.scrollHeight/linecount); - } - else if (document.selection) - { - var range = document.selection.createRange(); - if (range.parentElement() == e) - { - var isCollapsed = range.text == ""; - range.text = text; - if (!isCollapsed) - { - range.moveStart('character', -text.length); - range.select(); - } - } - } -} - -// Returns the text of the given (text) node, possibly merging subsequent text nodes -function getNodeText(e) -{ - var t = ""; - while (e && e.nodeName == "#text") - { - t += e.nodeValue; - e = e.nextSibling; - } - return t; -} -//# ------------------------- -//# LoaderBase: A (abstract) storage loader that loads the tiddlers from a list of HTML elements. -//# The format of the elements is defined by subclasses of this loader through the internalizeTiddler implementation. -//# Subclasses must implement: -//# function getTitle(store, e) -//# -//# store must implement: -//# function createTiddler(title). -//# - -function LoaderBase() -{ -} - -LoaderBase.prototype.loadTiddler = function(store,e,tiddlers) -{ - var title = this.getTitle(store, e); - if (title) - { - var tiddler = store.createTiddler(title); - this.internalizeTiddler(store, tiddler, title, e); - tiddlers.push(tiddler); - } -} - -LoaderBase.prototype.loadTiddlers = function(store,nodes) -{ - var tiddlers = []; - for (var t = 0; t < nodes.length; t++) - { - try - { - this.loadTiddler(store, nodes[t], tiddlers); - } - catch(e) - { - showException(e, config.messages.tiddlerLoadError.format([this.getTitle(store, nodes[t])])); - } - } - return tiddlers; -} - -//# ------------------------- -//# SaverBase: a (abstract) storage saver that externalizes all tiddlers into a string, -//# with every tiddler individually externalized (using this.externalizeTiddler) and joined with newlines -//# Subclasses must implement: -//# function externalizeTiddler(store, tiddler) -//# -//# store must implement: -//# function getTiddlers(sortByFieldName) -//# - -function SaverBase() -{ -} - -SaverBase.prototype.externalize = function(store) -{ - var results = []; - var tiddlers = store.getTiddlers("title"); - for (var t = 0; t < tiddlers.length; t++) - results.push(this.externalizeTiddler(store, tiddlers[t])); - return results.join("\n"); -} -//-------------------------------- -// TW21Loader (inherits from LoaderBase) - -function TW21Loader() {}; - -TW21Loader.prototype = new LoaderBase(); - -TW21Loader.prototype.getTitle = function(store, e) { - var title = null; - if(e.getAttribute) - title = e.getAttribute("tiddler"); - if(!title && e.id) { - var lenPrefix = store.idPrefix.length; - if (e.id.substr(0,lenPrefix) == store.idPrefix) - title = e.id.substr(lenPrefix); - } - return title; -} - -TW21Loader.prototype.internalizeTiddler = function(store, tiddler, title, data) { - var text = getNodeText(data.firstChild).unescapeLineBreaks(); - var modifier = data.getAttribute("modifier"); - var modified = Date.convertFromYYYYMMDDHHMM(data.getAttribute("modified")); - var c = data.getAttribute("created"); - var created = c ? Date.convertFromYYYYMMDDHHMM(c) : modified; - var tags = data.getAttribute("tags"); - var fields = {}; - var attrs = data.attributes; - for(var i = attrs.length-1; i >= 0; i--) { - var name = attrs[i].name; - if (attrs[i].specified && !TiddlyWiki.isStandardField(name)) { - fields[name] = attrs[i].value.unescapeLineBreaks(); - } - } - tiddler.assign(title,text,modifier,modified,tags,created, fields); - return tiddler; -}; - -//-------------------------------- -// TW21Saver (inherits from SaverBase) - -function TW21Saver() {}; - -TW21Saver.prototype = new SaverBase(); - -TW21Saver.prototype.externalizeTiddler = function(store, tiddler) -{ - try { - var extendedFieldAttributes = ""; - store.forEachField(tiddler, - function(tiddler, fieldName, value) { - // don't store stuff from the temp namespace - if (!fieldName.match(/^temp\./)) - extendedFieldAttributes += ' %0="%1"'.format([fieldName, value.escapeLineBreaks().htmlEncode()]); - }, true); - return '<div tiddler="%0" modifier="%1" modified="%2" created="%3" tags="%4"%6>%5</div>'.format([ - tiddler.title.htmlEncode(), - tiddler.modifier.htmlEncode(), - tiddler.modified.convertToYYYYMMDDHHMM(), - tiddler.created.convertToYYYYMMDDHHMM(), - tiddler.getTags().htmlEncode(), - tiddler.escapeLineBreaks().htmlEncode(), - extendedFieldAttributes - ]); - } catch (e) { - throw exceptionText(e, config.messages.tiddlerSaveError.format([tiddler.title])); - } -} - -// --------------------------------------------------------------------------------- -// Deprecated code -// --------------------------------------------------------------------------------- - -// @Deprecated: Use createElementAndWikify and this.termRegExp instead -config.formatterHelpers.charFormatHelper = function(w) -{ - w.subWikify(createTiddlyElement(w.output,this.element),this.terminator); -} - -// @Deprecated: Use enclosedTextHelper and this.lookaheadRegExp instead -config.formatterHelpers.monospacedByLineHelper = function(w) -{ - var lookaheadRegExp = new RegExp(this.lookahead,"mg"); - lookaheadRegExp.lastIndex = w.matchStart; - var lookaheadMatch = lookaheadRegExp.exec(w.source); - if(lookaheadMatch && lookaheadMatch.index == w.matchStart) - { - var text = lookaheadMatch[1]; - if(config.browser.isIE) - text = text.replace(/\n/g,"\r"); - createTiddlyElement(w.output,"pre",null,null,text); - w.nextMatch = lookaheadRegExp.lastIndex; - } -} - -// @Deprecated: Use <br> or <br /> instead of <<br>> -config.macros.br.handler = function(place) -{ - createTiddlyElement(place,"br"); -} - -// Find an entry in an array. Returns the array index or null -// @Deprecated: Use indexOf instead -Array.prototype.find = function(item) -{ - var i = this.indexOf(item); - return i == -1 ? null : i; -} - -// Load a tiddler from an HTML DIV. The caller should make sure to later call Tiddler.changed() -// @Deprecated: Use store.getLoader().internalizeTiddler instead -Tiddler.prototype.loadFromDiv = function(divRef,title) -{ - return store.getLoader().internalizeTiddler(store,this,title,divRef); -} - -// Format the text for storage in an HTML DIV -// @Deprecated Use store.getSaver().externalizeTiddler instead. -Tiddler.prototype.saveToDiv = function() -{ - return store.getSaver().externalizeTiddler(store,this); -} - -// @Deprecated: Use store.allTiddlersAsHtml() instead -function allTiddlersAsHtml() -{ - return store.allTiddlersAsHtml(); -} - -// @Deprecated: Use refreshPageTemplate instead -function applyPageTemplate(title) -{ - refreshPageTemplate(title); -} - -// @Deprecated: Use story.displayTiddlers instead -function displayTiddlers(srcElement,titles,template,unused1,unused2,animate,slowly) -{ - story.displayTiddlers(srcElement,titles,template,animate,slowly); -} - -// @Deprecated: Use story.displayTiddler instead -function displayTiddler(srcElement,title,template,unused1,unused2,animate,slowly) -{ - story.displayTiddler(srcElement,title,template,animate,slowly); -} - -// @Deprecated: Use functions on right hand side directly instead -var createTiddlerPopup = Popup.create; -var scrollToTiddlerPopup = Popup.show; -var hideTiddlerPopup = Popup.remove; - -// @Deprecated: Use right hand side directly instead -var regexpBackSlashEn = new RegExp("\\\\n","mg"); -var regexpBackSlash = new RegExp("\\\\","mg"); -var regexpBackSlashEss = new RegExp("\\\\s","mg"); -var regexpNewLine = new RegExp("\n","mg"); -var regexpCarriageReturn = new RegExp("\r","mg"); -// --------------------------------------------------------------------------------- -// End of scripts -merge(config.shadowTiddlers,{SiteTitle:'DevFire'}); -merge(config.shadowTiddlers,{MainMenu:"PageTemplate\nStyleSheet\nMainMenu\nDefaultTiddlers"}); -merge(config.shadowTiddlers,{SiteSubtitle:"a theme for ~TiddlyWiki"}); -merge(config.shadowTiddlers,{DefaultTiddlers:"LorumIpsum"}); -merge(config.shadowTiddlers,{LorumIpsum:"Aenean eros arcu, condimentum nec, dapibus ut, tincidunt sit amet, urna. Quisque viverra, eros sed imperdiet iaculis, est risus facilisis quam, id malesuada arcu nulla luctus urna. Nullam et est. Vestibulum velit sem, faucibus cursus, dapibus vestibulum, pellentesque et, urna. Donec luctus. Donec lectus. Aliquam eget eros facilisis tortor feugiat sollicitudin. Integer lobortis vulputate sapien. Sed iaculis erat ac nunc. Etiam eu enim. Mauris ipsum urna, rhoncus at, bibendum sit amet, euismod eget, dolor. Mauris fermentum quam vitae ligula. Vestibulum in libero feugiat justo dictum consectetuer. Vestibulum euismod purus eget elit. Nunc sed massa porta elit bibendum posuere. Nunc pulvinar justo sit amet odio. In sed est. Phasellus ornare elementum nulla. Nulla ipsum neque, cursus a, viverra a, imperdiet at, enim. Quisque facilisis, diam sed accumsan suscipit, odio arcu hendrerit dolor, quis aliquet massa nulla nec sem.\n!heading 1\n!!heading 2\n!!!heading3\n----\n<<tag button>>\nThis is a link to a [[StyleSheet]] tiddler.\n\n> This is a blockquote\n> This is a blockquote\n> This is a blockquote\n|>|>| !This is a header |h\n|column1|column2|column3|\n|row2| row2 |row2|\n|column1|column2|column3|\n|row2| row2 |row2|\n|column1|column2|column3|\n|row2| row2 |row2|"}); -// --------------------------------------------------------------------------------- -//]]> -</script> -<style type="text/css"> - -#saveTest { - display: none; -} - -.zoomer { - display: none; -} - -#messageArea { - display: none; -} - -#copyright { - display: none; -} - -.popup { - position: absolute; -} - -#storeArea { - display: none; - margin: 4em 10em 3em; -} - -#storeArea div { - padding: 0.5em; - margin: 1em 0em 0em 0em; - border-color: #f0f0f0 #606060 #404040 #d0d0d0; - border-style: solid; - border-width: 2px; - overflow: auto; -} - -#javascriptWarning { - width: 100%; - text-align: center; - font-weight: bold; - background-color: #dd1100; - color: #fff; - padding:1em 0em; -} - -</style> -<!--POST-HEAD-START--> - -<!--POST-HEAD-END--> -</head> -<body onload="main();" onunload="if(window.checkUnsavedChanges) checkUnsavedChanges();"> -<!--PRE-BODY-START--> - -<!--PRE-BODY-END--> - <script type="text/javascript"> -//<![CDATA[ -if (useJavaSaver) - document.write("<applet style='position:absolute;left:-1px' name='TiddlySaver' code='TiddlySaver.class' archive='TiddlySaver.jar' width='1' height='1'></applet>"); -//]]> - </script> - <div id="copyright"> - Welcome to TiddlyWiki by Jeremy Ruston, Copyright © 2006 Osmosoft Limited - </div> - <noscript> - <div id="javascriptWarning">This page requires JavaScript to function properly</div> - </noscript> - <div id="saveTest"></div> - <div id="contentWrapper"></div> - <div id="contentStash"></div> - <div id="storeArea"> -<div tiddler="(built-in shadow tiddler)" modifier="CameronRich" modified="200702240024" created="200702240024" tags="">changes, notes and errata</div> -<div tiddler="Cam" modifier="YourName" modified="200804011313" created="200804011313" tags="">Type the text for 'YourName'</div> -<div tiddler="Changelog" modifier="YourName" modified="201111040904" created="200702240022" tags="">@@bgcolor(#ff0000):color(#ffffff):Changes for 1.4.4@@\n\n!!__axhttpd__\n* Allow other CGI applications (such as PHP) to call HTML files from their command line.\n\n!!__SSL Library__\n* Fixed memory leak with invalid certificates (thanks Jon Trauntvein)\n* Fixed issue with non-blocking client connections not working properly (thanks Richard Titmuss).\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.4.3@@\n\n!!__SSL Library__\n* axtlswrap compilation error fixed.\n\n!!__axhttpd__\n* added '-w' command-line option to set the webroot directory.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.4.2@@\n\n!!__SSL Library__\n* bi_export could have a buffer overrun with incorrect input (thanks Gilles ~Boccon-Gibod - 3334305)\n\n!!__axhttpd__\n* ~RFC1123 time format used in the headers.\n* Expires heading added (current time + ~CONFIG_HTTP_TIMEOUT)\n* UTC/localtime issue with ~If-Modified-Since header.\n\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.4.1@@\n\n!!__SSL Library__\n* Allow reading of ~PKCS8/12 unencrypted keys in PEM format and mconf will allow the option in server mode (thanks Steve Bennett).\n* Issue where comparing a null and an empty string could return a false positive for cert check (thanks Gilles ~Boccon-Gibod - 3310885).\n* -fPIC added as a Linux compile option.\n\n!!__axhttpd__\n* Killing connections on session timeout is guaranteed.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.4.0@@\n\n!!__SSL Library__\n* TLS v1.1 implemented and is enabled by default.\n* Closure alerts implemented correctly.\n* Fixed issue with ~SSLv23 hello versioning. \n \n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.3.4@@\n\n!!__SSL Library__\n* SSL 2.0 client hello is turned off by default as per RFC 4346 Appendix E.\n* Client determines the cipher suite selected rather than the server as per RFC 4346 7.4.1.2.\n* Guard against timing HMAC timing attacks as per RFC 4346 6.2.3.2.\n* Fixed ~SOCKET_WRITE buffer issue (thanks Hardy Griech - 3177419)\n* Fixed variable length MAC issue as used by gnutls.\n* Fixed version issue when TLS >=1.1 is used.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.3.2@@\n\n!!__SSL Library__\n* Loading of PEM certificate bundles now loads CA certs properly.\n* ssl_client_new() can now be broken up into an ssl_client_new() and successive ssl_read()'s now by setting the ~SSL_CONNECT_IN_PARTS as an option in ssl_ctx_new().\n* Non-blocked mode is now not a requirement but calls may still be blocked.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.3.1@@\n\n!!__SSL Library__\n* Certificate bundles which contain "invalid" certificates (i.e. invalid digests types etc) are ignored rather than cause failure.\n\n!!__axhttpd__\n* ~HTTPv1.0 packets close a connection upon completion.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.3.0@@\n\n!!__SSL Library__\n* Close notify is now sent as an error code from ssl_read(). Server code should be modified to check for ~SSL_CLOSE_NOTIFY (thanks to Eric Hu - 3132700).\n* regular_square() issue fixed (3078672)\n* partial_multiply() removed and merged with regular_multiply() (3078372).\n* Invalid session id size now returns ~SSL_ERROR_INVALID_SESSION (thanks to Hardy Griech - 3072881)\n* q-dash issue with Barrett reduction fixed (thanks to Hardy Griech - 3079291).\n* PEM file detection now looks for "-BEGIN" in any part of the file rather than at the start (3123838).\n* 8/16/32 bit native int sizes can be selected in configuration.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.2.7@@\n\n!!__SSL Library__\n* A fix to find_max_exp_index() (thanks to Hardy Griech).\n* Check is made to get_cipher_info() if the appropriate cipher is not found (thanks to Hardy Griech).\n* Extra x509_free() removed from do_client_connect().\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.2.5@@\n\n!!__SSL Library__\n* The custom RNG updated to use an entropy pool (with better hooks to use counters).\n\n!!__axhttpd__\n* Headers are case insensitive (thanks to Joe Pruett for this and the following).\n* Child zombie issue fixed.\n* EOF on ~POSTs fixed.\n* Expect is ignored.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.2.4@@\n\n!!__SSL Library__\n* Client renegotiation now results in an error. This is the result of a security flaw described in this paper http://extendedsubset.com/Renegotiating_TLS.pdf, and also is explained in detail here http://www.cupfighter.net/index.php/2009/11/tls-renegotiation-attack/.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.2.3@@\n\n!!__SSL Library__\n* v3 certificates with ~SANs now supports (thanks to Carsten Sørensen).\n* axtlswrap added - a port of sslwrap (thanks to Steve Bennett)\n\n!!__axhttpd__\n* shutdown() called before socket close in CGI (thanks to Tom Brown)\n* command-line parameters to specify the http/https port.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.2.2@@\n\n!!__axhttpd__\n* File uploads over 1kB (but under MAXPOSTDATASIZE) are now supported.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.2.1@@\n\n!!__SSL Library__\n* Certificate verification now works for Firefox.\n* Extended the openssl API.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.2.0@@\n\n!!__SSL Library__\n* A self-signed certificate will be verified as ok provided that that it is on the certificate authority list.\n* Certificates are not verified when added as certificate authorities (since self-signed and expired certificates can be added to browsers etc)\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.9@@\n\n!!__SSL Library__\n* Now support MS IIS resource kit certificates (thanks to Carsten Sørensen).\n* Fixed a memory leak when freeing more than one CA certificate.\n* The bigint library had a problem with squaring which affected classical reduction (thanks to Manuel Klimek).\n\n!!__axhttpd__\n* Brought back setuid()/setgid() as an option.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.8@@\n\n!!__SSL Library__\n* Now using a BSD style license.\n* Self-signed certificates can now be automatically generated (the keys still need to be provided).\n* A new API call //ssl_x509_create()// can be used to programatically create the certificate.\n* Certificate/keys can be loaded automatically given a file location.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.7@@\n\n!!__SSL Library__\n\n* Variable sized session id's is now better handled for session caching. It has meant a new API call //ssl_get_session_id_size()// and a change to //ssl_client_new()// to define the session id size.\n* Muliple records with a single header are now better supported (thanks to Hervé Sibert).\n* ~MD2 added for Verisign root cert verification (thanks to Byron Rakitzis).\n* The ~MD5/~SHA1 digests are calculated incrementally to reduce memory (thanks to Byron Rakitzis).\n* The bigint cache is now cleared regularly to reduce memory.\n\n!!__axhttpd__\n\n* Improved the POST handling (thanks to Christian Melki).\n* CSS files now work properly.\n* Lua's CGI launcher location is configurable.\n* //vfork()// is now used for CGI for performance reasons.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.6@@\n\n!!__SSL Library__\n\n* ~RC4 speed improvements\n* Lua samples/bindings now work properly\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.5@@\n\n!!__SSL Library__\n\n* Session id's can now be variable lengths in server hello messages.\n* 0 length client certificates are now supported.\n* ssl_version() now returns just the version and not the date.\n* ssl_write() was not sending complete packets under load.\n\n!!__axhttpd__\n\n* Completely updated the CGI code.\n* Lua now integrated - Lua scripts and Lua Pages now run.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.4@@\n\n!!__SSL Library__\n\n* Fixed a Win32 crypto library issue with non-Administrator users\n* Removed compiler warnings that showed up in ~FC6.\n* GNU TLS certificates are now accepted.\n* Separated the send/receive headers for HMAC calculations.\n* Fixed a compilation problem with swig/perl/~FC6.\n* Fixed an issue with loading PEM CA certificates.\n\n!!__axhttpd__\n\n* Made //setuid()/setgid()// call an mconf option.\n* Made //chroot()// an mconf option. Default to //chdir()// instead.\n* Removed optional permissions checking.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.1@@\n\n!!__SSL Library__\n\n* AES should now work on 16bit processors (there was an alignment problem).\n* Various freed objects are cleared before freeing.\n* Header files now installed in ///usr/local/include/axTLS//.\n* -DCYGWIN replaced with -~DCONFIG_PLATFORM_CYGWIN (and the same for Solaris).\n* removed "-noextern" option in Swig. Fixed some other warnings in Win32.\n* SSLCTX changed to ~SSL_CTX (to be consistent with openssl). SSLCTX still exists for backwards compatibility.\n* malloc() and friends call abort() on failure.\n* Fixed a memory leak in directory listings.\n* Added openssl() compatibility functions.\n* Fixed Cygwin 'make install' issue.\n\n!!__axhttpd__\n\n* main.c now becomes axhttpd.c.\n* Header file issue fixed (in mime_types.c).\n* //chroot()// now used for better security.\n* Basic authentication implemented (via .htpasswd).\n* SSL access/denial protection implemented (via .htaccess).\n* Directory access protection implemented (via .htaccess).\n* Can now have more than one CGI file extension in mconf.\n* "~If-Modified-Since" request now handled properly.\n* Performance tweaks to remove //ssl_find()//.</div> -<div tiddler="DefaultTiddlers" modifier="CameronRich" modified="200702240019" created="200702240019" tags="">[[Read Me]]</div> -<div tiddler="License" modifier="YourName" modified="200804011309" created="200702240022" tags="">axTLS uses a BSD style license:\n\nCopyright (c) 2008, Cameron Rich All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this\nlist of conditions and the following disclaimer. Redistributions in binary\nform must reproduce the above copyright notice, this list of conditions and\nthe following disclaimer in the documentation and/or other materials\nprovided with the distribution. Neither the name of the axTLS Project nor\nthe names of its contributors may be used to endorse or promote products\nderived from this software without specific prior written permission. \n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\nOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGE.</div> -<div tiddler="MainMenu" modifier="CameronRich" modified="200702250353" created="200702240021" tags="">[[Read Me]] \n[[Changelog]]\n[[axhttpd]]\n[[License]]</div> -<div tiddler="PageTemplate" modifier="YourName" modified="200701122313" created="200701122350" tags="DevFireTheme"><div class='header' macro='gradient vert #390108 #900'>\n<div class='headerShadow'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;\n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n<div class='headerForeground'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;\n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n</div>\n<div id='mainMenu'>\n<div refresh='content' tiddler='MainMenu'></div>\n</div>\n<div id='sidebar'>\n<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>\n<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>\n</div>\n<div id='displayArea'>\n<div id='messageArea'></div>\n<div id='tiddlerDisplay'></div>\n</div></div> -<div tiddler="Read Me" modifier="YourName" modified="201106261041" created="200702240020" tags="">!@@bgcolor(#ff0000):color(#ffffff):axTLS Quick Start Guide@@\n\nThis is a guide to get a small SSL web-server up and running quickly.\n\n!!__Introduction__\n\nThe axTLS project is an SSL client/server library using the ~TLSv1 protocol. It is designed to be small and fast, and is suited to embedded projects. A web server is included.\n\nThe basic web server + SSL library is around 60-70kB and is configurable for features or size.\n\n!!__Compilation__\n\nAll platforms require GNU make. This means on Win32 that Cygwin needs to be installed with "make" and various developer options selected.\n\nConfiguration now uses a tool called "mconf" which gives a nice way to configure options (similar to what is used in ~BusyBox and the Linux kernel).\n\nYou should be able to compile axTLS simply by extracting it, change into the extracted directory and typing:\n\n{{indent{{{{> make}}}\n\nSelect your platform type, save the configuration, exit, and then type "make" again.\n\nIf all goes well, you should end up with an executable called "axhttpd" (or axhttpd.exe) in the //_stage// directory.\n\nTo play with all the various axTLS options, type:\n\n{{indent{{{{> make menuconfig}}}\n\nSave the new configuration and rebuild.\n\n!!__Running it__\n\nTo run it, go to the //_stage// directory, and type (as superuser):\n\n{{indent{{{{> axhttpd}}}\n\nNote: you may have to set your ~LD_LIBRARY_PATH - e.g. go to //_stage// and type //export ~LD_LIBRARY_PATH=`pwd`//\n\nAnd then point your browser at https://127.0.0.1 And you should see a this html page with a padlock appearing on your browser. or type http://127.0.0.1 to see the same page unencrypted.\n\n!!__The axssl utilities__\n\nThe axssl suite of tools are the SSL test tools in the various language bindings. They are:\n\n* axssl - C sample\n* axssl.csharp - C# sample\n* axssl.vbnet - VB.NET sample\n* axtls.jar - Java sample\n* axssl.pl - Perl sample\n* axssl.lua - Lua sample\n\nAll the tools have identical command-line parameters. e.g. to run something interesting:\n\n{{indent{{{{> axssl s_server -verify -CAfile ../ssl/test/axTLS.ca_x509}}}\n\nand\n\n{{indent{{{{> axssl s_client -cert ../ssl/test/axTLS.x509_1024 -key ../ssl/test/axTLS.key_1024 -reconnect}}}\n\n!!!!C#\n\nIf building under Linux or other non-Win32 platforms, Mono must be installed and the executable is run as:\n\n{{indent{{{{> mono axssl.csharp.exe ...}}}\n\n!!!!Java\n\nThe java version is run as:\n\n{{indent{{{{> java -jar axtls.jar <options>}}}\n\n!!!!Perl\n\n{{indent{{{{> [perl] ./axssl.pl <options>}}}\n\nIf running under Win32, be sure to use the correct version of Perl (i.e. ~ActiveState's version works ok).\n\n!!!!Lua\n\n{{indent{{{{> [lua] ./axssl.lua <options>}}}\n\n!__Known Issues__\n\n* Firefox doesn't handle legacy ~SSLv2 at all well. Disabling ~SSLv2 still initiates a ~SSLv23 handshake (v1.5). And continuous pressing of the "Reload" page instigates a change to ~SSLv3 for some reason (even though the TLS 1.0 option is selected). This will cause a "Firefox and <server> cannot communicate securely because they have no common encryption algorithms" (v1.5), or "Firefox can't connect to <server> because the site uses a security protocol which isn't enabled" (v2.0). See bugzilla issues 343543 and 359484 (Comment #7). It's all broken (hopefully fixed soon).\n* Perl/Java bindings don't work on 64 bit Linux machines. I can't even compile the latest version of Perl on an ~AMD64 box (using ~FC3).\n* Java 1.4 or better is required for the Java interfaces.\n* Processes that fork can't use session resumption unless some form of IPC is used.\n* Ensure libperl.so and libaxtls.so are in the shared library path when running with the perl bindings. A way to do this is with:\n\n{{indent{{{{> export LD_LIBRARY_PATH=`perl -e 'use Config; print $Config{archlib};'`/CORE:.}}}\n* The lua sample requires the luabit library from http://luaforge.net/projects/bit.\n\n!!!!Win32 issues\n\n* Be careful about doing .NET executions on network drives - .NET complains with security exceptions on the binary. //TODO: Add a manifest file to prevent this.//\n* CGI has been removed from Win32 - it needs a lot more work to get it right.\n* The default Microsoft .NET SDK is v2.0.50727. Download from: http://msdn.microsoft.com/netframework/downloads/updates/default.aspx.\n\n!!!!Solaris issues\n\n* mconf doesn't work well - some manual tweaking is required for string values.\n* GNU make is required and needs to be in $PATH.\n* To get swig's library dependencies to work (and for the C library to be found), I needed to type:\n\n{{indent{{{{> export LD_LIBRARY_PATH=/usr/local/gcc-3.3.1/lib:.}}}\n\n!!!!Cygwin issues\n\n* The bindings all compile but don't run under Cygwin with the exception of Perl. This is due to win32 executables being incompatible with Cygwin libraries.\n\n</div> -<div tiddler="SiteSubtitle" modifier="CameronRich" modified="200702240025" created="200702240025" tags="">changes, notes and errata</div> -<div tiddler="SiteTitle" modifier="CameronRich" modified="200702240023" created="200702240023" tags="">axTLS Embedded SSL</div> -<div tiddler="SiteUrl" modifier="CameronRich" modified="200702240025" created="200702240025" tags="">http://axtls.cerocclub.com.au</div> -<div tiddler="StyleSheet" modifier="CameronRich" modified="200702250600" created="200701122350" tags="DevFireTheme">/***\nhttp://tiddlystyles.com/#theme:DevFire\nAuthor: Clint Checketts\n***/\n\n/*{{{*/\nbody {\nbackground: #000;\n}\n/*}}}*/\n/***\n!Link styles /% ============================================================= %/\n***/\n/*{{{*/\na,\na.button,\n#mainMenu a.button,\n#sidebarOptions .sliderPanel a{\n color: #ffbf00;\n border: 0;\n background: transparent;\n}\n\na:hover,\na.button:hover,\n#mainMenu a.button:hover,\n#sidebarOptions .sliderPanel a:hover\n#sidebarOptions .sliderPanel a:active{\n color: #ff7f00;\n border: 0;\n border-bottom: #ff7f00 1px dashed;\n background: transparent;\n text-decoration: none;\n}\n\n#displayArea .button.highlight{\n color: #ffbf00;\n background: #4c4c4c;\n}\n/*}}}*/\n/***\n!Header styles /% ============================================================= %/\n***/\n/*{{{*/\n.header{\n border-bottom: 2px solid #ffbf00;\n color: #fff;\n}\n\n.headerForeground a {\n color: #fff;\n}\n\n.header a:hover {\n border-bottom: 1px dashed #fff;\n}\n/*}}}*/\n/***\n!Main menu styles /% ============================================================= %/\n***/\n/*{{{*/\n#mainMenu {color: #fff;}\n#mainMenu h1{\n font-size: 1.1em;\n}\n#mainMenu li,#mainMenu ul{\n list-style: none;\n margin: 0;\n padding: 0;\n}\n/*}}}*/\n/***\n!Sidebar styles /% ============================================================= %/\n***/\n/*{{{*/\n#sidebar {\n right: 0;\n color: #fff;\n border: 2px solid #ffbf00;\n border-width: 0 0 2px 2px;\n}\n#sidebarOptions {\n background-color: #4c4c4c;\n padding: 0;\n}\n\n#sidebarOptions a{\n margin: 0;\n color: #ffbf00;\n border: 0;\n}\n#sidebarOptions a:hover {\n color: #4c4c4c;\n background-color: #ffbf00;\n\n}\n\n#sidebarOptions a:active {\n color: #ffbf00;\n background-color: transparent;\n}\n\n#sidebarOptions .sliderPanel {\n background-color: #333;\n margin: 0;\n}\n\n#sidebarTabs {background-color: #4c4c4c;}\n#sidebarTabs .tabSelected {\n padding: 3px 3px;\n cursor: default;\n color: #ffbf00;\n background-color: #666;\n}\n#sidebarTabs .tabUnselected {\n color: #ffbf00;\n background-color: #5f5f5f;\n padding: 0 4px;\n}\n\n#sidebarTabs .tabUnselected:hover,\n#sidebarTabs .tabContents {\n background-color: #666;\n}\n\n.listTitle{color: #FFF;}\n#sidebarTabs .tabContents a{\n color: #ffbf00;\n}\n\n#sidebarTabs .tabContents a:hover{\n color: #ff7f00;\n background: transparent;\n}\n\n#sidebarTabs .txtMoreTab .tabSelected,\n#sidebarTabs .txtMoreTab .tab:hover,\n#sidebarTabs .txtMoreTab .tabContents{\n color: #ffbf00;\n background: #4c4c4c;\n}\n\n#sidebarTabs .txtMoreTab .tabUnselected {\n color: #ffbf00;\n background: #5f5f5f;\n}\n\n.tab.tabSelected, .tab.tabSelected:hover{color: #ffbf00; border: 0; background-color: #4c4c4c;cursor:default;}\n.tab.tabUnselected {background-color: #666;}\n.tab.tabUnselected:hover{color:#ffbf00; border: 0;background-color: #4c4c4c;}\n.tabContents {\n background-color: #4c4c4c;\n border: 0;\n}\n.tabContents .tabContents{background: #666;}\n.tabContents .tabSelected{background: #666;}\n.tabContents .tabUnselected{background: #5f5f5f;}\n.tabContents .tab:hover{background: #666;}\n/*}}}*/\n/***\n!Message area styles /% ============================================================= %/\n***/\n/*{{{*/\n#messageArea {background-color: #666; color: #fff; border: 2px solid #ffbf00;}\n#messageArea a:link, #messageArea a:visited {color: #ffbf00; text-decoration:none;}\n#messageArea a:hover {color: #ff7f00;}\n#messageArea a:active {color: #ff7f00;}\n#messageArea .messageToolbar a{\n border: 1px solid #ffbf00;\n background: #4c4c4c;\n}\n/*}}}*/\n/***\n!Popup styles /% ============================================================= %/\n***/\n/*{{{*/\n.popup {color: #fff; background-color: #4c4c4c; border: 1px solid #ffbf00;}\n.popup li.disabled{color: #fff;}\n.popup a {color: #ffbf00; }\n.popup a:hover { background: transparent; color: #ff7f00; border: 0;}\n.popup hr {color: #ffbf00; background: #ffbf00;}\n/*}}}*/\n/***\n!Tiddler Display styles /% ============================================================= %/\n***/\n/*{{{*/\n.title{color: #fff;}\nh1, h2, h3, h4, h5 {\n color: #fff;\n background-color: transparent;\n border-bottom: 1px solid #333;\n}\n\n.subtitle{\n color: #666;\n}\n\n.viewer {color: #fff; }\n\n.viewer table{background: #666; color: #fff;}\n\n.viewer th {background-color: #996; color: #fff;}\n\n.viewer pre, .viewer code {color: #ddd; background-color: #4c4c4c; border: 1px solid #ffbf00;}\n\n.viewer hr {color: #666;}\n\n.tiddler .button {color: #4c4c4c;}\n.tiddler .button:hover { color: #ffbf00; background-color: #4c4c4c;}\n.tiddler .button:active {color: #ffbf00; background-color: #4c4c4c;}\n\n.toolbar {\n color: #4c4c4c;\n}\n\n.toolbar a.button,\n.toolbar a.button:hover,\n.toolbar a.button:active,\n.editorFooter a{\n border: 0;\n}\n\n.footer {\n color: #ddd;\n}\n\n.selected .footer {\n color: #888;\n}\n\n.highlight, .marked {\n color: #000;\n background-color: #ffe72f;\n}\n.editorFooter {\n color: #aaa;\n}\n\n.tab{\n-moz-border-radius-topleft: 3px;\n-moz-border-radius-topright: 3px;\n}\n\n.tagging,\n.tagged{\n background: #4c4c4c;\n border: 1px solid #4c4c4c; \n}\n\n.selected .tagging,\n.selected .tagged{\n background-color: #333;\n border: 1px solid #ffbf00;\n}\n\n.tagging .listTitle,\n.tagged .listTitle{\n color: #fff;\n}\n\n.tagging .button,\n.tagged .button{\n color: #ffbf00;\n border: 0;\n padding: 0;\n}\n\n.tagging .button:hover,\n.tagged .button:hover{\nbackground: transparent;\n}\n\n.selected .isTag .tagging.simple,\n.selected .tagged.simple,\n.isTag .tagging.simple,\n.tagged.simple {\n float: none;\n display: inline;\n border: 0;\n background: transparent;\n color: #fff;\n margin: 0;\n}\n\n.cascade {\n background: #4c4c4c;\n color: #ddd;\n border: 1px solid #ffbf00;\n}\n/*}}}*/</div> -<div tiddler="axhttpd" modifier="YourName" modified="201106241105" created="200702242231" tags="">axhttpd is a small embedded web server using the axTLS library. It is based originally on the web server written by Doug Currie which is at http://www.hcsw.org/awhttpd.\n\n!@@bgcolor(#ff0000):color(#ffffff):axhttpd Features@@ \n\n!!__Basic Authentication__\n\nBasic Authentication uses a password file called ".htpasswd", in the directory to be protected. This file is formatted as the familiar colon-separated username/encrypted-password pair, records delimited by newlines. The protection does not carry over to subdirectories. The utility program htpasswd is included to help manually edit .htpasswd files.\n\nThe encryption of this password uses a proprietary algorithm due to the dependency of many crypt libraries on DES. An example is in [[/test_dir/no_http|https://localhost/test_dir/no_http]] (username 'abcd', password is '1234').\n\n//Note: This is an mconf enabled configuration option.//\n\n!!__SSL Protection__\n\nDirectories/files can be accessed using the 'http' or 'https' uri prefix. If normal http access for a directory needs to be disabled, then put "~SSLRequireSSL" into a '.htaccess' file in the directory to be protected. \n\nConversely, use "~SSLDenySSL" to deny access to directories via SSL.\n\nAn example is in [[/test_dir/no_http|http://localhost/test_dir/no_http]] and [[/test_dir/no_ssl|https://localhost/test_dir/no_ssl]].\n\nEntire directories can be denied access with a "Deny all" directive (regardless of SSL or authentication). An example is in [[/test_dir/bin|http://localhost/test_dir/bin]]\n\n!!__CGI__\n\nMost of the CGI 1.1 variables are now placed into the script environment and should work as normal.\n\n!!__Lua and Lua Pages__\n\nThis is a small scripting language gaining popularity in embedded applications due to its small footprint and fast speed.\n\nLua has been incorporated into the build, so simply select it and it will automatically install. Try pointing your browser at [[test_main.html|http://localhost/lua/test_main.html]] to see an example of Lua Pages.\n\n//Note: This is an mconf enabled configuration option.//\n\nThe readline development library may have to be downloaded: //yum install readline-devel//\n\n!!__Directory Listing__\n\nAn mconf option. Allow the files in directories to be displayed. An example is in [[/test_dir|http://localhost/test_dir]]\n\n!!__Other Features__\n\n* Timeout - HTTP 1.1 allows for persistent connections. This is the time allowed for this connection in seconds.\n* Daemon - Puts the process in daemon mode. \n* SSL session cache size - The size of the session cache (a heavily loaded server should maintain many sessions). A session will save on expensive SSL handshaking.\n\n</div> -</div> -<!--POST-BODY-START--> - -<!--POST-BODY-END--> - </body> -</html> |