diff options
Diffstat (limited to 'src/libstrongswan/plugins')
82 files changed, 15066 insertions, 0 deletions
diff --git a/src/libstrongswan/plugins/aes/Makefile.am b/src/libstrongswan/plugins/aes/Makefile.am new file mode 100644 index 000000000..e73040f27 --- /dev/null +++ b/src/libstrongswan/plugins/aes/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-aes.la + +libstrongswan_aes_la_SOURCES = aes_plugin.h aes_plugin.c aes_crypter.c aes_crypter.h +libstrongswan_aes_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/aes/aes_crypter.c b/src/libstrongswan/plugins/aes/aes_crypter.c new file mode 100644 index 000000000..f0c31cfa2 --- /dev/null +++ b/src/libstrongswan/plugins/aes/aes_crypter.c @@ -0,0 +1,1621 @@ +/* + * Copyright (C) 2001 Dr B. R. Gladman <brg@gladman.uk.net> + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "aes_crypter.h" + +/* + * The number of key schedule words for different block and key lengths + * allowing for method of computation which requires the length to be a + * multiple of the key length. This version of AES implementation supports + * all three keylengths 16, 24 and 32 bytes! + * + * Nk = 4 6 8 + * ------------- + * Nb = 4 | 60 60 64 + * 6 | 96 90 96 + * 8 | 120 120 120 + */ +#define AES_KS_LENGTH 120 +#define AES_RC_LENGTH 29 + +#define AES_BLOCK_SIZE 16 + +typedef struct private_aes_crypter_t private_aes_crypter_t; + +/** + * Class implementing the AES symmetric encryption algorithm. + * + * @ingroup crypters + */ +struct private_aes_crypter_t { + + /** + * Public part of this class. + */ + aes_crypter_t public; + + /** + * Number of words in the key input block. + */ + u_int32_t aes_Nkey; + + /** + * The number of cipher rounds. + */ + u_int32_t aes_Nrnd; + + /** + * The encryption key schedule. + */ + u_int32_t aes_e_key[AES_KS_LENGTH]; + + /** + * The decryption key schedule. + */ + u_int32_t aes_d_key[AES_KS_LENGTH]; + + /** + * Key size of this AES cypher object. + */ + u_int32_t key_size; + + /** + * Decrypts a block. + * + * No memory gets allocated. + * + * @param this calling object + * @param[in] in_blk block to decrypt + * @param[out] out_blk decrypted data are written to this location + */ + void (*decrypt_block) (const private_aes_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]); + + /** + * Encrypts a block. + * + * No memory gets allocated. + * + * @param this calling object + * @param[in] in_blk block to encrypt + * @param[out] out_blk encrypted data are written to this location + */ + void (*encrypt_block) (const private_aes_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]); +}; + + +/* ugly macro stuff */ + +/* 1. Define UNROLL for full loop unrolling in encryption and decryption. + * 2. Define PARTIAL_UNROLL to unroll two loops in encryption and decryption. + * 3. Define FIXED_TABLES for compiled rather than dynamic tables. + * 4. Define FF_TABLES to use tables for field multiplies and inverses. + * Do not enable this without understanding stack space requirements. + * 5. Define ARRAYS to use arrays to hold the local state block. If this + * is not defined, individually declared 32-bit words are used. + * 6. Define FAST_VARIABLE if a high speed variable block implementation + * is needed (essentially three separate fixed block size code sequences) + * 7. Define either ONE_TABLE or FOUR_TABLES for a fast table driven + * version using 1 table (2 kbytes of table space) or 4 tables (8 + * kbytes of table space) for higher speed. + * 8. Define either ONE_LR_TABLE or FOUR_LR_TABLES for a further speed + * increase by using tables for the last rounds but with more table + * space (2 or 8 kbytes extra). + * 9. If neither ONE_TABLE nor FOUR_TABLES is defined, a compact but + * slower version is provided. + * 10. If fast decryption key scheduling is needed define ONE_IM_TABLE + * or FOUR_IM_TABLES for higher speed (2 or 8 kbytes extra). + */ + +#define UNROLL +//#define PARTIAL_UNROLL + +#define FIXED_TABLES +//#define FF_TABLES +//#define ARRAYS +#define FAST_VARIABLE + +//#define ONE_TABLE +#define FOUR_TABLES + +//#define ONE_LR_TABLE +#define FOUR_LR_TABLES + +//#define ONE_IM_TABLE +#define FOUR_IM_TABLES + +#if defined(UNROLL) && defined (PARTIAL_UNROLL) +#error both UNROLL and PARTIAL_UNROLL are defined +#endif + +#if defined(ONE_TABLE) && defined (FOUR_TABLES) +#error both ONE_TABLE and FOUR_TABLES are defined +#endif + +#if defined(ONE_LR_TABLE) && defined (FOUR_LR_TABLES) +#error both ONE_LR_TABLE and FOUR_LR_TABLES are defined +#endif + +#if defined(ONE_IM_TABLE) && defined (FOUR_IM_TABLES) +#error both ONE_IM_TABLE and FOUR_IM_TABLES are defined +#endif + +#if defined(AES_BLOCK_SIZE) && AES_BLOCK_SIZE != 16 && AES_BLOCK_SIZE != 24 && AES_BLOCK_SIZE != 32 +#error an illegal block size has been specified +#endif + +/** + * Rotates bytes within words by n positions, moving bytes + * to higher index positions with wrap around into low positions. + */ +#define upr(x,n) (((x) << 8 * (n)) | ((x) >> (32 - 8 * (n)))) +/** + * Moves bytes by n positions to higher index positions in + * words but without wrap around. + */ +#define ups(x,n) ((x) << 8 * (n)) + +/** + * Extracts a byte from a word. + */ +#define bval(x,n) ((unsigned char)((x) >> 8 * (n))) +#define bytes2word(b0, b1, b2, b3) \ + ((u_int32_t)(b3) << 24 | (u_int32_t)(b2) << 16 | (u_int32_t)(b1) << 8 | (b0)) + + +/* little endian processor without data alignment restrictions: AES_LE_OK */ +/* original code: i386 */ +#if defined(i386) || defined(_I386) || defined(__i386__) || defined(__i386) +#define AES_LE_OK 1 +/* added (tested): alpha --jjo */ +#elif defined(__alpha__)|| defined (__alpha) +#define AES_LE_OK 1 +/* added (tested): ia64 --jjo */ +#elif defined(__ia64__)|| defined (__ia64) +#define AES_LE_OK 1 +#endif + +#ifdef AES_LE_OK +/* little endian processor without data alignment restrictions */ +#define word_in(x) *(u_int32_t*)(x) +#define const_word_in(x) *(const u_int32_t*)(x) +#define word_out(x,v) *(u_int32_t*)(x) = (v) +#define const_word_out(x,v) *(const u_int32_t*)(x) = (v) +#else +/* slower but generic big endian or with data alignment restrictions */ +/* some additional "const" touches to stop "gcc -Wcast-qual" complains --jjo */ +#define word_in(x) ((u_int32_t)(((unsigned char *)(x))[0])|((u_int32_t)(((unsigned char *)(x))[1])<<8)|((u_int32_t)(((unsigned char *)(x))[2])<<16)|((u_int32_t)(((unsigned char *)(x))[3])<<24)) +#define const_word_in(x) ((const u_int32_t)(((const unsigned char *)(x))[0])|((const u_int32_t)(((const unsigned char *)(x))[1])<<8)|((const u_int32_t)(((const unsigned char *)(x))[2])<<16)|((const u_int32_t)(((const unsigned char *)(x))[3])<<24)) +#define word_out(x,v) ((unsigned char *)(x))[0]=(v),((unsigned char *)(x))[1]=((v)>>8),((unsigned char *)(x))[2]=((v)>>16),((unsigned char *)(x))[3]=((v)>>24) +#define const_word_out(x,v) ((const unsigned char *)(x))[0]=(v),((const unsigned char *)(x))[1]=((v)>>8),((const unsigned char *)(x))[2]=((v)>>16),((const unsigned char *)(x))[3]=((v)>>24) +#endif + +// Disable at least some poor combinations of options + +#if !defined(ONE_TABLE) && !defined(FOUR_TABLES) +#define FIXED_TABLES +#undef UNROLL +#undef ONE_LR_TABLE +#undef FOUR_LR_TABLES +#undef ONE_IM_TABLE +#undef FOUR_IM_TABLES +#elif !defined(FOUR_TABLES) +#ifdef FOUR_LR_TABLES +#undef FOUR_LR_TABLES +#define ONE_LR_TABLE +#endif +#ifdef FOUR_IM_TABLES +#undef FOUR_IM_TABLES +#define ONE_IM_TABLE +#endif +#elif !defined(AES_BLOCK_SIZE) +#if defined(UNROLL) +#define PARTIAL_UNROLL +#undef UNROLL +#endif +#endif + +// the finite field modular polynomial and elements + +#define ff_poly 0x011b +#define ff_hi 0x80 + +// multiply four bytes in GF(2^8) by 'x' {02} in parallel + +#define m1 0x80808080 +#define m2 0x7f7f7f7f +#define m3 0x0000001b +#define FFmulX(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * m3)) + +// The following defines provide alternative definitions of FFmulX that might +// give improved performance if a fast 32-bit multiply is not available. Note +// that a temporary variable u needs to be defined where FFmulX is used. + +// #define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6)) +// #define m4 0x1b1b1b1b +// #define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4) + +// perform column mix operation on four bytes in parallel + +#define fwd_mcol(x) (f2 = FFmulX(x), f2 ^ upr(x ^ f2,3) ^ upr(x,2) ^ upr(x,1)) + +#if defined(FIXED_TABLES) + +// the S-Box table + +static const unsigned char s_box[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 +}; + +// the inverse S-Box table + +static const unsigned char inv_s_box[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 +}; + +#define w0(p) 0x000000##p + +// Number of elements required in this table for different +// block and key lengths is: +// +// Nk = 4 6 8 +// ---------- +// Nb = 4 | 10 8 7 +// 6 | 19 12 11 +// 8 | 29 19 14 +// +// this table can be a table of bytes if the key schedule +// code is adjusted accordingly + +static const u_int32_t rcon_tab[29] = +{ + w0(01), w0(02), w0(04), w0(08), + w0(10), w0(20), w0(40), w0(80), + w0(1b), w0(36), w0(6c), w0(d8), + w0(ab), w0(4d), w0(9a), w0(2f), + w0(5e), w0(bc), w0(63), w0(c6), + w0(97), w0(35), w0(6a), w0(d4), + w0(b3), w0(7d), w0(fa), w0(ef), + w0(c5) +}; + +#undef w0 + +#define r0(p,q,r,s) 0x##p##q##r##s +#define r1(p,q,r,s) 0x##q##r##s##p +#define r2(p,q,r,s) 0x##r##s##p##q +#define r3(p,q,r,s) 0x##s##p##q##r +#define w0(p) 0x000000##p +#define w1(p) 0x0000##p##00 +#define w2(p) 0x00##p##0000 +#define w3(p) 0x##p##000000 + +#if defined(FIXED_TABLES) && (defined(ONE_TABLE) || defined(FOUR_TABLES)) + +// data for forward tables (other than last round) + +#define f_table \ + r(a5,63,63,c6), r(84,7c,7c,f8), r(99,77,77,ee), r(8d,7b,7b,f6),\ + r(0d,f2,f2,ff), r(bd,6b,6b,d6), r(b1,6f,6f,de), r(54,c5,c5,91),\ + r(50,30,30,60), r(03,01,01,02), r(a9,67,67,ce), r(7d,2b,2b,56),\ + r(19,fe,fe,e7), r(62,d7,d7,b5), r(e6,ab,ab,4d), r(9a,76,76,ec),\ + r(45,ca,ca,8f), r(9d,82,82,1f), r(40,c9,c9,89), r(87,7d,7d,fa),\ + r(15,fa,fa,ef), r(eb,59,59,b2), r(c9,47,47,8e), r(0b,f0,f0,fb),\ + r(ec,ad,ad,41), r(67,d4,d4,b3), r(fd,a2,a2,5f), r(ea,af,af,45),\ + r(bf,9c,9c,23), r(f7,a4,a4,53), r(96,72,72,e4), r(5b,c0,c0,9b),\ + r(c2,b7,b7,75), r(1c,fd,fd,e1), r(ae,93,93,3d), r(6a,26,26,4c),\ + r(5a,36,36,6c), r(41,3f,3f,7e), r(02,f7,f7,f5), r(4f,cc,cc,83),\ + r(5c,34,34,68), r(f4,a5,a5,51), r(34,e5,e5,d1), r(08,f1,f1,f9),\ + r(93,71,71,e2), r(73,d8,d8,ab), r(53,31,31,62), r(3f,15,15,2a),\ + r(0c,04,04,08), r(52,c7,c7,95), r(65,23,23,46), r(5e,c3,c3,9d),\ + r(28,18,18,30), r(a1,96,96,37), r(0f,05,05,0a), r(b5,9a,9a,2f),\ + r(09,07,07,0e), r(36,12,12,24), r(9b,80,80,1b), r(3d,e2,e2,df),\ + r(26,eb,eb,cd), r(69,27,27,4e), r(cd,b2,b2,7f), r(9f,75,75,ea),\ + r(1b,09,09,12), r(9e,83,83,1d), r(74,2c,2c,58), r(2e,1a,1a,34),\ + r(2d,1b,1b,36), r(b2,6e,6e,dc), r(ee,5a,5a,b4), r(fb,a0,a0,5b),\ + r(f6,52,52,a4), r(4d,3b,3b,76), r(61,d6,d6,b7), r(ce,b3,b3,7d),\ + r(7b,29,29,52), r(3e,e3,e3,dd), r(71,2f,2f,5e), r(97,84,84,13),\ + r(f5,53,53,a6), r(68,d1,d1,b9), r(00,00,00,00), r(2c,ed,ed,c1),\ + r(60,20,20,40), r(1f,fc,fc,e3), r(c8,b1,b1,79), r(ed,5b,5b,b6),\ + r(be,6a,6a,d4), r(46,cb,cb,8d), r(d9,be,be,67), r(4b,39,39,72),\ + r(de,4a,4a,94), r(d4,4c,4c,98), r(e8,58,58,b0), r(4a,cf,cf,85),\ + r(6b,d0,d0,bb), r(2a,ef,ef,c5), r(e5,aa,aa,4f), r(16,fb,fb,ed),\ + r(c5,43,43,86), r(d7,4d,4d,9a), r(55,33,33,66), r(94,85,85,11),\ + r(cf,45,45,8a), r(10,f9,f9,e9), r(06,02,02,04), r(81,7f,7f,fe),\ + r(f0,50,50,a0), r(44,3c,3c,78), r(ba,9f,9f,25), r(e3,a8,a8,4b),\ + r(f3,51,51,a2), r(fe,a3,a3,5d), r(c0,40,40,80), r(8a,8f,8f,05),\ + r(ad,92,92,3f), r(bc,9d,9d,21), r(48,38,38,70), r(04,f5,f5,f1),\ + r(df,bc,bc,63), r(c1,b6,b6,77), r(75,da,da,af), r(63,21,21,42),\ + r(30,10,10,20), r(1a,ff,ff,e5), r(0e,f3,f3,fd), r(6d,d2,d2,bf),\ + r(4c,cd,cd,81), r(14,0c,0c,18), r(35,13,13,26), r(2f,ec,ec,c3),\ + r(e1,5f,5f,be), r(a2,97,97,35), r(cc,44,44,88), r(39,17,17,2e),\ + r(57,c4,c4,93), r(f2,a7,a7,55), r(82,7e,7e,fc), r(47,3d,3d,7a),\ + r(ac,64,64,c8), r(e7,5d,5d,ba), r(2b,19,19,32), r(95,73,73,e6),\ + r(a0,60,60,c0), r(98,81,81,19), r(d1,4f,4f,9e), r(7f,dc,dc,a3),\ + r(66,22,22,44), r(7e,2a,2a,54), r(ab,90,90,3b), r(83,88,88,0b),\ + r(ca,46,46,8c), r(29,ee,ee,c7), r(d3,b8,b8,6b), r(3c,14,14,28),\ + r(79,de,de,a7), r(e2,5e,5e,bc), r(1d,0b,0b,16), r(76,db,db,ad),\ + r(3b,e0,e0,db), r(56,32,32,64), r(4e,3a,3a,74), r(1e,0a,0a,14),\ + r(db,49,49,92), r(0a,06,06,0c), r(6c,24,24,48), r(e4,5c,5c,b8),\ + r(5d,c2,c2,9f), r(6e,d3,d3,bd), r(ef,ac,ac,43), r(a6,62,62,c4),\ + r(a8,91,91,39), r(a4,95,95,31), r(37,e4,e4,d3), r(8b,79,79,f2),\ + r(32,e7,e7,d5), r(43,c8,c8,8b), r(59,37,37,6e), r(b7,6d,6d,da),\ + r(8c,8d,8d,01), r(64,d5,d5,b1), r(d2,4e,4e,9c), r(e0,a9,a9,49),\ + r(b4,6c,6c,d8), r(fa,56,56,ac), r(07,f4,f4,f3), r(25,ea,ea,cf),\ + r(af,65,65,ca), r(8e,7a,7a,f4), r(e9,ae,ae,47), r(18,08,08,10),\ + r(d5,ba,ba,6f), r(88,78,78,f0), r(6f,25,25,4a), r(72,2e,2e,5c),\ + r(24,1c,1c,38), r(f1,a6,a6,57), r(c7,b4,b4,73), r(51,c6,c6,97),\ + r(23,e8,e8,cb), r(7c,dd,dd,a1), r(9c,74,74,e8), r(21,1f,1f,3e),\ + r(dd,4b,4b,96), r(dc,bd,bd,61), r(86,8b,8b,0d), r(85,8a,8a,0f),\ + r(90,70,70,e0), r(42,3e,3e,7c), r(c4,b5,b5,71), r(aa,66,66,cc),\ + r(d8,48,48,90), r(05,03,03,06), r(01,f6,f6,f7), r(12,0e,0e,1c),\ + r(a3,61,61,c2), r(5f,35,35,6a), r(f9,57,57,ae), r(d0,b9,b9,69),\ + r(91,86,86,17), r(58,c1,c1,99), r(27,1d,1d,3a), r(b9,9e,9e,27),\ + r(38,e1,e1,d9), r(13,f8,f8,eb), r(b3,98,98,2b), r(33,11,11,22),\ + r(bb,69,69,d2), r(70,d9,d9,a9), r(89,8e,8e,07), r(a7,94,94,33),\ + r(b6,9b,9b,2d), r(22,1e,1e,3c), r(92,87,87,15), r(20,e9,e9,c9),\ + r(49,ce,ce,87), r(ff,55,55,aa), r(78,28,28,50), r(7a,df,df,a5),\ + r(8f,8c,8c,03), r(f8,a1,a1,59), r(80,89,89,09), r(17,0d,0d,1a),\ + r(da,bf,bf,65), r(31,e6,e6,d7), r(c6,42,42,84), r(b8,68,68,d0),\ + r(c3,41,41,82), r(b0,99,99,29), r(77,2d,2d,5a), r(11,0f,0f,1e),\ + r(cb,b0,b0,7b), r(fc,54,54,a8), r(d6,bb,bb,6d), r(3a,16,16,2c) + +// data for inverse tables (other than last round) + +#define i_table \ + r(50,a7,f4,51), r(53,65,41,7e), r(c3,a4,17,1a), r(96,5e,27,3a),\ + r(cb,6b,ab,3b), r(f1,45,9d,1f), r(ab,58,fa,ac), r(93,03,e3,4b),\ + r(55,fa,30,20), r(f6,6d,76,ad), r(91,76,cc,88), r(25,4c,02,f5),\ + r(fc,d7,e5,4f), r(d7,cb,2a,c5), r(80,44,35,26), r(8f,a3,62,b5),\ + r(49,5a,b1,de), r(67,1b,ba,25), r(98,0e,ea,45), r(e1,c0,fe,5d),\ + r(02,75,2f,c3), r(12,f0,4c,81), r(a3,97,46,8d), r(c6,f9,d3,6b),\ + r(e7,5f,8f,03), r(95,9c,92,15), r(eb,7a,6d,bf), r(da,59,52,95),\ + r(2d,83,be,d4), r(d3,21,74,58), r(29,69,e0,49), r(44,c8,c9,8e),\ + r(6a,89,c2,75), r(78,79,8e,f4), r(6b,3e,58,99), r(dd,71,b9,27),\ + r(b6,4f,e1,be), r(17,ad,88,f0), r(66,ac,20,c9), r(b4,3a,ce,7d),\ + r(18,4a,df,63), r(82,31,1a,e5), r(60,33,51,97), r(45,7f,53,62),\ + r(e0,77,64,b1), r(84,ae,6b,bb), r(1c,a0,81,fe), r(94,2b,08,f9),\ + r(58,68,48,70), r(19,fd,45,8f), r(87,6c,de,94), r(b7,f8,7b,52),\ + r(23,d3,73,ab), r(e2,02,4b,72), r(57,8f,1f,e3), r(2a,ab,55,66),\ + r(07,28,eb,b2), r(03,c2,b5,2f), r(9a,7b,c5,86), r(a5,08,37,d3),\ + r(f2,87,28,30), r(b2,a5,bf,23), r(ba,6a,03,02), r(5c,82,16,ed),\ + r(2b,1c,cf,8a), r(92,b4,79,a7), r(f0,f2,07,f3), r(a1,e2,69,4e),\ + r(cd,f4,da,65), r(d5,be,05,06), r(1f,62,34,d1), r(8a,fe,a6,c4),\ + r(9d,53,2e,34), r(a0,55,f3,a2), r(32,e1,8a,05), r(75,eb,f6,a4),\ + r(39,ec,83,0b), r(aa,ef,60,40), r(06,9f,71,5e), r(51,10,6e,bd),\ + r(f9,8a,21,3e), r(3d,06,dd,96), r(ae,05,3e,dd), r(46,bd,e6,4d),\ + r(b5,8d,54,91), r(05,5d,c4,71), r(6f,d4,06,04), r(ff,15,50,60),\ + r(24,fb,98,19), r(97,e9,bd,d6), r(cc,43,40,89), r(77,9e,d9,67),\ + r(bd,42,e8,b0), r(88,8b,89,07), r(38,5b,19,e7), r(db,ee,c8,79),\ + r(47,0a,7c,a1), r(e9,0f,42,7c), r(c9,1e,84,f8), r(00,00,00,00),\ + r(83,86,80,09), r(48,ed,2b,32), r(ac,70,11,1e), r(4e,72,5a,6c),\ + r(fb,ff,0e,fd), r(56,38,85,0f), r(1e,d5,ae,3d), r(27,39,2d,36),\ + r(64,d9,0f,0a), r(21,a6,5c,68), r(d1,54,5b,9b), r(3a,2e,36,24),\ + r(b1,67,0a,0c), r(0f,e7,57,93), r(d2,96,ee,b4), r(9e,91,9b,1b),\ + r(4f,c5,c0,80), r(a2,20,dc,61), r(69,4b,77,5a), r(16,1a,12,1c),\ + r(0a,ba,93,e2), r(e5,2a,a0,c0), r(43,e0,22,3c), r(1d,17,1b,12),\ + r(0b,0d,09,0e), r(ad,c7,8b,f2), r(b9,a8,b6,2d), r(c8,a9,1e,14),\ + r(85,19,f1,57), r(4c,07,75,af), r(bb,dd,99,ee), r(fd,60,7f,a3),\ + r(9f,26,01,f7), r(bc,f5,72,5c), r(c5,3b,66,44), r(34,7e,fb,5b),\ + r(76,29,43,8b), r(dc,c6,23,cb), r(68,fc,ed,b6), r(63,f1,e4,b8),\ + r(ca,dc,31,d7), r(10,85,63,42), r(40,22,97,13), r(20,11,c6,84),\ + r(7d,24,4a,85), r(f8,3d,bb,d2), r(11,32,f9,ae), r(6d,a1,29,c7),\ + r(4b,2f,9e,1d), r(f3,30,b2,dc), r(ec,52,86,0d), r(d0,e3,c1,77),\ + r(6c,16,b3,2b), r(99,b9,70,a9), r(fa,48,94,11), r(22,64,e9,47),\ + r(c4,8c,fc,a8), r(1a,3f,f0,a0), r(d8,2c,7d,56), r(ef,90,33,22),\ + r(c7,4e,49,87), r(c1,d1,38,d9), r(fe,a2,ca,8c), r(36,0b,d4,98),\ + r(cf,81,f5,a6), r(28,de,7a,a5), r(26,8e,b7,da), r(a4,bf,ad,3f),\ + r(e4,9d,3a,2c), r(0d,92,78,50), r(9b,cc,5f,6a), r(62,46,7e,54),\ + r(c2,13,8d,f6), r(e8,b8,d8,90), r(5e,f7,39,2e), r(f5,af,c3,82),\ + r(be,80,5d,9f), r(7c,93,d0,69), r(a9,2d,d5,6f), r(b3,12,25,cf),\ + r(3b,99,ac,c8), r(a7,7d,18,10), r(6e,63,9c,e8), r(7b,bb,3b,db),\ + r(09,78,26,cd), r(f4,18,59,6e), r(01,b7,9a,ec), r(a8,9a,4f,83),\ + r(65,6e,95,e6), r(7e,e6,ff,aa), r(08,cf,bc,21), r(e6,e8,15,ef),\ + r(d9,9b,e7,ba), r(ce,36,6f,4a), r(d4,09,9f,ea), r(d6,7c,b0,29),\ + r(af,b2,a4,31), r(31,23,3f,2a), r(30,94,a5,c6), r(c0,66,a2,35),\ + r(37,bc,4e,74), r(a6,ca,82,fc), r(b0,d0,90,e0), r(15,d8,a7,33),\ + r(4a,98,04,f1), r(f7,da,ec,41), r(0e,50,cd,7f), r(2f,f6,91,17),\ + r(8d,d6,4d,76), r(4d,b0,ef,43), r(54,4d,aa,cc), r(df,04,96,e4),\ + r(e3,b5,d1,9e), r(1b,88,6a,4c), r(b8,1f,2c,c1), r(7f,51,65,46),\ + r(04,ea,5e,9d), r(5d,35,8c,01), r(73,74,87,fa), r(2e,41,0b,fb),\ + r(5a,1d,67,b3), r(52,d2,db,92), r(33,56,10,e9), r(13,47,d6,6d),\ + r(8c,61,d7,9a), r(7a,0c,a1,37), r(8e,14,f8,59), r(89,3c,13,eb),\ + r(ee,27,a9,ce), r(35,c9,61,b7), r(ed,e5,1c,e1), r(3c,b1,47,7a),\ + r(59,df,d2,9c), r(3f,73,f2,55), r(79,ce,14,18), r(bf,37,c7,73),\ + r(ea,cd,f7,53), r(5b,aa,fd,5f), r(14,6f,3d,df), r(86,db,44,78),\ + r(81,f3,af,ca), r(3e,c4,68,b9), r(2c,34,24,38), r(5f,40,a3,c2),\ + r(72,c3,1d,16), r(0c,25,e2,bc), r(8b,49,3c,28), r(41,95,0d,ff),\ + r(71,01,a8,39), r(de,b3,0c,08), r(9c,e4,b4,d8), r(90,c1,56,64),\ + r(61,84,cb,7b), r(70,b6,32,d5), r(74,5c,6c,48), r(42,57,b8,d0) + +// generate the required tables in the desired endian format + +#undef r +#define r r0 + +#if defined(ONE_TABLE) +static const u_int32_t ft_tab[256] = + { f_table }; +#elif defined(FOUR_TABLES) +static const u_int32_t ft_tab[4][256] = +{ { f_table }, +#undef r +#define r r1 + { f_table }, +#undef r +#define r r2 + { f_table }, +#undef r +#define r r3 + { f_table } +}; +#endif + +#undef r +#define r r0 +#if defined(ONE_TABLE) +static const u_int32_t it_tab[256] = + { i_table }; +#elif defined(FOUR_TABLES) +static const u_int32_t it_tab[4][256] = +{ { i_table }, +#undef r +#define r r1 + { i_table }, +#undef r +#define r r2 + { i_table }, +#undef r +#define r r3 + { i_table } +}; +#endif + +#endif + +#if defined(FIXED_TABLES) && (defined(ONE_LR_TABLE) || defined(FOUR_LR_TABLES)) + +// data for inverse tables (last round) + +#define li_table \ + w(52), w(09), w(6a), w(d5), w(30), w(36), w(a5), w(38),\ + w(bf), w(40), w(a3), w(9e), w(81), w(f3), w(d7), w(fb),\ + w(7c), w(e3), w(39), w(82), w(9b), w(2f), w(ff), w(87),\ + w(34), w(8e), w(43), w(44), w(c4), w(de), w(e9), w(cb),\ + w(54), w(7b), w(94), w(32), w(a6), w(c2), w(23), w(3d),\ + w(ee), w(4c), w(95), w(0b), w(42), w(fa), w(c3), w(4e),\ + w(08), w(2e), w(a1), w(66), w(28), w(d9), w(24), w(b2),\ + w(76), w(5b), w(a2), w(49), w(6d), w(8b), w(d1), w(25),\ + w(72), w(f8), w(f6), w(64), w(86), w(68), w(98), w(16),\ + w(d4), w(a4), w(5c), w(cc), w(5d), w(65), w(b6), w(92),\ + w(6c), w(70), w(48), w(50), w(fd), w(ed), w(b9), w(da),\ + w(5e), w(15), w(46), w(57), w(a7), w(8d), w(9d), w(84),\ + w(90), w(d8), w(ab), w(00), w(8c), w(bc), w(d3), w(0a),\ + w(f7), w(e4), w(58), w(05), w(b8), w(b3), w(45), w(06),\ + w(d0), w(2c), w(1e), w(8f), w(ca), w(3f), w(0f), w(02),\ + w(c1), w(af), w(bd), w(03), w(01), w(13), w(8a), w(6b),\ + w(3a), w(91), w(11), w(41), w(4f), w(67), w(dc), w(ea),\ + w(97), w(f2), w(cf), w(ce), w(f0), w(b4), w(e6), w(73),\ + w(96), w(ac), w(74), w(22), w(e7), w(ad), w(35), w(85),\ + w(e2), w(f9), w(37), w(e8), w(1c), w(75), w(df), w(6e),\ + w(47), w(f1), w(1a), w(71), w(1d), w(29), w(c5), w(89),\ + w(6f), w(b7), w(62), w(0e), w(aa), w(18), w(be), w(1b),\ + w(fc), w(56), w(3e), w(4b), w(c6), w(d2), w(79), w(20),\ + w(9a), w(db), w(c0), w(fe), w(78), w(cd), w(5a), w(f4),\ + w(1f), w(dd), w(a8), w(33), w(88), w(07), w(c7), w(31),\ + w(b1), w(12), w(10), w(59), w(27), w(80), w(ec), w(5f),\ + w(60), w(51), w(7f), w(a9), w(19), w(b5), w(4a), w(0d),\ + w(2d), w(e5), w(7a), w(9f), w(93), w(c9), w(9c), w(ef),\ + w(a0), w(e0), w(3b), w(4d), w(ae), w(2a), w(f5), w(b0),\ + w(c8), w(eb), w(bb), w(3c), w(83), w(53), w(99), w(61),\ + w(17), w(2b), w(04), w(7e), w(ba), w(77), w(d6), w(26),\ + w(e1), w(69), w(14), w(63), w(55), w(21), w(0c), w(7d), + +// generate the required tables in the desired endian format + +#undef r +#define r(p,q,r,s) w0(q) +#if defined(ONE_LR_TABLE) +static const u_int32_t fl_tab[256] = + { f_table }; +#elif defined(FOUR_LR_TABLES) +static const u_int32_t fl_tab[4][256] = +{ { f_table }, +#undef r +#define r(p,q,r,s) w1(q) + { f_table }, +#undef r +#define r(p,q,r,s) w2(q) + { f_table }, +#undef r +#define r(p,q,r,s) w3(q) + { f_table } +}; +#endif + +#undef w +#define w w0 +#if defined(ONE_LR_TABLE) +static const u_int32_t il_tab[256] = + { li_table }; +#elif defined(FOUR_LR_TABLES) +static const u_int32_t il_tab[4][256] = +{ { li_table }, +#undef w +#define w w1 + { li_table }, +#undef w +#define w w2 + { li_table }, +#undef w +#define w w3 + { li_table } +}; +#endif + +#endif + +#if defined(FIXED_TABLES) && (defined(ONE_IM_TABLE) || defined(FOUR_IM_TABLES)) + +#define m_table \ + r(00,00,00,00), r(0b,0d,09,0e), r(16,1a,12,1c), r(1d,17,1b,12),\ + r(2c,34,24,38), r(27,39,2d,36), r(3a,2e,36,24), r(31,23,3f,2a),\ + r(58,68,48,70), r(53,65,41,7e), r(4e,72,5a,6c), r(45,7f,53,62),\ + r(74,5c,6c,48), r(7f,51,65,46), r(62,46,7e,54), r(69,4b,77,5a),\ + r(b0,d0,90,e0), r(bb,dd,99,ee), r(a6,ca,82,fc), r(ad,c7,8b,f2),\ + r(9c,e4,b4,d8), r(97,e9,bd,d6), r(8a,fe,a6,c4), r(81,f3,af,ca),\ + r(e8,b8,d8,90), r(e3,b5,d1,9e), r(fe,a2,ca,8c), r(f5,af,c3,82),\ + r(c4,8c,fc,a8), r(cf,81,f5,a6), r(d2,96,ee,b4), r(d9,9b,e7,ba),\ + r(7b,bb,3b,db), r(70,b6,32,d5), r(6d,a1,29,c7), r(66,ac,20,c9),\ + r(57,8f,1f,e3), r(5c,82,16,ed), r(41,95,0d,ff), r(4a,98,04,f1),\ + r(23,d3,73,ab), r(28,de,7a,a5), r(35,c9,61,b7), r(3e,c4,68,b9),\ + r(0f,e7,57,93), r(04,ea,5e,9d), r(19,fd,45,8f), r(12,f0,4c,81),\ + r(cb,6b,ab,3b), r(c0,66,a2,35), r(dd,71,b9,27), r(d6,7c,b0,29),\ + r(e7,5f,8f,03), r(ec,52,86,0d), r(f1,45,9d,1f), r(fa,48,94,11),\ + r(93,03,e3,4b), r(98,0e,ea,45), r(85,19,f1,57), r(8e,14,f8,59),\ + r(bf,37,c7,73), r(b4,3a,ce,7d), r(a9,2d,d5,6f), r(a2,20,dc,61),\ + r(f6,6d,76,ad), r(fd,60,7f,a3), r(e0,77,64,b1), r(eb,7a,6d,bf),\ + r(da,59,52,95), r(d1,54,5b,9b), r(cc,43,40,89), r(c7,4e,49,87),\ + r(ae,05,3e,dd), r(a5,08,37,d3), r(b8,1f,2c,c1), r(b3,12,25,cf),\ + r(82,31,1a,e5), r(89,3c,13,eb), r(94,2b,08,f9), r(9f,26,01,f7),\ + r(46,bd,e6,4d), r(4d,b0,ef,43), r(50,a7,f4,51), r(5b,aa,fd,5f),\ + r(6a,89,c2,75), r(61,84,cb,7b), r(7c,93,d0,69), r(77,9e,d9,67),\ + r(1e,d5,ae,3d), r(15,d8,a7,33), r(08,cf,bc,21), r(03,c2,b5,2f),\ + r(32,e1,8a,05), r(39,ec,83,0b), r(24,fb,98,19), r(2f,f6,91,17),\ + r(8d,d6,4d,76), r(86,db,44,78), r(9b,cc,5f,6a), r(90,c1,56,64),\ + r(a1,e2,69,4e), r(aa,ef,60,40), r(b7,f8,7b,52), r(bc,f5,72,5c),\ + r(d5,be,05,06), r(de,b3,0c,08), r(c3,a4,17,1a), r(c8,a9,1e,14),\ + r(f9,8a,21,3e), r(f2,87,28,30), r(ef,90,33,22), r(e4,9d,3a,2c),\ + r(3d,06,dd,96), r(36,0b,d4,98), r(2b,1c,cf,8a), r(20,11,c6,84),\ + r(11,32,f9,ae), r(1a,3f,f0,a0), r(07,28,eb,b2), r(0c,25,e2,bc),\ + r(65,6e,95,e6), r(6e,63,9c,e8), r(73,74,87,fa), r(78,79,8e,f4),\ + r(49,5a,b1,de), r(42,57,b8,d0), r(5f,40,a3,c2), r(54,4d,aa,cc),\ + r(f7,da,ec,41), r(fc,d7,e5,4f), r(e1,c0,fe,5d), r(ea,cd,f7,53),\ + r(db,ee,c8,79), r(d0,e3,c1,77), r(cd,f4,da,65), r(c6,f9,d3,6b),\ + r(af,b2,a4,31), r(a4,bf,ad,3f), r(b9,a8,b6,2d), r(b2,a5,bf,23),\ + r(83,86,80,09), r(88,8b,89,07), r(95,9c,92,15), r(9e,91,9b,1b),\ + r(47,0a,7c,a1), r(4c,07,75,af), r(51,10,6e,bd), r(5a,1d,67,b3),\ + r(6b,3e,58,99), r(60,33,51,97), r(7d,24,4a,85), r(76,29,43,8b),\ + r(1f,62,34,d1), r(14,6f,3d,df), r(09,78,26,cd), r(02,75,2f,c3),\ + r(33,56,10,e9), r(38,5b,19,e7), r(25,4c,02,f5), r(2e,41,0b,fb),\ + r(8c,61,d7,9a), r(87,6c,de,94), r(9a,7b,c5,86), r(91,76,cc,88),\ + r(a0,55,f3,a2), r(ab,58,fa,ac), r(b6,4f,e1,be), r(bd,42,e8,b0),\ + r(d4,09,9f,ea), r(df,04,96,e4), r(c2,13,8d,f6), r(c9,1e,84,f8),\ + r(f8,3d,bb,d2), r(f3,30,b2,dc), r(ee,27,a9,ce), r(e5,2a,a0,c0),\ + r(3c,b1,47,7a), r(37,bc,4e,74), r(2a,ab,55,66), r(21,a6,5c,68),\ + r(10,85,63,42), r(1b,88,6a,4c), r(06,9f,71,5e), r(0d,92,78,50),\ + r(64,d9,0f,0a), r(6f,d4,06,04), r(72,c3,1d,16), r(79,ce,14,18),\ + r(48,ed,2b,32), r(43,e0,22,3c), r(5e,f7,39,2e), r(55,fa,30,20),\ + r(01,b7,9a,ec), r(0a,ba,93,e2), r(17,ad,88,f0), r(1c,a0,81,fe),\ + r(2d,83,be,d4), r(26,8e,b7,da), r(3b,99,ac,c8), r(30,94,a5,c6),\ + r(59,df,d2,9c), r(52,d2,db,92), r(4f,c5,c0,80), r(44,c8,c9,8e),\ + r(75,eb,f6,a4), r(7e,e6,ff,aa), r(63,f1,e4,b8), r(68,fc,ed,b6),\ + r(b1,67,0a,0c), r(ba,6a,03,02), r(a7,7d,18,10), r(ac,70,11,1e),\ + r(9d,53,2e,34), r(96,5e,27,3a), r(8b,49,3c,28), r(80,44,35,26),\ + r(e9,0f,42,7c), r(e2,02,4b,72), r(ff,15,50,60), r(f4,18,59,6e),\ + r(c5,3b,66,44), r(ce,36,6f,4a), r(d3,21,74,58), r(d8,2c,7d,56),\ + r(7a,0c,a1,37), r(71,01,a8,39), r(6c,16,b3,2b), r(67,1b,ba,25),\ + r(56,38,85,0f), r(5d,35,8c,01), r(40,22,97,13), r(4b,2f,9e,1d),\ + r(22,64,e9,47), r(29,69,e0,49), r(34,7e,fb,5b), r(3f,73,f2,55),\ + r(0e,50,cd,7f), r(05,5d,c4,71), r(18,4a,df,63), r(13,47,d6,6d),\ + r(ca,dc,31,d7), r(c1,d1,38,d9), r(dc,c6,23,cb), r(d7,cb,2a,c5),\ + r(e6,e8,15,ef), r(ed,e5,1c,e1), r(f0,f2,07,f3), r(fb,ff,0e,fd),\ + r(92,b4,79,a7), r(99,b9,70,a9), r(84,ae,6b,bb), r(8f,a3,62,b5),\ + r(be,80,5d,9f), r(b5,8d,54,91), r(a8,9a,4f,83), r(a3,97,46,8d) + +#undef r +#define r r0 + +#if defined(ONE_IM_TABLE) +static const u_int32_t im_tab[256] = + { m_table }; +#elif defined(FOUR_IM_TABLES) +static const u_int32_t im_tab[4][256] = +{ { m_table }, +#undef r +#define r r1 + { m_table }, +#undef r +#define r r2 + { m_table }, +#undef r +#define r r3 + { m_table } +}; +#endif + +#endif + +#else + +static int tab_gen = 0; + +static unsigned char s_box[256]; // the S box +static unsigned char inv_s_box[256]; // the inverse S box +static u_int32_t rcon_tab[AES_RC_LENGTH]; // table of round constants + +#if defined(ONE_TABLE) +static u_int32_t ft_tab[256]; +static u_int32_t it_tab[256]; +#elif defined(FOUR_TABLES) +static u_int32_t ft_tab[4][256]; +static u_int32_t it_tab[4][256]; +#endif + +#if defined(ONE_LR_TABLE) +static u_int32_t fl_tab[256]; +static u_int32_t il_tab[256]; +#elif defined(FOUR_LR_TABLES) +static u_int32_t fl_tab[4][256]; +static u_int32_t il_tab[4][256]; +#endif + +#if defined(ONE_IM_TABLE) +static u_int32_t im_tab[256]; +#elif defined(FOUR_IM_TABLES) +static u_int32_t im_tab[4][256]; +#endif + +// Generate the tables for the dynamic table option + +#if !defined(FF_TABLES) + +// It will generally be sensible to use tables to compute finite +// field multiplies and inverses but where memory is scarse this +// code might sometimes be better. + +// return 2 ^ (n - 1) where n is the bit number of the highest bit +// set in x with x in the range 1 < x < 0x00000200. This form is +// used so that locals within FFinv can be bytes rather than words + +static unsigned char hibit(const u_int32_t x) +{ unsigned char r = (unsigned char)((x >> 1) | (x >> 2)); + + r |= (r >> 2); + r |= (r >> 4); + return (r + 1) >> 1; +} + +// return the inverse of the finite field element x + +static unsigned char FFinv(const unsigned char x) +{ unsigned char p1 = x, p2 = 0x1b, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + + if(x < 2) return x; + + for(;;) + { + if(!n1) return v1; + + while(n2 >= n1) + { + n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2); + } + + if(!n2) return v2; + + while(n1 >= n2) + { + n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1); + } + } +} + +// define the finite field multiplies required for Rijndael + +#define FFmul02(x) ((((x) & 0x7f) << 1) ^ ((x) & 0x80 ? 0x1b : 0)) +#define FFmul03(x) ((x) ^ FFmul02(x)) +#define FFmul09(x) ((x) ^ FFmul02(FFmul02(FFmul02(x)))) +#define FFmul0b(x) ((x) ^ FFmul02((x) ^ FFmul02(FFmul02(x)))) +#define FFmul0d(x) ((x) ^ FFmul02(FFmul02((x) ^ FFmul02(x)))) +#define FFmul0e(x) FFmul02((x) ^ FFmul02((x) ^ FFmul02(x))) + +#else + +#define FFinv(x) ((x) ? pow[255 - log[x]]: 0) + +#define FFmul02(x) (x ? pow[log[x] + 0x19] : 0) +#define FFmul03(x) (x ? pow[log[x] + 0x01] : 0) +#define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0) +#define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0) +#define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0) +#define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0) + +#endif + +// The forward and inverse affine transformations used in the S-box + +#define fwd_affine(x) \ + (w = (u_int32_t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(unsigned char)(w^(w>>8))) + +#define inv_affine(x) \ + (w = (u_int32_t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(unsigned char)(w^(w>>8))) + +static void gen_tabs(void) +{ u_int32_t i, w; + +#if defined(FF_TABLES) + + unsigned char pow[512], log[256]; + + // log and power tables for GF(2^8) finite field with + // 0x011b as modular polynomial - the simplest primitive + // root is 0x03, used here to generate the tables + + i = 0; w = 1; + do + { + pow[i] = (unsigned char)w; + pow[i + 255] = (unsigned char)w; + log[w] = (unsigned char)i++; + w ^= (w << 1) ^ (w & ff_hi ? ff_poly : 0); + } + while (w != 1); + +#endif + + for(i = 0, w = 1; i < AES_RC_LENGTH; ++i) + { + rcon_tab[i] = bytes2word(w, 0, 0, 0); + w = (w << 1) ^ (w & ff_hi ? ff_poly : 0); + } + + for(i = 0; i < 256; ++i) + { unsigned char b; + + s_box[i] = b = fwd_affine(FFinv((unsigned char)i)); + + w = bytes2word(b, 0, 0, 0); +#if defined(ONE_LR_TABLE) + fl_tab[i] = w; +#elif defined(FOUR_LR_TABLES) + fl_tab[0][i] = w; + fl_tab[1][i] = upr(w,1); + fl_tab[2][i] = upr(w,2); + fl_tab[3][i] = upr(w,3); +#endif + w = bytes2word(FFmul02(b), b, b, FFmul03(b)); +#if defined(ONE_TABLE) + ft_tab[i] = w; +#elif defined(FOUR_TABLES) + ft_tab[0][i] = w; + ft_tab[1][i] = upr(w,1); + ft_tab[2][i] = upr(w,2); + ft_tab[3][i] = upr(w,3); +#endif + inv_s_box[i] = b = FFinv(inv_affine((unsigned char)i)); + + w = bytes2word(b, 0, 0, 0); +#if defined(ONE_LR_TABLE) + il_tab[i] = w; +#elif defined(FOUR_LR_TABLES) + il_tab[0][i] = w; + il_tab[1][i] = upr(w,1); + il_tab[2][i] = upr(w,2); + il_tab[3][i] = upr(w,3); +#endif + w = bytes2word(FFmul0e(b), FFmul09(b), FFmul0d(b), FFmul0b(b)); +#if defined(ONE_TABLE) + it_tab[i] = w; +#elif defined(FOUR_TABLES) + it_tab[0][i] = w; + it_tab[1][i] = upr(w,1); + it_tab[2][i] = upr(w,2); + it_tab[3][i] = upr(w,3); +#endif +#if defined(ONE_IM_TABLE) + im_tab[b] = w; +#elif defined(FOUR_IM_TABLES) + im_tab[0][b] = w; + im_tab[1][b] = upr(w,1); + im_tab[2][b] = upr(w,2); + im_tab[3][b] = upr(w,3); +#endif + + } +} + +#endif + +#define no_table(x,box,vf,rf,c) bytes2word( \ + box[bval(vf(x,0,c),rf(0,c))], \ + box[bval(vf(x,1,c),rf(1,c))], \ + box[bval(vf(x,2,c),rf(2,c))], \ + box[bval(vf(x,3,c),rf(3,c))]) + +#define one_table(x,op,tab,vf,rf,c) \ + ( tab[bval(vf(x,0,c),rf(0,c))] \ + ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ + ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ + ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) + +#define four_tables(x,tab,vf,rf,c) \ + ( tab[0][bval(vf(x,0,c),rf(0,c))] \ + ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ + ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ + ^ tab[3][bval(vf(x,3,c),rf(3,c))]) + +#define vf1(x,r,c) (x) +#define rf1(r,c) (r) +#define rf2(r,c) ((r-c)&3) + +#if defined(FOUR_LR_TABLES) +#define ls_box(x,c) four_tables(x,fl_tab,vf1,rf2,c) +#elif defined(ONE_LR_TABLE) +#define ls_box(x,c) one_table(x,upr,fl_tab,vf1,rf2,c) +#else +#define ls_box(x,c) no_table(x,s_box,vf1,rf2,c) +#endif + +#if defined(FOUR_IM_TABLES) +#define inv_mcol(x) four_tables(x,im_tab,vf1,rf1,0) +#elif defined(ONE_IM_TABLE) +#define inv_mcol(x) one_table(x,upr,im_tab,vf1,rf1,0) +#else +#define inv_mcol(x) \ + (f9 = (x),f2 = FFmulX(f9), f4 = FFmulX(f2), f8 = FFmulX(f4), f9 ^= f8, \ + f2 ^= f4 ^ f8 ^ upr(f2 ^ f9,3) ^ upr(f4 ^ f9,2) ^ upr(f9,1)) +#endif + +#define nc (AES_BLOCK_SIZE/4) + +// Initialise the key schedule from the user supplied key. The key +// length is now specified in bytes - 16, 24 or 32 as appropriate. +// This corresponds to bit lengths of 128, 192 and 256 bits, and +// to Nk values of 4, 6 and 8 respectively. + +#define mx(t,f) (*t++ = inv_mcol(*f),f++) +#define cp(t,f) *t++ = *f++ + +#if AES_BLOCK_SIZE == 16 +#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s) +#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s) +#elif AES_BLOCK_SIZE == 24 +#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s); \ + cp(d,s); cp(d,s) +#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s); \ + mx(d,s); mx(d,s) +#elif AES_BLOCK_SIZE == 32 +#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s); \ + cp(d,s); cp(d,s); cp(d,s); cp(d,s) +#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s); \ + mx(d,s); mx(d,s); mx(d,s); mx(d,s) +#else + +#define cpy(d,s) \ +switch(nc) \ +{ case 8: cp(d,s); cp(d,s); \ + case 6: cp(d,s); cp(d,s); \ + case 4: cp(d,s); cp(d,s); \ + cp(d,s); cp(d,s); \ +} + +#define mix(d,s) \ +switch(nc) \ +{ case 8: mx(d,s); mx(d,s); \ + case 6: mx(d,s); mx(d,s); \ + case 4: mx(d,s); mx(d,s); \ + mx(d,s); mx(d,s); \ +} + +#endif + +// y = output word, x = input word, r = row, c = column +// for r = 0, 1, 2 and 3 = column accessed for row r + +#if defined(ARRAYS) +#define s(x,c) x[c] +#else +#define s(x,c) x##c +#endif + +// I am grateful to Frank Yellin for the following constructions +// which, given the column (c) of the output state variable that +// is being computed, return the input state variables which are +// needed for each row (r) of the state + +// For the fixed block size options, compilers reduce these two +// expressions to fixed variable references. For variable block +// size code conditional clauses will sometimes be returned + +#define unused 77 // Sunset Strip + +#define fwd_var(x,r,c) \ + ( r==0 ? \ + ( c==0 ? s(x,0) \ + : c==1 ? s(x,1) \ + : c==2 ? s(x,2) \ + : c==3 ? s(x,3) \ + : c==4 ? s(x,4) \ + : c==5 ? s(x,5) \ + : c==6 ? s(x,6) \ + : s(x,7)) \ + : r==1 ? \ + ( c==0 ? s(x,1) \ + : c==1 ? s(x,2) \ + : c==2 ? s(x,3) \ + : c==3 ? nc==4 ? s(x,0) : s(x,4) \ + : c==4 ? s(x,5) \ + : c==5 ? nc==8 ? s(x,6) : s(x,0) \ + : c==6 ? s(x,7) \ + : s(x,0)) \ + : r==2 ? \ + ( c==0 ? nc==8 ? s(x,3) : s(x,2) \ + : c==1 ? nc==8 ? s(x,4) : s(x,3) \ + : c==2 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \ + : c==3 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \ + : c==4 ? nc==8 ? s(x,7) : s(x,0) \ + : c==5 ? nc==8 ? s(x,0) : s(x,1) \ + : c==6 ? s(x,1) \ + : s(x,2)) \ + : \ + ( c==0 ? nc==8 ? s(x,4) : s(x,3) \ + : c==1 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \ + : c==2 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \ + : c==3 ? nc==4 ? s(x,2) : nc==8 ? s(x,7) : s(x,0) \ + : c==4 ? nc==8 ? s(x,0) : s(x,1) \ + : c==5 ? nc==8 ? s(x,1) : s(x,2) \ + : c==6 ? s(x,2) \ + : s(x,3))) + +#define inv_var(x,r,c) \ + ( r==0 ? \ + ( c==0 ? s(x,0) \ + : c==1 ? s(x,1) \ + : c==2 ? s(x,2) \ + : c==3 ? s(x,3) \ + : c==4 ? s(x,4) \ + : c==5 ? s(x,5) \ + : c==6 ? s(x,6) \ + : s(x,7)) \ + : r==1 ? \ + ( c==0 ? nc==4 ? s(x,3) : nc==8 ? s(x,7) : s(x,5) \ + : c==1 ? s(x,0) \ + : c==2 ? s(x,1) \ + : c==3 ? s(x,2) \ + : c==4 ? s(x,3) \ + : c==5 ? s(x,4) \ + : c==6 ? s(x,5) \ + : s(x,6)) \ + : r==2 ? \ + ( c==0 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \ + : c==1 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \ + : c==2 ? nc==8 ? s(x,7) : s(x,0) \ + : c==3 ? nc==8 ? s(x,0) : s(x,1) \ + : c==4 ? nc==8 ? s(x,1) : s(x,2) \ + : c==5 ? nc==8 ? s(x,2) : s(x,3) \ + : c==6 ? s(x,3) \ + : s(x,4)) \ + : \ + ( c==0 ? nc==4 ? s(x,1) : nc==8 ? s(x,4) : s(x,3) \ + : c==1 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \ + : c==2 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \ + : c==3 ? nc==8 ? s(x,7) : s(x,0) \ + : c==4 ? nc==8 ? s(x,0) : s(x,1) \ + : c==5 ? nc==8 ? s(x,1) : s(x,2) \ + : c==6 ? s(x,2) \ + : s(x,3))) + +#define si(y,x,k,c) s(y,c) = const_word_in(x + 4 * c) ^ k[c] +#define so(y,x,c) word_out(y + 4 * c, s(x,c)) + +#if defined(FOUR_TABLES) +#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,ft_tab,fwd_var,rf1,c) +#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,it_tab,inv_var,rf1,c) +#elif defined(ONE_TABLE) +#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,ft_tab,fwd_var,rf1,c) +#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,it_tab,inv_var,rf1,c) +#else +#define fwd_rnd(y,x,k,c) s(y,c) = fwd_mcol(no_table(x,s_box,fwd_var,rf1,c)) ^ (k)[c] +#define inv_rnd(y,x,k,c) s(y,c) = inv_mcol(no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c]) +#endif + +#if defined(FOUR_LR_TABLES) +#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,fl_tab,fwd_var,rf1,c) +#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,il_tab,inv_var,rf1,c) +#elif defined(ONE_LR_TABLE) +#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,fl_tab,fwd_var,rf1,c) +#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,il_tab,inv_var,rf1,c) +#else +#define fwd_lrnd(y,x,k,c) s(y,c) = no_table(x,s_box,fwd_var,rf1,c) ^ (k)[c] +#define inv_lrnd(y,x,k,c) s(y,c) = no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c] +#endif + +#if AES_BLOCK_SIZE == 16 + +#if defined(ARRAYS) +#define locals(y,x) x[4],y[4] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3 +// the following defines prevent the compiler requiring the declaration +// of generated but unused variables in the fwd_var and inv_var macros +#define b04 unused +#define b05 unused +#define b06 unused +#define b07 unused +#define b14 unused +#define b15 unused +#define b16 unused +#define b17 unused +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) + +#elif AES_BLOCK_SIZE == 24 + +#if defined(ARRAYS) +#define locals(y,x) x[6],y[6] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5, \ + y##0,y##1,y##2,y##3,y##4,y##5 +#define b06 unused +#define b07 unused +#define b16 unused +#define b17 unused +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); \ + s(y,4) = s(x,4); s(y,5) = s(x,5); +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \ + si(y,x,k,3); si(y,x,k,4); si(y,x,k,5) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); \ + so(y,x,3); so(y,x,4); so(y,x,5) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \ + rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5) +#else + +#if defined(ARRAYS) +#define locals(y,x) x[8],y[8] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5,x##6,x##7, \ + y##0,y##1,y##2,y##3,y##4,y##5,y##6,y##7 +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); \ + s(y,4) = s(x,4); s(y,5) = s(x,5); \ + s(y,6) = s(x,6); s(y,7) = s(x,7); + +#if AES_BLOCK_SIZE == 32 + +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); \ + si(y,x,k,4); si(y,x,k,5); si(y,x,k,6); si(y,x,k,7) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); \ + so(y,x,4); so(y,x,5); so(y,x,6); so(y,x,7) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); \ + rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6); rm(y,x,k,7) +#else + +#define state_in(y,x,k) \ +switch(nc) \ +{ case 8: si(y,x,k,7); si(y,x,k,6); \ + case 6: si(y,x,k,5); si(y,x,k,4); \ + case 4: si(y,x,k,3); si(y,x,k,2); \ + si(y,x,k,1); si(y,x,k,0); \ +} + +#define state_out(y,x) \ +switch(nc) \ +{ case 8: so(y,x,7); so(y,x,6); \ + case 6: so(y,x,5); so(y,x,4); \ + case 4: so(y,x,3); so(y,x,2); \ + so(y,x,1); so(y,x,0); \ +} + +#if defined(FAST_VARIABLE) + +#define round(rm,y,x,k) \ +switch(nc) \ +{ case 8: rm(y,x,k,7); rm(y,x,k,6); \ + rm(y,x,k,5); rm(y,x,k,4); \ + rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ + case 6: rm(y,x,k,5); rm(y,x,k,4); \ + rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ + case 4: rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ +} +#else + +#define round(rm,y,x,k) \ +switch(nc) \ +{ case 8: rm(y,x,k,7); rm(y,x,k,6); \ + case 6: rm(y,x,k,5); rm(y,x,k,4); \ + case 4: rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ +} + +#endif + +#endif +#endif + +/** + * Implementation of private_aes_crypter_t.encrypt_block. + */ +static void encrypt_block(const private_aes_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]) +{ u_int32_t locals(b0, b1); + const u_int32_t *kp = this->aes_e_key; + +#if !defined(ONE_TABLE) && !defined(FOUR_TABLES) + u_int32_t f2; +#endif + + state_in(b0, in_blk, kp); kp += nc; + +#if defined(UNROLL) + + switch(this->aes_Nrnd) + { + case 14: round(fwd_rnd, b1, b0, kp ); + round(fwd_rnd, b0, b1, kp + nc ); kp += 2 * nc; + case 12: round(fwd_rnd, b1, b0, kp ); + round(fwd_rnd, b0, b1, kp + nc ); kp += 2 * nc; + case 10: round(fwd_rnd, b1, b0, kp ); + round(fwd_rnd, b0, b1, kp + nc); + round(fwd_rnd, b1, b0, kp + 2 * nc); + round(fwd_rnd, b0, b1, kp + 3 * nc); + round(fwd_rnd, b1, b0, kp + 4 * nc); + round(fwd_rnd, b0, b1, kp + 5 * nc); + round(fwd_rnd, b1, b0, kp + 6 * nc); + round(fwd_rnd, b0, b1, kp + 7 * nc); + round(fwd_rnd, b1, b0, kp + 8 * nc); + round(fwd_lrnd, b0, b1, kp + 9 * nc); + } + +#elif defined(PARTIAL_UNROLL) + { u_int32_t rnd; + + for(rnd = 0; rnd < (this->aes_Nrnd >> 1) - 1; ++rnd) + { + round(fwd_rnd, b1, b0, kp); + round(fwd_rnd, b0, b1, kp + nc); kp += 2 * nc; + } + + round(fwd_rnd, b1, b0, kp); + round(fwd_lrnd, b0, b1, kp + nc); + } +#else + { u_int32_t rnd; + + for(rnd = 0; rnd < this->aes_Nrnd - 1; ++rnd) + { + round(fwd_rnd, b1, b0, kp); + l_copy(b0, b1); kp += nc; + } + + round(fwd_lrnd, b0, b1, kp); + } +#endif + + state_out(out_blk, b0); +} + +/** + * Implementation of private_aes_crypter_t.decrypt_block. + */ +static void decrypt_block(const private_aes_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]) +{ u_int32_t locals(b0, b1); + const u_int32_t *kp = this->aes_d_key; + +#if !defined(ONE_TABLE) && !defined(FOUR_TABLES) + u_int32_t f2, f4, f8, f9; +#endif + + state_in(b0, in_blk, kp); kp += nc; + +#if defined(UNROLL) + + switch(this->aes_Nrnd) + { + case 14: round(inv_rnd, b1, b0, kp ); + round(inv_rnd, b0, b1, kp + nc ); kp += 2 * nc; + case 12: round(inv_rnd, b1, b0, kp ); + round(inv_rnd, b0, b1, kp + nc ); kp += 2 * nc; + case 10: round(inv_rnd, b1, b0, kp ); + round(inv_rnd, b0, b1, kp + nc); + round(inv_rnd, b1, b0, kp + 2 * nc); + round(inv_rnd, b0, b1, kp + 3 * nc); + round(inv_rnd, b1, b0, kp + 4 * nc); + round(inv_rnd, b0, b1, kp + 5 * nc); + round(inv_rnd, b1, b0, kp + 6 * nc); + round(inv_rnd, b0, b1, kp + 7 * nc); + round(inv_rnd, b1, b0, kp + 8 * nc); + round(inv_lrnd, b0, b1, kp + 9 * nc); + } + +#elif defined(PARTIAL_UNROLL) + { u_int32_t rnd; + + for(rnd = 0; rnd < (this->aes_Nrnd >> 1) - 1; ++rnd) + { + round(inv_rnd, b1, b0, kp); + round(inv_rnd, b0, b1, kp + nc); kp += 2 * nc; + } + + round(inv_rnd, b1, b0, kp); + round(inv_lrnd, b0, b1, kp + nc); + } +#else + { u_int32_t rnd; + + for(rnd = 0; rnd < this->aes_Nrnd - 1; ++rnd) + { + round(inv_rnd, b1, b0, kp); + l_copy(b0, b1); kp += nc; + } + + round(inv_lrnd, b0, b1, kp); + } +#endif + + state_out(out_blk, b0); +} + +/** + * Implementation of crypter_t.decrypt. + */ +static status_t decrypt (private_aes_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) +{ + int ret, pos; + const u_int32_t *iv_i; + u_int8_t *in, *out; + + ret = data.len; + if (((data.len) % 16) != 0) + { + /* data length must be padded to a multiple of blocksize */ + return INVALID_ARG; + } + + decrypted->ptr = malloc(data.len); + if (decrypted->ptr == NULL) + { + return OUT_OF_RES; + } + decrypted->len = data.len; + + in = data.ptr; + out = decrypted->ptr; + + pos=data.len-16; + in+=pos; + out+=pos; + while(pos>=0) { + this->decrypt_block(this,in,out); + if (pos==0) + iv_i=(const u_int32_t*) (iv.ptr); + else + iv_i=(const u_int32_t*) (in-16); + *((u_int32_t *)(&out[ 0])) ^= iv_i[0]; + *((u_int32_t *)(&out[ 4])) ^= iv_i[1]; + *((u_int32_t *)(&out[ 8])) ^= iv_i[2]; + *((u_int32_t *)(&out[12])) ^= iv_i[3]; + in-=16; + out-=16; + pos-=16; + } + + return SUCCESS; +} + + +/** + * Implementation of crypter_t.decrypt. + */ +static status_t encrypt (private_aes_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) +{ + int ret, pos; + const u_int32_t *iv_i; + u_int8_t *in, *out; + + ret = data.len; + if (((data.len) % 16) != 0) + { + /* data length must be padded to a multiple of blocksize */ + return INVALID_ARG; + } + + encrypted->ptr = malloc(data.len); + if (encrypted->ptr == NULL) + { + return OUT_OF_RES; + } + encrypted->len = data.len; + + in = data.ptr; + out = encrypted->ptr; + + pos=0; + while(pos<data.len) + { + if (pos==0) + iv_i=(const u_int32_t*) iv.ptr; + else + iv_i=(const u_int32_t*) (out-16); + *((u_int32_t *)(&out[ 0])) = iv_i[0]^*((const u_int32_t *)(&in[ 0])); + *((u_int32_t *)(&out[ 4])) = iv_i[1]^*((const u_int32_t *)(&in[ 4])); + *((u_int32_t *)(&out[ 8])) = iv_i[2]^*((const u_int32_t *)(&in[ 8])); + *((u_int32_t *)(&out[12])) = iv_i[3]^*((const u_int32_t *)(&in[12])); + this->encrypt_block(this,out,out); + in+=16; + out+=16; + pos+=16; + } + return SUCCESS; +} + +/** + * Implementation of crypter_t.get_block_size. + */ +static size_t get_block_size (private_aes_crypter_t *this) +{ + return AES_BLOCK_SIZE; +} + +/** + * Implementation of crypter_t.get_key_size. + */ +static size_t get_key_size (private_aes_crypter_t *this) +{ + return this->key_size; +} + +/** + * Implementation of crypter_t.set_key. + */ +static status_t set_key (private_aes_crypter_t *this, chunk_t key) +{ + u_int32_t *kf, *kt, rci, f = 0; + u_int8_t *in_key = key.ptr; + + if (key.len != this->key_size) + { + return INVALID_ARG; + } + + this->aes_Nrnd = (this->aes_Nkey > (nc) ? this->aes_Nkey : (nc)) + 6; + + this->aes_e_key[0] = const_word_in(in_key ); + this->aes_e_key[1] = const_word_in(in_key + 4); + this->aes_e_key[2] = const_word_in(in_key + 8); + this->aes_e_key[3] = const_word_in(in_key + 12); + + kf = this->aes_e_key; + kt = kf + nc * (this->aes_Nrnd + 1) - this->aes_Nkey; + rci = 0; + + switch(this->aes_Nkey) + { + case 4: do + { kf[4] = kf[0] ^ ls_box(kf[3],3) ^ rcon_tab[rci++]; + kf[5] = kf[1] ^ kf[4]; + kf[6] = kf[2] ^ kf[5]; + kf[7] = kf[3] ^ kf[6]; + kf += 4; + } + while(kf < kt); + break; + + case 6: this->aes_e_key[4] = const_word_in(in_key + 16); + this->aes_e_key[5] = const_word_in(in_key + 20); + do + { kf[ 6] = kf[0] ^ ls_box(kf[5],3) ^ rcon_tab[rci++]; + kf[ 7] = kf[1] ^ kf[ 6]; + kf[ 8] = kf[2] ^ kf[ 7]; + kf[ 9] = kf[3] ^ kf[ 8]; + kf[10] = kf[4] ^ kf[ 9]; + kf[11] = kf[5] ^ kf[10]; + kf += 6; + } + while(kf < kt); + break; + + case 8: this->aes_e_key[4] = const_word_in(in_key + 16); + this->aes_e_key[5] = const_word_in(in_key + 20); + this->aes_e_key[6] = const_word_in(in_key + 24); + this->aes_e_key[7] = const_word_in(in_key + 28); + do + { kf[ 8] = kf[0] ^ ls_box(kf[7],3) ^ rcon_tab[rci++]; + kf[ 9] = kf[1] ^ kf[ 8]; + kf[10] = kf[2] ^ kf[ 9]; + kf[11] = kf[3] ^ kf[10]; + kf[12] = kf[4] ^ ls_box(kf[11],0); + kf[13] = kf[5] ^ kf[12]; + kf[14] = kf[6] ^ kf[13]; + kf[15] = kf[7] ^ kf[14]; + kf += 8; + } + while (kf < kt); + break; + } + + if(!f) + { + u_int32_t i; + + kt = this->aes_d_key + nc * this->aes_Nrnd; + kf = this->aes_e_key; + + cpy(kt, kf); kt -= 2 * nc; + + for(i = 1; i < this->aes_Nrnd; ++i) + { +#if defined(ONE_TABLE) || defined(FOUR_TABLES) +#if !defined(ONE_IM_TABLE) && !defined(FOUR_IM_TABLES) + u_int32_t f2, f4, f8, f9; +#endif + mix(kt, kf); +#else + cpy(kt, kf); +#endif + kt -= 2 * nc; + } + cpy(kt, kf); + } + + return SUCCESS; +} + +/** + * Implementation of crypter_t.destroy and aes_crypter_t.destroy. + */ +static void destroy (private_aes_crypter_t *this) +{ + free(this); +} + +/* + * Described in header + */ +aes_crypter_t *aes_crypter_create(encryption_algorithm_t algo, size_t key_size) +{ + private_aes_crypter_t *this; + + if (algo != ENCR_AES_CBC) + { + return NULL; + } + + this = malloc_thing(private_aes_crypter_t); + + #if !defined(FIXED_TABLES) + if(!tab_gen) { gen_tabs(); tab_gen = 1; } + #endif + + this->key_size = key_size; + switch(key_size) + { + case 32: /* bytes */ + this->aes_Nkey = 8; + break; + case 24: /* bytes */ + this->aes_Nkey = 6; + break; + case 16: /* bytes */ + this->aes_Nkey = 4; + break; + default: + free(this); + return NULL; + } + + /* functions of crypter_t interface */ + this->public.crypter_interface.encrypt = (status_t (*) (crypter_t *, chunk_t,chunk_t, chunk_t *)) encrypt; + this->public.crypter_interface.decrypt = (status_t (*) (crypter_t *, chunk_t , chunk_t, chunk_t *)) decrypt; + this->public.crypter_interface.get_block_size = (size_t (*) (crypter_t *)) get_block_size; + this->public.crypter_interface.get_key_size = (size_t (*) (crypter_t *)) get_key_size; + this->public.crypter_interface.set_key = (status_t (*) (crypter_t *,chunk_t)) set_key; + this->public.crypter_interface.destroy = (void (*) (crypter_t *)) destroy; + + /* private functions */ + this->decrypt_block = decrypt_block; + this->encrypt_block = encrypt_block; + + return &(this->public); +} diff --git a/src/libstrongswan/plugins/aes/aes_crypter.h b/src/libstrongswan/plugins/aes/aes_crypter.h new file mode 100644 index 000000000..e42a6bc5b --- /dev/null +++ b/src/libstrongswan/plugins/aes/aes_crypter.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup aes_crypter aes_crypter + * @{ @ingroup aes_p + */ + +#ifndef AES_CRYPTER_H_ +#define AES_CRYPTER_H_ + +typedef struct aes_crypter_t aes_crypter_t; + +#include <crypto/crypters/crypter.h> + +/** + * Class implementing the AES encryption algorithm. + */ +struct aes_crypter_t { + + /** + * The crypter_t interface. + */ + crypter_t crypter_interface; +}; + +/** + * Constructor to create aes_crypter_t objects. + * + * @param key_size key size in bytes + * @param algo algorithm to implement + * @return aes_crypter_t object, NULL if not supported + */ +aes_crypter_t *aes_crypter_create(encryption_algorithm_t algo, + size_t key_size); + +#endif /* AES_CRYPTER_H_ @}*/ diff --git a/src/libstrongswan/plugins/aes/aes_plugin.c b/src/libstrongswan/plugins/aes/aes_plugin.c new file mode 100644 index 000000000..590948f07 --- /dev/null +++ b/src/libstrongswan/plugins/aes/aes_plugin.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "aes_plugin.h" + +#include <library.h> +#include "aes_crypter.h" + +typedef struct private_aes_plugin_t private_aes_plugin_t; + +/** + * private data of aes_plugin + */ +struct private_aes_plugin_t { + + /** + * public functions + */ + aes_plugin_t public; +}; + +/** + * Implementation of aes_plugin_t.destroy + */ +static void destroy(private_aes_plugin_t *this) +{ + lib->crypto->remove_crypter(lib->crypto, + (crypter_constructor_t)aes_crypter_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_aes_plugin_t *this = malloc_thing(private_aes_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_crypter(lib->crypto, ENCR_AES_CBC, + (crypter_constructor_t)aes_crypter_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/aes/aes_plugin.h b/src/libstrongswan/plugins/aes/aes_plugin.h new file mode 100644 index 000000000..4cf0bc15e --- /dev/null +++ b/src/libstrongswan/plugins/aes/aes_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup aes_p aes + * @ingroup plugins + * + * @defgroup aes_plugin aes_plugin + * @{ @ingroup aes_p + */ + +#ifndef AES_PLUGIN_H_ +#define AES_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct aes_plugin_t aes_plugin_t; + +/** + * Plugin implementing AES based algorithms in software. + */ +struct aes_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a aes_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* AES_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/curl/Makefile.am b/src/libstrongswan/plugins/curl/Makefile.am new file mode 100644 index 000000000..1b44516b2 --- /dev/null +++ b/src/libstrongswan/plugins/curl/Makefile.am @@ -0,0 +1,11 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-curl.la + +libstrongswan_curl_la_SOURCES = curl_plugin.h curl_plugin.c curl_fetcher.c curl_fetcher.h +libstrongswan_curl_la_LDFLAGS = -module +libstrongswan_curl_la_LIBADD = -lcurl + diff --git a/src/libstrongswan/plugins/curl/curl_fetcher.c b/src/libstrongswan/plugins/curl/curl_fetcher.c new file mode 100644 index 000000000..fe49717fa --- /dev/null +++ b/src/libstrongswan/plugins/curl/curl_fetcher.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2007 Andreas Steffen + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include <curl/curl.h> + +#include <library.h> +#include <debug.h> + +#include "curl_fetcher.h" + +#define DEFAULT_TIMEOUT 10 + +typedef struct private_curl_fetcher_t private_curl_fetcher_t; + +/** + * private data of a curl_fetcher_t object. + */ +struct private_curl_fetcher_t { + /** + * Public data + */ + curl_fetcher_t public; + + /** + * CURL handle + */ + CURL* curl; + + /** + * request type, as set with FETCH_REQUEST_TYPE + */ + char *request_type; +}; + +/** + * writes data into a dynamically resizeable chunk_t + */ +static size_t append(void *ptr, size_t size, size_t nmemb, chunk_t *data) +{ + size_t realsize = size * nmemb; + + data->ptr = (u_char*)realloc(data->ptr, data->len + realsize); + if (data->ptr) + { + memcpy(&data->ptr[data->len], ptr, realsize); + data->len += realsize; + } + return realsize; +} + +/** + * Implements fetcher_t.fetch. + */ +static status_t fetch(private_curl_fetcher_t *this, char *uri, chunk_t *result) +{ + struct curl_slist *headers = NULL; + char error[CURL_ERROR_SIZE]; + char buf[256];; + status_t status; + + *result = chunk_empty; + + if (curl_easy_setopt(this->curl, CURLOPT_URL, uri) != CURLE_OK) + { /* URL type not supported by curl */ + return NOT_SUPPORTED; + } + curl_easy_setopt(this->curl, CURLOPT_ERRORBUFFER, error); + curl_easy_setopt(this->curl, CURLOPT_FAILONERROR, TRUE); + curl_easy_setopt(this->curl, CURLOPT_NOSIGNAL, TRUE); + curl_easy_setopt(this->curl, CURLOPT_CONNECTTIMEOUT, DEFAULT_TIMEOUT); + curl_easy_setopt(this->curl, CURLOPT_WRITEFUNCTION, (void*)append); + curl_easy_setopt(this->curl, CURLOPT_WRITEDATA, (void*)result); + if (this->request_type) + { + snprintf(buf, sizeof(buf), "Content-Type: %s", this->request_type); + headers = curl_slist_append(headers, buf); + curl_easy_setopt(this->curl, CURLOPT_HTTPHEADER, headers); + } + + DBG2("sending http request to '%s'...", uri); + switch (curl_easy_perform(this->curl)) + { + case CURLE_UNSUPPORTED_PROTOCOL: + status = NOT_SUPPORTED; + break; + case CURLE_OK: + status = SUCCESS; + break; + default: + DBG1("libcurl http request failed: %s", error); + status = FAILED; + break; + } + curl_slist_free_all(headers); + return status; +} + +/** + * Implementation of fetcher_t.set_option. + */ +static bool set_option(private_curl_fetcher_t *this, fetcher_option_t option, ...) +{ + va_list args; + + va_start(args, option); + switch (option) + { + case FETCH_REQUEST_DATA: + { + chunk_t data = va_arg(args, chunk_t); + curl_easy_setopt(this->curl, CURLOPT_POSTFIELDS, data.ptr); + curl_easy_setopt(this->curl, CURLOPT_POSTFIELDSIZE, data.len); + return TRUE; + } + case FETCH_REQUEST_TYPE: + { + this->request_type = va_arg(args, char*); + return TRUE; + } + case FETCH_TIMEOUT: + { + curl_easy_setopt(this->curl, CURLOPT_CONNECTTIMEOUT, + va_arg(args, u_int)); + return TRUE; + } + default: + return FALSE; + } +} + +/** + * Implements fetcher_t.destroy + */ +static void destroy(private_curl_fetcher_t *this) +{ + curl_easy_cleanup(this->curl); + free(this); +} + +/* + * Described in header. + */ +curl_fetcher_t *curl_fetcher_create() +{ + private_curl_fetcher_t *this = malloc_thing(private_curl_fetcher_t); + + this->curl = curl_easy_init(); + if (this->curl == NULL) + { + free(this); + return NULL; + } + this->request_type = NULL; + + this->public.interface.fetch = (status_t(*)(fetcher_t*,char*,chunk_t*))fetch; + this->public.interface.set_option = (bool(*)(fetcher_t*, fetcher_option_t option, ...))set_option; + this->public.interface.destroy = (void (*)(fetcher_t*))destroy; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/curl/curl_fetcher.h b/src/libstrongswan/plugins/curl/curl_fetcher.h new file mode 100644 index 000000000..3028eac1b --- /dev/null +++ b/src/libstrongswan/plugins/curl/curl_fetcher.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup curl_fetcher curl_fetcher + * @{ @ingroup curl_p + */ + +#ifndef CURL_FETCHER_H_ +#define CURL_FETCHER_H_ + +typedef struct curl_fetcher_t curl_fetcher_t; + +/** + * Fetcher implementation using libcurl + */ +struct curl_fetcher_t { + + /** + * Implements fetcher interface + */ + fetcher_t interface; + + /** + * Destroy a curl_fetcher instance. + */ + void (*destroy)(curl_fetcher_t *this); +}; + +/** + * Create a curl_fetcher instance. + */ +curl_fetcher_t *curl_fetcher_create(); + +#endif /* CURL_FETCHER_H_ @}*/ diff --git a/src/libstrongswan/plugins/curl/curl_plugin.c b/src/libstrongswan/plugins/curl/curl_plugin.c new file mode 100644 index 000000000..04e9b1783 --- /dev/null +++ b/src/libstrongswan/plugins/curl/curl_plugin.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "curl_plugin.h" + +#include <library.h> +#include <debug.h> +#include "curl_fetcher.h" + +#include <curl/curl.h> + +typedef struct private_curl_plugin_t private_curl_plugin_t; + +/** + * private data of curl_plugin + */ +struct private_curl_plugin_t { + + /** + * public functions + */ + curl_plugin_t public; +}; + +/** + * Implementation of curl_plugin_t.curltroy + */ +static void destroy(private_curl_plugin_t *this) +{ + lib->fetcher->remove_fetcher(lib->fetcher, + (fetcher_constructor_t)curl_fetcher_create); + curl_global_cleanup(); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + CURLcode res; + private_curl_plugin_t *this = malloc_thing(private_curl_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + res = curl_global_init(CURL_GLOBAL_NOTHING); + if (res == CURLE_OK) + { + lib->fetcher->add_fetcher(lib->fetcher, + (fetcher_constructor_t)curl_fetcher_create, "file://"); + lib->fetcher->add_fetcher(lib->fetcher, + (fetcher_constructor_t)curl_fetcher_create, "http://"); + lib->fetcher->add_fetcher(lib->fetcher, + (fetcher_constructor_t)curl_fetcher_create, "https://"); + lib->fetcher->add_fetcher(lib->fetcher, + (fetcher_constructor_t)curl_fetcher_create, "ftp://"); + } + else + { + DBG1("global libcurl initializing failed: %s, curl disabled", + curl_easy_strerror(res)); + } + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/curl/curl_plugin.h b/src/libstrongswan/plugins/curl/curl_plugin.h new file mode 100644 index 000000000..73166a25b --- /dev/null +++ b/src/libstrongswan/plugins/curl/curl_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup curl_p curl + * @ingroup plugins + * + * @defgroup curl_plugin curl_plugin + * @{ @ingroup curl_p + */ + +#ifndef CURL_PLUGIN_H_ +#define CURL_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct curl_plugin_t curl_plugin_t; + +/** + * Plugin implementing fetcher interface using libcurl http library. + */ +struct curl_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a curl_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* CURL_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/des/Makefile.am b/src/libstrongswan/plugins/des/Makefile.am new file mode 100644 index 000000000..ea94eda8a --- /dev/null +++ b/src/libstrongswan/plugins/des/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-des.la + +libstrongswan_des_la_SOURCES = des_plugin.h des_plugin.c des_crypter.c des_crypter.h +libstrongswan_des_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/des/des_crypter.c b/src/libstrongswan/plugins/des/des_crypter.c new file mode 100644 index 000000000..55c12ad81 --- /dev/null +++ b/src/libstrongswan/plugins/des/des_crypter.c @@ -0,0 +1,1531 @@ +/* Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * Derived from Plutos DES library by Eric Young. + * + * Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * $Id$ + */ + +#include "des_crypter.h" + +typedef u_char des_cblock[8]; + +typedef struct des_ks_struct { + des_cblock _; +} des_key_schedule[16]; + + +typedef struct private_des_crypter_t private_des_crypter_t; + +/** + * Private data for des_crypter_t + */ +struct private_des_crypter_t { + + /** + * Public part of this class. + */ + des_crypter_t public; + + /** + * Key size, depends on algoritm... + */ + size_t key_size; + + union { + /** key schedule for single des */ + des_key_schedule ks; + /** key schedule for 3des */ + des_key_schedule ks3[3]; + }; +}; + + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +#define DES_LONG u_int32_t + +#if defined(WIN32) || defined(WIN16) +#ifndef MSDOS +#define MSDOS +#endif +#endif + +#ifndef DES_DEFAULT_OPTIONS +/* the following is tweaked from a config script, that is why it is a + * protected undef/define */ +#ifndef DES_PTR +#define DES_PTR +#endif + +/* This helps C compiler generate the correct code for multiple functional + * units. It reduces register dependancies at the expense of 2 more + * registers */ +#ifndef DES_RISC1 +#define DES_RISC1 +#endif + +#ifndef DES_RISC2 +#undef DES_RISC2 +#endif + +#if defined(DES_RISC1) && defined(DES_RISC2) +YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!! +#endif + +/* Unroll the inner loop, this sometimes helps, sometimes hinders. + * Very mucy CPU dependant */ +#ifndef DES_UNROLL +#define DES_UNROLL +#endif + +/* These default values were supplied by + * Peter Gutman <pgut001@cs.auckland.ac.nz> + * They are only used if nothing else has been defined */ +#if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL) +/* Special defines which change the way the code is built depending on the + CPU and OS. For SGI machines you can use _MIPS_SZLONG (32 or 64) to find + even newer MIPS CPU's, but at the moment one size fits all for + optimization options. Older Sparc's work better with only UNROLL, but + there's no way to tell at compile time what it is you're running on */ + +#if defined( sun ) /* Newer Sparc's */ +#define DES_PTR +#define DES_RISC1 +#define DES_UNROLL +#elif defined( __ultrix ) /* Older MIPS */ +#define DES_PTR +#define DES_RISC2 +#define DES_UNROLL +#elif defined( __osf1__ ) /* Alpha */ +#define DES_PTR +#define DES_RISC2 +#elif defined ( _AIX ) /* RS6000 */ + /* Unknown */ +#elif defined( __hpux ) /* HP-PA */ + /* Unknown */ +#elif defined( __aux ) /* 68K */ + /* Unknown */ +#elif defined( __dgux ) /* 88K (but P6 in latest boxes) */ +#define DES_UNROLL +#elif defined( __sgi ) /* Newer MIPS */ +#define DES_PTR +#define DES_RISC2 +#define DES_UNROLL +#elif defined( i386 ) /* x86 boxes, should be gcc */ +#define DES_PTR +#define DES_RISC1 +#define DES_UNROLL +#endif /* Systems-specific speed defines */ +#endif + +#endif /* DES_DEFAULT_OPTIONS */ + +#ifdef MSDOS /* Visual C++ 2.1 (Windows NT/95) */ +#include <stdlib.h> +#include <errno.h> +#include <time.h> +#include <io.h> +#ifndef RAND +#define RAND +#endif +#undef NOPROTO +#endif + +#if defined(__STDC__) || defined(VMS) || defined(M_XENIX) || defined(MSDOS) +#ifndef __KERNEL__ +#include <string.h> +#else +#include <linux/string.h> +#endif +#endif + +#ifndef RAND +#define RAND +#endif + +#ifdef linux +#undef RAND +#endif + +#ifdef MSDOS +#define getpid() 2 +#define RAND +#undef NOPROTO +#endif + +#if defined(NOCONST) +#define const +#endif + +#ifdef __STDC__ +#undef NOPROTO +#endif + +#ifdef RAND +#define srandom(s) srand(s) +#define random rand +#endif + +#define ITERATIONS 16 +#define HALF_ITERATIONS 8 + +/* used in des_read and des_write */ +#define MAXWRITE (1024*16) +#define BSIZE (MAXWRITE+4) + +#define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \ + l|=((DES_LONG)(*((c)++)))<< 8L, \ + l|=((DES_LONG)(*((c)++)))<<16L, \ + l|=((DES_LONG)(*((c)++)))<<24L) + +/* NOTE - c is not incremented as per c2l */ +#define c2ln(c,l1,l2,n) { \ + c+=n; \ + l1=l2=0; \ + switch (n) { \ + case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \ + case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \ + case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \ + case 5: l2|=((DES_LONG)(*(--(c)))); \ + case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \ + case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \ + case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \ + case 1: l1|=((DES_LONG)(*(--(c)))); \ +} \ +} + +#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24L)&0xff)) + +/* replacements for htonl and ntohl since I have no idea what to do + * when faced with machines with 8 byte longs. */ +#define HDRSIZE 4 + +#define n2l(c,l) (l =((DES_LONG)(*((c)++)))<<24L, \ + l|=((DES_LONG)(*((c)++)))<<16L, \ + l|=((DES_LONG)(*((c)++)))<< 8L, \ + l|=((DES_LONG)(*((c)++)))) + +#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ + *((c)++)=(unsigned char)(((l) )&0xff)) + +/* NOTE - c is not incremented as per l2c */ +#define l2cn(l1,l2,c,n) { \ + c+=n; \ + switch (n) { \ + case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \ + case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \ + case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \ + case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \ + case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \ + case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \ + case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \ + case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \ +} \ +} + +#if defined(WIN32) +#define ROTATE(a,n) (_lrotr(a,n)) +#else +#define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n)))) +#endif + +/* Don't worry about the LOAD_DATA() stuff, that is used by + * fcrypt() to add it's little bit to the front */ + +#ifdef DES_FCRYPT + +#define LOAD_DATA_tmp(R,S,u,t,E0,E1) \ +{ DES_LONG tmp; LOAD_DATA(R,S,u,t,E0,E1,tmp); } + +#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \ + t=R^(R>>16L); \ + u=t&E0; t&=E1; \ + tmp=(u<<16); u^=R^s[S ]; u^=tmp; \ + tmp=(t<<16); t^=R^s[S+1]; t^=tmp +#else +#define LOAD_DATA_tmp(a,b,c,d,e,f) LOAD_DATA(a,b,c,d,e,f,g) +#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \ + u=R^s[S ]; \ + t=R^s[S+1] +#endif + +/* The changes to this macro may help or hinder, depending on the + * compiler and the achitecture. gcc2 always seems to do well :-). + * Inspired by Dana How <how@isl.stanford.edu> + * DO NOT use the alternative version on machines with 8 byte longs. + * It does not seem to work on the Alpha, even when DES_LONG is 4 + * bytes, probably an issue of accessing non-word aligned objects :-( */ +#ifdef DES_PTR + +/* It recently occured to me that 0^0^0^0^0^0^0 == 0, so there + * is no reason to not xor all the sub items together. This potentially + * saves a register since things can be xored directly into L */ + +#if defined(DES_RISC1) || defined(DES_RISC2) +#ifdef DES_RISC1 +#define D_ENCRYPT(LL,R,S) { \ + unsigned int u1,u2,u3; \ + LOAD_DATA(R,S,u,t,E0,E1,u1); \ + u2=(int)u>>8L; \ + u1=(int)u&0xfc; \ + u2&=0xfc; \ + t=ROTATE(t,4); \ + u>>=16L; \ + LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \ + u3=(int)(u>>8L); \ + u1=(int)u&0xfc; \ + u3&=0xfc; \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+u1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+u3); \ + u2=(int)t>>8L; \ + u1=(int)t&0xfc; \ + u2&=0xfc; \ + t>>=16L; \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \ + u3=(int)t>>8L; \ + u1=(int)t&0xfc; \ + u3&=0xfc; \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+u1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+u3); } +#endif +#ifdef DES_RISC2 +#define D_ENCRYPT(LL,R,S) { \ + unsigned int u1,u2,s1,s2; \ + LOAD_DATA(R,S,u,t,E0,E1,u1); \ + u2=(int)u>>8L; \ + u1=(int)u&0xfc; \ + u2&=0xfc; \ + t=ROTATE(t,4); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \ + s1=(int)(u>>16L); \ + s2=(int)(u>>24L); \ + s1&=0xfc; \ + s2&=0xfc; \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+s1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+s2); \ + u2=(int)t>>8L; \ + u1=(int)t&0xfc; \ + u2&=0xfc; \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \ + s1=(int)(t>>16L); \ + s2=(int)(t>>24L); \ + s1&=0xfc; \ + s2&=0xfc; \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+s1); \ + LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+s2); } +#endif +#else +#define D_ENCRYPT(LL,R,S) { \ + LOAD_DATA_tmp(R,S,u,t,E0,E1); \ + t=ROTATE(t,4); \ + LL^= \ + *(DES_LONG *)((unsigned char *)des_SP +((u )&0xfc))^ \ + *(DES_LONG *)((unsigned char *)des_SP+0x200+((u>> 8L)&0xfc))^ \ + *(DES_LONG *)((unsigned char *)des_SP+0x400+((u>>16L)&0xfc))^ \ + *(DES_LONG *)((unsigned char *)des_SP+0x600+((u>>24L)&0xfc))^ \ + *(DES_LONG *)((unsigned char *)des_SP+0x100+((t )&0xfc))^ \ + *(DES_LONG *)((unsigned char *)des_SP+0x300+((t>> 8L)&0xfc))^ \ + *(DES_LONG *)((unsigned char *)des_SP+0x500+((t>>16L)&0xfc))^ \ + *(DES_LONG *)((unsigned char *)des_SP+0x700+((t>>24L)&0xfc)); } +#endif + +#else /* original version */ + +#if defined(DES_RISC1) || defined(DES_RISC2) +#ifdef DES_RISC1 +#define D_ENCRYPT(LL,R,S) {\ + unsigned int u1,u2,u3; \ + LOAD_DATA(R,S,u,t,E0,E1,u1); \ + u>>=2L; \ + t=ROTATE(t,6); \ + u2=(int)u>>8L; \ + u1=(int)u&0x3f; \ + u2&=0x3f; \ + u>>=16L; \ + LL^=des_SPtrans[0][u1]; \ + LL^=des_SPtrans[2][u2]; \ + u3=(int)u>>8L; \ + u1=(int)u&0x3f; \ + u3&=0x3f; \ + LL^=des_SPtrans[4][u1]; \ + LL^=des_SPtrans[6][u3]; \ + u2=(int)t>>8L; \ + u1=(int)t&0x3f; \ + u2&=0x3f; \ + t>>=16L; \ + LL^=des_SPtrans[1][u1]; \ + LL^=des_SPtrans[3][u2]; \ + u3=(int)t>>8L; \ + u1=(int)t&0x3f; \ + u3&=0x3f; \ + LL^=des_SPtrans[5][u1]; \ + LL^=des_SPtrans[7][u3]; } +#endif +#ifdef DES_RISC2 +#define D_ENCRYPT(LL,R,S) {\ + unsigned int u1,u2,s1,s2; \ + LOAD_DATA(R,S,u,t,E0,E1,u1); \ + u>>=2L; \ + t=ROTATE(t,6); \ + u2=(int)u>>8L; \ + u1=(int)u&0x3f; \ + u2&=0x3f; \ + LL^=des_SPtrans[0][u1]; \ + LL^=des_SPtrans[2][u2]; \ + s1=(int)u>>16L; \ + s2=(int)u>>24L; \ + s1&=0x3f; \ + s2&=0x3f; \ + LL^=des_SPtrans[4][s1]; \ + LL^=des_SPtrans[6][s2]; \ + u2=(int)t>>8L; \ + u1=(int)t&0x3f; \ + u2&=0x3f; \ + LL^=des_SPtrans[1][u1]; \ + LL^=des_SPtrans[3][u2]; \ + s1=(int)t>>16; \ + s2=(int)t>>24L; \ + s1&=0x3f; \ + s2&=0x3f; \ + LL^=des_SPtrans[5][s1]; \ + LL^=des_SPtrans[7][s2]; } +#endif + +#else + +#define D_ENCRYPT(LL,R,S) {\ + LOAD_DATA_tmp(R,S,u,t,E0,E1); \ + t=ROTATE(t,4); \ + LL^=\ + des_SPtrans[0][(u>> 2L)&0x3f]^ \ + des_SPtrans[2][(u>>10L)&0x3f]^ \ + des_SPtrans[4][(u>>18L)&0x3f]^ \ + des_SPtrans[6][(u>>26L)&0x3f]^ \ + des_SPtrans[1][(t>> 2L)&0x3f]^ \ + des_SPtrans[3][(t>>10L)&0x3f]^ \ + des_SPtrans[5][(t>>18L)&0x3f]^ \ + des_SPtrans[7][(t>>26L)&0x3f]; } +#endif +#endif + + /* IP and FP + * The problem is more of a geometric problem that random bit fiddling. + 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6 + 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4 + 16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2 + 24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0 + + 32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7 + 40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5 + 48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3 + 56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1 + + The output has been subject to swaps of the form + 0 1 -> 3 1 but the odd and even bits have been put into + 2 3 2 0 + different words. The main trick is to remember that + t=((l>>size)^r)&(mask); + r^=t; + l^=(t<<size); + can be used to swap and move bits between words. + + So l = 0 1 2 3 r = 16 17 18 19 + 4 5 6 7 20 21 22 23 + 8 9 10 11 24 25 26 27 + 12 13 14 15 28 29 30 31 + becomes (for size == 2 and mask == 0x3333) + t = 2^16 3^17 -- -- l = 0 1 16 17 r = 2 3 18 19 + 6^20 7^21 -- -- 4 5 20 21 6 7 22 23 + 10^24 11^25 -- -- 8 9 24 25 10 11 24 25 + 14^28 15^29 -- -- 12 13 28 29 14 15 28 29 + + Thanks for hints from Richard Outerbridge - he told me IP&FP + could be done in 15 xor, 10 shifts and 5 ands. + When I finally started to think of the problem in 2D + I first got ~42 operations without xors. When I remembered + how to use xors :-) I got it to its final state. + */ +#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\ + (b)^=(t),\ + (a)^=((t)<<(n))) + +#define IP(l,r) \ +{ \ + register DES_LONG tt; \ + PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \ + PERM_OP(l,r,tt,16,0x0000ffffL); \ + PERM_OP(r,l,tt, 2,0x33333333L); \ + PERM_OP(l,r,tt, 8,0x00ff00ffL); \ + PERM_OP(r,l,tt, 1,0x55555555L); \ +} + +#define FP(l,r) \ +{ \ + register DES_LONG tt; \ + PERM_OP(l,r,tt, 1,0x55555555L); \ + PERM_OP(r,l,tt, 8,0x00ff00ffL); \ + PERM_OP(l,r,tt, 2,0x33333333L); \ + PERM_OP(r,l,tt,16,0x0000ffffL); \ + PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \ +} + +#ifndef NOPROTO +void fcrypt_body(DES_LONG *out,des_key_schedule ks, + DES_LONG Eswap0, DES_LONG Eswap1); +#else +void fcrypt_body(); +#endif + +static const DES_LONG des_skb[8][64]={ + { /* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ + 0x00000000L,0x00000010L,0x20000000L,0x20000010L, + 0x00010000L,0x00010010L,0x20010000L,0x20010010L, + 0x00000800L,0x00000810L,0x20000800L,0x20000810L, + 0x00010800L,0x00010810L,0x20010800L,0x20010810L, + 0x00000020L,0x00000030L,0x20000020L,0x20000030L, + 0x00010020L,0x00010030L,0x20010020L,0x20010030L, + 0x00000820L,0x00000830L,0x20000820L,0x20000830L, + 0x00010820L,0x00010830L,0x20010820L,0x20010830L, + 0x00080000L,0x00080010L,0x20080000L,0x20080010L, + 0x00090000L,0x00090010L,0x20090000L,0x20090010L, + 0x00080800L,0x00080810L,0x20080800L,0x20080810L, + 0x00090800L,0x00090810L,0x20090800L,0x20090810L, + 0x00080020L,0x00080030L,0x20080020L,0x20080030L, + 0x00090020L,0x00090030L,0x20090020L,0x20090030L, + 0x00080820L,0x00080830L,0x20080820L,0x20080830L, + 0x00090820L,0x00090830L,0x20090820L,0x20090830L, + }, + { /* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */ + 0x00000000L,0x02000000L,0x00002000L,0x02002000L, + 0x00200000L,0x02200000L,0x00202000L,0x02202000L, + 0x00000004L,0x02000004L,0x00002004L,0x02002004L, + 0x00200004L,0x02200004L,0x00202004L,0x02202004L, + 0x00000400L,0x02000400L,0x00002400L,0x02002400L, + 0x00200400L,0x02200400L,0x00202400L,0x02202400L, + 0x00000404L,0x02000404L,0x00002404L,0x02002404L, + 0x00200404L,0x02200404L,0x00202404L,0x02202404L, + 0x10000000L,0x12000000L,0x10002000L,0x12002000L, + 0x10200000L,0x12200000L,0x10202000L,0x12202000L, + 0x10000004L,0x12000004L,0x10002004L,0x12002004L, + 0x10200004L,0x12200004L,0x10202004L,0x12202004L, + 0x10000400L,0x12000400L,0x10002400L,0x12002400L, + 0x10200400L,0x12200400L,0x10202400L,0x12202400L, + 0x10000404L,0x12000404L,0x10002404L,0x12002404L, + 0x10200404L,0x12200404L,0x10202404L,0x12202404L, + }, + { /* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */ + 0x00000000L,0x00000001L,0x00040000L,0x00040001L, + 0x01000000L,0x01000001L,0x01040000L,0x01040001L, + 0x00000002L,0x00000003L,0x00040002L,0x00040003L, + 0x01000002L,0x01000003L,0x01040002L,0x01040003L, + 0x00000200L,0x00000201L,0x00040200L,0x00040201L, + 0x01000200L,0x01000201L,0x01040200L,0x01040201L, + 0x00000202L,0x00000203L,0x00040202L,0x00040203L, + 0x01000202L,0x01000203L,0x01040202L,0x01040203L, + 0x08000000L,0x08000001L,0x08040000L,0x08040001L, + 0x09000000L,0x09000001L,0x09040000L,0x09040001L, + 0x08000002L,0x08000003L,0x08040002L,0x08040003L, + 0x09000002L,0x09000003L,0x09040002L,0x09040003L, + 0x08000200L,0x08000201L,0x08040200L,0x08040201L, + 0x09000200L,0x09000201L,0x09040200L,0x09040201L, + 0x08000202L,0x08000203L,0x08040202L,0x08040203L, + 0x09000202L,0x09000203L,0x09040202L,0x09040203L, + }, + { /* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */ + 0x00000000L,0x00100000L,0x00000100L,0x00100100L, + 0x00000008L,0x00100008L,0x00000108L,0x00100108L, + 0x00001000L,0x00101000L,0x00001100L,0x00101100L, + 0x00001008L,0x00101008L,0x00001108L,0x00101108L, + 0x04000000L,0x04100000L,0x04000100L,0x04100100L, + 0x04000008L,0x04100008L,0x04000108L,0x04100108L, + 0x04001000L,0x04101000L,0x04001100L,0x04101100L, + 0x04001008L,0x04101008L,0x04001108L,0x04101108L, + 0x00020000L,0x00120000L,0x00020100L,0x00120100L, + 0x00020008L,0x00120008L,0x00020108L,0x00120108L, + 0x00021000L,0x00121000L,0x00021100L,0x00121100L, + 0x00021008L,0x00121008L,0x00021108L,0x00121108L, + 0x04020000L,0x04120000L,0x04020100L,0x04120100L, + 0x04020008L,0x04120008L,0x04020108L,0x04120108L, + 0x04021000L,0x04121000L,0x04021100L,0x04121100L, + 0x04021008L,0x04121008L,0x04021108L,0x04121108L, + }, + { /* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ + 0x00000000L,0x10000000L,0x00010000L,0x10010000L, + 0x00000004L,0x10000004L,0x00010004L,0x10010004L, + 0x20000000L,0x30000000L,0x20010000L,0x30010000L, + 0x20000004L,0x30000004L,0x20010004L,0x30010004L, + 0x00100000L,0x10100000L,0x00110000L,0x10110000L, + 0x00100004L,0x10100004L,0x00110004L,0x10110004L, + 0x20100000L,0x30100000L,0x20110000L,0x30110000L, + 0x20100004L,0x30100004L,0x20110004L,0x30110004L, + 0x00001000L,0x10001000L,0x00011000L,0x10011000L, + 0x00001004L,0x10001004L,0x00011004L,0x10011004L, + 0x20001000L,0x30001000L,0x20011000L,0x30011000L, + 0x20001004L,0x30001004L,0x20011004L,0x30011004L, + 0x00101000L,0x10101000L,0x00111000L,0x10111000L, + 0x00101004L,0x10101004L,0x00111004L,0x10111004L, + 0x20101000L,0x30101000L,0x20111000L,0x30111000L, + 0x20101004L,0x30101004L,0x20111004L,0x30111004L, + }, + { /* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */ + 0x00000000L,0x08000000L,0x00000008L,0x08000008L, + 0x00000400L,0x08000400L,0x00000408L,0x08000408L, + 0x00020000L,0x08020000L,0x00020008L,0x08020008L, + 0x00020400L,0x08020400L,0x00020408L,0x08020408L, + 0x00000001L,0x08000001L,0x00000009L,0x08000009L, + 0x00000401L,0x08000401L,0x00000409L,0x08000409L, + 0x00020001L,0x08020001L,0x00020009L,0x08020009L, + 0x00020401L,0x08020401L,0x00020409L,0x08020409L, + 0x02000000L,0x0A000000L,0x02000008L,0x0A000008L, + 0x02000400L,0x0A000400L,0x02000408L,0x0A000408L, + 0x02020000L,0x0A020000L,0x02020008L,0x0A020008L, + 0x02020400L,0x0A020400L,0x02020408L,0x0A020408L, + 0x02000001L,0x0A000001L,0x02000009L,0x0A000009L, + 0x02000401L,0x0A000401L,0x02000409L,0x0A000409L, + 0x02020001L,0x0A020001L,0x02020009L,0x0A020009L, + 0x02020401L,0x0A020401L,0x02020409L,0x0A020409L, + }, + { /* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */ + 0x00000000L,0x00000100L,0x00080000L,0x00080100L, + 0x01000000L,0x01000100L,0x01080000L,0x01080100L, + 0x00000010L,0x00000110L,0x00080010L,0x00080110L, + 0x01000010L,0x01000110L,0x01080010L,0x01080110L, + 0x00200000L,0x00200100L,0x00280000L,0x00280100L, + 0x01200000L,0x01200100L,0x01280000L,0x01280100L, + 0x00200010L,0x00200110L,0x00280010L,0x00280110L, + 0x01200010L,0x01200110L,0x01280010L,0x01280110L, + 0x00000200L,0x00000300L,0x00080200L,0x00080300L, + 0x01000200L,0x01000300L,0x01080200L,0x01080300L, + 0x00000210L,0x00000310L,0x00080210L,0x00080310L, + 0x01000210L,0x01000310L,0x01080210L,0x01080310L, + 0x00200200L,0x00200300L,0x00280200L,0x00280300L, + 0x01200200L,0x01200300L,0x01280200L,0x01280300L, + 0x00200210L,0x00200310L,0x00280210L,0x00280310L, + 0x01200210L,0x01200310L,0x01280210L,0x01280310L, + }, + { /* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */ + 0x00000000L,0x04000000L,0x00040000L,0x04040000L, + 0x00000002L,0x04000002L,0x00040002L,0x04040002L, + 0x00002000L,0x04002000L,0x00042000L,0x04042000L, + 0x00002002L,0x04002002L,0x00042002L,0x04042002L, + 0x00000020L,0x04000020L,0x00040020L,0x04040020L, + 0x00000022L,0x04000022L,0x00040022L,0x04040022L, + 0x00002020L,0x04002020L,0x00042020L,0x04042020L, + 0x00002022L,0x04002022L,0x00042022L,0x04042022L, + 0x00000800L,0x04000800L,0x00040800L,0x04040800L, + 0x00000802L,0x04000802L,0x00040802L,0x04040802L, + 0x00002800L,0x04002800L,0x00042800L,0x04042800L, + 0x00002802L,0x04002802L,0x00042802L,0x04042802L, + 0x00000820L,0x04000820L,0x00040820L,0x04040820L, + 0x00000822L,0x04000822L,0x00040822L,0x04040822L, + 0x00002820L,0x04002820L,0x00042820L,0x04042820L, + 0x00002822L,0x04002822L,0x00042822L,0x04042822L, + } +}; + +const DES_LONG des_SPtrans[8][64]={ + { + /* nibble 0 */ + 0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L, + 0x02000000L, 0x00080802L, 0x00080002L, 0x02000002L, + 0x00080802L, 0x02080800L, 0x02080000L, 0x00000802L, + 0x02000802L, 0x02000000L, 0x00000000L, 0x00080002L, + 0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L, + 0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L, + 0x00000002L, 0x00000800L, 0x00080800L, 0x02080002L, + 0x00000800L, 0x02000802L, 0x02080002L, 0x00000000L, + 0x00000000L, 0x02080802L, 0x02000800L, 0x00080002L, + 0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L, + 0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L, + 0x00080802L, 0x00000002L, 0x02000002L, 0x02080000L, + 0x02080802L, 0x00080800L, 0x02080000L, 0x02000802L, + 0x02000000L, 0x00000802L, 0x00080002L, 0x00000000L, + 0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L, + 0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L, + }, + { /* nibble 1 */ + 0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L, + 0x40000010L, 0x00008010L, 0x40008000L, 0x00108000L, + 0x00008000L, 0x40100010L, 0x00000010L, 0x40008000L, + 0x00100010L, 0x40108000L, 0x40100000L, 0x00000010L, + 0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L, + 0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L, + 0x40008010L, 0x00108010L, 0x40108000L, 0x40000010L, + 0x40000000L, 0x00100000L, 0x00008010L, 0x40108010L, + 0x00100010L, 0x40108000L, 0x40008000L, 0x00108010L, + 0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L, + 0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L, + 0x00008000L, 0x40000000L, 0x00108010L, 0x40008010L, + 0x40108000L, 0x00008000L, 0x00000000L, 0x40000010L, + 0x00000010L, 0x40108010L, 0x00108000L, 0x40100000L, + 0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L, + 0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L, + }, + { /* nibble 2 */ + 0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L, + 0x00040001L, 0x04000000L, 0x04000101L, 0x00040100L, + 0x04000100L, 0x00040000L, 0x04040000L, 0x00000001L, + 0x04040101L, 0x00000101L, 0x00000001L, 0x04040001L, + 0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L, + 0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L, + 0x04040001L, 0x04000100L, 0x00040101L, 0x04040000L, + 0x00040100L, 0x00000000L, 0x04000000L, 0x00040101L, + 0x04040100L, 0x00000100L, 0x00000001L, 0x00040000L, + 0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L, + 0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L, + 0x00040001L, 0x04000000L, 0x04040101L, 0x00000001L, + 0x00040101L, 0x04000001L, 0x04000000L, 0x04040101L, + 0x00040000L, 0x04000100L, 0x04000101L, 0x00040100L, + 0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L, + 0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L, + }, + { /* nibble 3 */ + 0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L, + 0x00000000L, 0x10400000L, 0x10001008L, 0x00400008L, + 0x10401000L, 0x10000008L, 0x10000000L, 0x00001008L, + 0x10000008L, 0x00401008L, 0x00400000L, 0x10000000L, + 0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L, + 0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L, + 0x00001008L, 0x00000000L, 0x00400008L, 0x10401000L, + 0x10001000L, 0x10400008L, 0x10401008L, 0x00400000L, + 0x10400008L, 0x00001008L, 0x00400000L, 0x10000008L, + 0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L, + 0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L, + 0x00000000L, 0x10400008L, 0x10401000L, 0x00001000L, + 0x10000000L, 0x10401008L, 0x00401008L, 0x00400000L, + 0x10401008L, 0x00000008L, 0x10001000L, 0x00401008L, + 0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L, + 0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L, + }, + { /* nibble 4 */ + 0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L, + 0x08010020L, 0x08000400L, 0x00010420L, 0x08010000L, + 0x00010000L, 0x00000020L, 0x08000020L, 0x00010400L, + 0x08000420L, 0x08010020L, 0x08010400L, 0x00000000L, + 0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L, + 0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L, + 0x00000020L, 0x08000420L, 0x08010420L, 0x00010020L, + 0x08010000L, 0x00000400L, 0x00000420L, 0x08010400L, + 0x08010400L, 0x08000420L, 0x00010020L, 0x08010000L, + 0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L, + 0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L, + 0x00010420L, 0x08000000L, 0x00000400L, 0x00010020L, + 0x08000420L, 0x00000400L, 0x00000000L, 0x08010420L, + 0x08010020L, 0x08010400L, 0x00000420L, 0x00010000L, + 0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L, + 0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L, + }, + { /* nibble 5 */ + 0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L, + 0x00200040L, 0x00002000L, 0x80002040L, 0x00200000L, + 0x00002040L, 0x80202040L, 0x00202000L, 0x80000000L, + 0x80002000L, 0x80000040L, 0x80200000L, 0x00202040L, + 0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L, + 0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L, + 0x80202040L, 0x80200000L, 0x80000000L, 0x00002040L, + 0x00000040L, 0x00202000L, 0x00202040L, 0x80002000L, + 0x00002040L, 0x80000000L, 0x80002000L, 0x00202040L, + 0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L, + 0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L, + 0x00200040L, 0x80202040L, 0x00202000L, 0x00000040L, + 0x80202040L, 0x00202000L, 0x00200000L, 0x80002040L, + 0x80000040L, 0x80200000L, 0x00202040L, 0x00000000L, + 0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L, + 0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L, + }, + { /* nibble 6 */ + 0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L, + 0x01004204L, 0x00004004L, 0x00004200L, 0x00000000L, + 0x01000000L, 0x01000204L, 0x00000204L, 0x01004000L, + 0x00000004L, 0x01004200L, 0x01004000L, 0x00000204L, + 0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L, + 0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L, + 0x01004004L, 0x00004204L, 0x01004200L, 0x00000004L, + 0x00004204L, 0x01004004L, 0x00000200L, 0x01000000L, + 0x00004204L, 0x01004000L, 0x01004004L, 0x00000204L, + 0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L, + 0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L, + 0x00000200L, 0x01000004L, 0x00000004L, 0x01000200L, + 0x00000000L, 0x01000204L, 0x01000200L, 0x00004200L, + 0x00000204L, 0x00004000L, 0x01004204L, 0x01000000L, + 0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L, + 0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L, + }, + { /* nibble 7 */ + 0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L, + 0x20020000L, 0x00800080L, 0x20800000L, 0x20820080L, + 0x00000080L, 0x20000000L, 0x00820000L, 0x00020080L, + 0x00820080L, 0x20020080L, 0x20000080L, 0x20800000L, + 0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L, + 0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L, + 0x20000000L, 0x00800000L, 0x20020080L, 0x20800080L, + 0x00800000L, 0x00020000L, 0x20820000L, 0x00000080L, + 0x00800000L, 0x00020000L, 0x20000080L, 0x20820080L, + 0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L, + 0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L, + 0x20820000L, 0x00000080L, 0x00800080L, 0x20020000L, + 0x20820080L, 0x00800000L, 0x20800000L, 0x20000080L, + 0x00820000L, 0x00020080L, 0x20020080L, 0x20800000L, + 0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L, + 0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L, + } +}; + +#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\ + (a)=(a)^(t)^(t>>(16-(n)))) + +static const unsigned char odd_parity[256]={ + 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, + 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, + 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, + 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, + 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, + 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, + 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110, + 112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127, + 128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143, + 145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158, + 161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174, + 176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191, + 193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206, + 208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223, + 224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239, + 241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254 +}; + +/** + * Create key schedule for a single DES 64Bit key + */ +static int des_set_key(des_cblock *key, des_key_schedule *schedule) +{ + static int shifts2[16] = {0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0}; + register DES_LONG c,d,t,s,t2; + register unsigned char *in; + register DES_LONG *k; + register int i; + des_cblock odd; + + for (i = 0; i < sizeof(des_cblock); i++) + { + odd[i] = odd_parity[(*key)[i]]; + } + + k=(DES_LONG *)schedule; + in=(unsigned char *)&odd; + + c2l(in,c); + c2l(in,d); + + /* do PC1 in 60 simple operations */ +/* PERM_OP(d,c,t,4,0x0f0f0f0fL); + HPERM_OP(c,t,-2, 0xcccc0000L); + HPERM_OP(c,t,-1, 0xaaaa0000L); + HPERM_OP(c,t, 8, 0x00ff0000L); + HPERM_OP(c,t,-1, 0xaaaa0000L); + HPERM_OP(d,t,-8, 0xff000000L); + HPERM_OP(d,t, 8, 0x00ff0000L); + HPERM_OP(d,t, 2, 0x33330000L); + d=((d&0x00aa00aaL)<<7L)|((d&0x55005500L)>>7L)|(d&0xaa55aa55L); + d=(d>>8)|((c&0xf0000000L)>>4); + c&=0x0fffffffL; */ + + /* I now do it in 47 simple operations :-) + * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov) + * for the inspiration. :-) */ + PERM_OP (d,c,t,4,0x0f0f0f0fL); + HPERM_OP(c,t,-2,0xcccc0000L); + HPERM_OP(d,t,-2,0xcccc0000L); + PERM_OP (d,c,t,1,0x55555555L); + PERM_OP (c,d,t,8,0x00ff00ffL); + PERM_OP (d,c,t,1,0x55555555L); + d= (((d&0x000000ffL)<<16L)| (d&0x0000ff00L) | + ((d&0x00ff0000L)>>16L)|((c&0xf0000000L)>>4L)); + c&=0x0fffffffL; + + for (i=0; i<ITERATIONS; i++) + { + if (shifts2[i]) + { c=((c>>2L)|(c<<26L)); d=((d>>2L)|(d<<26L)); } + else + { c=((c>>1L)|(c<<27L)); d=((d>>1L)|(d<<27L)); } + c&=0x0fffffffL; + d&=0x0fffffffL; + /* could be a few less shifts but I am to lazy at this + * point in time to investigate */ + s= des_skb[0][ (c )&0x3f ]| + des_skb[1][((c>> 6)&0x03)|((c>> 7L)&0x3c)]| + des_skb[2][((c>>13)&0x0f)|((c>>14L)&0x30)]| + des_skb[3][((c>>20)&0x01)|((c>>21L)&0x06) | + ((c>>22L)&0x38)]; + t= des_skb[4][ (d )&0x3f ]| + des_skb[5][((d>> 7L)&0x03)|((d>> 8L)&0x3c)]| + des_skb[6][ (d>>15L)&0x3f ]| + des_skb[7][((d>>21L)&0x0f)|((d>>22L)&0x30)]; + + /* table contained 0213 4657 */ + t2=((t<<16L)|(s&0x0000ffffL))&0xffffffffL; + *(k++)=ROTATE(t2,30)&0xffffffffL; + + t2=((s>>16L)|(t&0xffff0000L)); + *(k++)=ROTATE(t2,26)&0xffffffffL; + } + return(0); +} + + +static void des_encrypt(DES_LONG *data, des_key_schedule ks, int enc) +{ + register DES_LONG l,r,t,u; +#ifdef DES_PTR + register unsigned char *des_SP=(unsigned char *)des_SPtrans; +#endif +#ifndef DES_UNROLL + register int i; +#endif + register DES_LONG *s; + + r=data[0]; + l=data[1]; + + IP(r,l); + /* Things have been modified so that the initial rotate is + * done outside the loop. This required the + * des_SPtrans values in sp.h to be rotated 1 bit to the right. + * One perl script later and things have a 5% speed up on a sparc2. + * Thanks to Richard Outerbridge <71755.204@CompuServe.COM> + * for pointing this out. */ + /* clear the top bits on machines with 8byte longs */ + /* shift left by 2 */ + r=ROTATE(r,29)&0xffffffffL; + l=ROTATE(l,29)&0xffffffffL; + + s=(DES_LONG *)ks; + /* I don't know if it is worth the effort of loop unrolling the + * inner loop */ + if (enc) + { +#ifdef DES_UNROLL + D_ENCRYPT(l,r, 0); /* 1 */ + D_ENCRYPT(r,l, 2); /* 2 */ + D_ENCRYPT(l,r, 4); /* 3 */ + D_ENCRYPT(r,l, 6); /* 4 */ + D_ENCRYPT(l,r, 8); /* 5 */ + D_ENCRYPT(r,l,10); /* 6 */ + D_ENCRYPT(l,r,12); /* 7 */ + D_ENCRYPT(r,l,14); /* 8 */ + D_ENCRYPT(l,r,16); /* 9 */ + D_ENCRYPT(r,l,18); /* 10 */ + D_ENCRYPT(l,r,20); /* 11 */ + D_ENCRYPT(r,l,22); /* 12 */ + D_ENCRYPT(l,r,24); /* 13 */ + D_ENCRYPT(r,l,26); /* 14 */ + D_ENCRYPT(l,r,28); /* 15 */ + D_ENCRYPT(r,l,30); /* 16 */ +#else + for (i=0; i<32; i+=8) +{ + D_ENCRYPT(l,r,i+0); /* 1 */ + D_ENCRYPT(r,l,i+2); /* 2 */ + D_ENCRYPT(l,r,i+4); /* 3 */ + D_ENCRYPT(r,l,i+6); /* 4 */ +} +#endif + } + else +{ +#ifdef DES_UNROLL + D_ENCRYPT(l,r,30); /* 16 */ + D_ENCRYPT(r,l,28); /* 15 */ + D_ENCRYPT(l,r,26); /* 14 */ + D_ENCRYPT(r,l,24); /* 13 */ + D_ENCRYPT(l,r,22); /* 12 */ + D_ENCRYPT(r,l,20); /* 11 */ + D_ENCRYPT(l,r,18); /* 10 */ + D_ENCRYPT(r,l,16); /* 9 */ + D_ENCRYPT(l,r,14); /* 8 */ + D_ENCRYPT(r,l,12); /* 7 */ + D_ENCRYPT(l,r,10); /* 6 */ + D_ENCRYPT(r,l, 8); /* 5 */ + D_ENCRYPT(l,r, 6); /* 4 */ + D_ENCRYPT(r,l, 4); /* 3 */ + D_ENCRYPT(l,r, 2); /* 2 */ + D_ENCRYPT(r,l, 0); /* 1 */ +#else + for (i=30; i>0; i-=8) +{ + D_ENCRYPT(l,r,i-0); /* 16 */ + D_ENCRYPT(r,l,i-2); /* 15 */ + D_ENCRYPT(l,r,i-4); /* 14 */ + D_ENCRYPT(r,l,i-6); /* 13 */ +} +#endif +} + + /* rotate and clear the top bits on machines with 8byte longs */ + l=ROTATE(l,3)&0xffffffffL; + r=ROTATE(r,3)&0xffffffffL; + + FP(r,l); + data[0]=l; + data[1]=r; + l=r=t=u=0; +} + +/** + * DES CBC encrypt decrypt routine + */ +static void des_cbc_encrypt(des_cblock *input, des_cblock *output, long length, + des_key_schedule schedule, des_cblock *ivec, int enc) +{ + register DES_LONG tin0,tin1; + register DES_LONG tout0,tout1,xor0,xor1; + register unsigned char *in,*out; + register long l=length; + DES_LONG tin[2]; + unsigned char *iv; + + in=(unsigned char *)input; + out=(unsigned char *)output; + iv=(unsigned char *)ivec; + + if (enc) + { + c2l(iv,tout0); + c2l(iv,tout1); + for (l-=8; l>=0; l-=8) + { + c2l(in,tin0); + c2l(in,tin1); + tin0^=tout0; tin[0]=tin0; + tin1^=tout1; tin[1]=tin1; + des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT); + tout0=tin[0]; l2c(tout0,out); + tout1=tin[1]; l2c(tout1,out); + } + if (l != -8) + { + c2ln(in,tin0,tin1,l+8); + tin0^=tout0; tin[0]=tin0; + tin1^=tout1; tin[1]=tin1; + des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT); + tout0=tin[0]; l2c(tout0,out); + tout1=tin[1]; l2c(tout1,out); + } + } + else + { + c2l(iv,xor0); + c2l(iv,xor1); + for (l-=8; l>=0; l-=8) + { + c2l(in,tin0); tin[0]=tin0; + c2l(in,tin1); tin[1]=tin1; + des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT); + tout0=tin[0]^xor0; + tout1=tin[1]^xor1; + l2c(tout0,out); + l2c(tout1,out); + xor0=tin0; + xor1=tin1; + } + if (l != -8) + { + c2l(in,tin0); tin[0]=tin0; + c2l(in,tin1); tin[1]=tin1; + des_encrypt((DES_LONG *)tin,schedule,DES_DECRYPT); + tout0=tin[0]^xor0; + tout1=tin[1]^xor1; + l2cn(tout0,tout1,out,l+8); + /* xor0=tin0; + xor1=tin1; */ + } + } + tin0=tin1=tout0=tout1=xor0=xor1=0; + tin[0]=tin[1]=0; +} + +static void des_encrypt2(DES_LONG *data, des_key_schedule ks, int enc) +{ + register DES_LONG l,r,t,u; +#ifdef DES_PTR + register unsigned char *des_SP=(unsigned char *)des_SPtrans; +#endif +#ifndef DES_UNROLL + register int i; +#endif + register DES_LONG *s; + + r=data[0]; + l=data[1]; + + /* Things have been modified so that the initial rotate is + * done outside the loop. This required the + * des_SPtrans values in sp.h to be rotated 1 bit to the right. + * One perl script later and things have a 5% speed up on a sparc2. + * Thanks to Richard Outerbridge <71755.204@CompuServe.COM> + * for pointing this out. + * clear the top bits on machines with 8byte longs */ + r=ROTATE(r,29)&0xffffffffL; + l=ROTATE(l,29)&0xffffffffL; + + s=(DES_LONG *)ks; + /* I don't know if it is worth the effort of loop unrolling the + * inner loop */ + if (enc) + { +#ifdef DES_UNROLL + D_ENCRYPT(l,r, 0); /* 1 */ + D_ENCRYPT(r,l, 2); /* 2 */ + D_ENCRYPT(l,r, 4); /* 3 */ + D_ENCRYPT(r,l, 6); /* 4 */ + D_ENCRYPT(l,r, 8); /* 5 */ + D_ENCRYPT(r,l,10); /* 6 */ + D_ENCRYPT(l,r,12); /* 7 */ + D_ENCRYPT(r,l,14); /* 8 */ + D_ENCRYPT(l,r,16); /* 9 */ + D_ENCRYPT(r,l,18); /* 10 */ + D_ENCRYPT(l,r,20); /* 11 */ + D_ENCRYPT(r,l,22); /* 12 */ + D_ENCRYPT(l,r,24); /* 13 */ + D_ENCRYPT(r,l,26); /* 14 */ + D_ENCRYPT(l,r,28); /* 15 */ + D_ENCRYPT(r,l,30); /* 16 */ +#else + for (i=0; i<32; i+=8) +{ + D_ENCRYPT(l,r,i+0); /* 1 */ + D_ENCRYPT(r,l,i+2); /* 2 */ + D_ENCRYPT(l,r,i+4); /* 3 */ + D_ENCRYPT(r,l,i+6); /* 4 */ +} +#endif + } + else +{ +#ifdef DES_UNROLL + D_ENCRYPT(l,r,30); /* 16 */ + D_ENCRYPT(r,l,28); /* 15 */ + D_ENCRYPT(l,r,26); /* 14 */ + D_ENCRYPT(r,l,24); /* 13 */ + D_ENCRYPT(l,r,22); /* 12 */ + D_ENCRYPT(r,l,20); /* 11 */ + D_ENCRYPT(l,r,18); /* 10 */ + D_ENCRYPT(r,l,16); /* 9 */ + D_ENCRYPT(l,r,14); /* 8 */ + D_ENCRYPT(r,l,12); /* 7 */ + D_ENCRYPT(l,r,10); /* 6 */ + D_ENCRYPT(r,l, 8); /* 5 */ + D_ENCRYPT(l,r, 6); /* 4 */ + D_ENCRYPT(r,l, 4); /* 3 */ + D_ENCRYPT(l,r, 2); /* 2 */ + D_ENCRYPT(r,l, 0); /* 1 */ +#else + for (i=30; i>0; i-=8) +{ + D_ENCRYPT(l,r,i-0); /* 16 */ + D_ENCRYPT(r,l,i-2); /* 15 */ + D_ENCRYPT(l,r,i-4); /* 14 */ + D_ENCRYPT(r,l,i-6); /* 13 */ +} +#endif +} + /* rotate and clear the top bits on machines with 8byte longs */ + data[0]=ROTATE(l,3)&0xffffffffL; + data[1]=ROTATE(r,3)&0xffffffffL; + l=r=t=u=0; +} + +/** + * Single block 3DES EDE encrypt routine + */ +static void des_encrypt3(DES_LONG *data, des_key_schedule ks1, + des_key_schedule ks2, des_key_schedule ks3) +{ + register DES_LONG l,r; + + l=data[0]; + r=data[1]; + IP(l,r); + data[0]=l; + data[1]=r; + des_encrypt2((DES_LONG *)data,ks1,DES_ENCRYPT); + des_encrypt2((DES_LONG *)data,ks2,DES_DECRYPT); + des_encrypt2((DES_LONG *)data,ks3,DES_ENCRYPT); + l=data[0]; + r=data[1]; + FP(r,l); + data[0]=l; + data[1]=r; +} + +/** + * Single block 3DES EDE decrypt routine + */ +static void des_decrypt3(DES_LONG *data, des_key_schedule ks1, + des_key_schedule ks2, des_key_schedule ks3) +{ + register DES_LONG l,r; + + l=data[0]; + r=data[1]; + IP(l,r); + data[0]=l; + data[1]=r; + des_encrypt2((DES_LONG *)data,ks3,DES_DECRYPT); + des_encrypt2((DES_LONG *)data,ks2,DES_ENCRYPT); + des_encrypt2((DES_LONG *)data,ks1,DES_DECRYPT); + l=data[0]; + r=data[1]; + FP(r,l); + data[0]=l; + data[1]=r; +} + +/** + * 3DES EDE CBC encrypt/decrypt routine + */ +static void des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output, long length, + des_key_schedule ks1, des_key_schedule ks2, + des_key_schedule ks3, des_cblock *ivec, int enc) +{ + register DES_LONG tin0,tin1; + register DES_LONG tout0,tout1,xor0,xor1; + register unsigned char *in,*out; + register long l=length; + DES_LONG tin[2]; + unsigned char *iv; + + in=(unsigned char *)input; + out=(unsigned char *)output; + iv=(unsigned char *)ivec; + + if (enc) + { + c2l(iv,tout0); + c2l(iv,tout1); + for (l-=8; l>=0; l-=8) + { + c2l(in,tin0); + c2l(in,tin1); + tin0^=tout0; + tin1^=tout1; + + tin[0]=tin0; + tin[1]=tin1; + des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3); + tout0=tin[0]; + tout1=tin[1]; + + l2c(tout0,out); + l2c(tout1,out); + } + if (l != -8) + { + c2ln(in,tin0,tin1,l+8); + tin0^=tout0; + tin1^=tout1; + + tin[0]=tin0; + tin[1]=tin1; + des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3); + tout0=tin[0]; + tout1=tin[1]; + + l2c(tout0,out); + l2c(tout1,out); + } + iv=(unsigned char *)ivec; + l2c(tout0,iv); + l2c(tout1,iv); + } + else + { + register DES_LONG t0,t1; + + c2l(iv,xor0); + c2l(iv,xor1); + for (l-=8; l>=0; l-=8) + { + c2l(in,tin0); + c2l(in,tin1); + + t0=tin0; + t1=tin1; + + tin[0]=tin0; + tin[1]=tin1; + des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3); + tout0=tin[0]; + tout1=tin[1]; + + tout0^=xor0; + tout1^=xor1; + l2c(tout0,out); + l2c(tout1,out); + xor0=t0; + xor1=t1; + } + if (l != -8) + { + c2l(in,tin0); + c2l(in,tin1); + + t0=tin0; + t1=tin1; + + tin[0]=tin0; + tin[1]=tin1; + des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3); + tout0=tin[0]; + tout1=tin[1]; + + tout0^=xor0; + tout1^=xor1; + l2cn(tout0,tout1,out,l+8); + xor0=t0; + xor1=t1; + } + + iv=(unsigned char *)ivec; + l2c(xor0,iv); + l2c(xor1,iv); + } + tin0=tin1=tout0=tout1=xor0=xor1=0; + tin[0]=tin[1]=0; +} + +/** + * Implementation of crypter_t.decrypt for DES. + */ +static status_t decrypt(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) +{ + des_cblock ivb; + + if (data.len % sizeof(des_cblock) != 0 || + iv.len != sizeof(des_cblock)) + { + return INVALID_ARG; + } + + *decrypted = chunk_alloc(data.len); + memcpy(&ivb, iv.ptr, sizeof(des_cblock)); + des_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(decrypted->ptr), + data.len, this->ks, &ivb, DES_DECRYPT); + return SUCCESS; +} + + +/** + * Implementation of crypter_t.decrypt for DES. + */ +static status_t encrypt(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) +{ + des_cblock ivb; + + if (data.len % sizeof(des_cblock) != 0 || + iv.len != sizeof(des_cblock)) + { + return INVALID_ARG; + } + + *encrypted = chunk_alloc(data.len); + memcpy(&ivb, iv.ptr, sizeof(des_cblock)); + des_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(encrypted->ptr), + data.len, this->ks, &ivb, DES_ENCRYPT); + return SUCCESS; +} + +/** + * Implementation of crypter_t.decrypt for 3DES. + */ +static status_t decrypt3(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) +{ + des_cblock ivb; + + if (data.len % sizeof(des_cblock) != 0 || + iv.len != sizeof(des_cblock)) + { + return INVALID_ARG; + } + + *decrypted = chunk_alloc(data.len); + memcpy(&ivb, iv.ptr, sizeof(des_cblock)); + des_ede3_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(decrypted->ptr), + data.len, this->ks3[0], this->ks3[1], this->ks3[2], + &ivb, DES_DECRYPT); + return SUCCESS; +} + +/** + * Implementation of crypter_t.decrypt for 3DES. + */ +static status_t encrypt3(private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) +{ + des_cblock ivb; + + if (data.len % sizeof(des_cblock) != 0 || + iv.len != sizeof(des_cblock)) + { + return INVALID_ARG; + } + + *encrypted = chunk_alloc(data.len); + memcpy(&ivb, iv.ptr, sizeof(des_cblock)); + des_ede3_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)(encrypted->ptr), + data.len, this->ks3[0], this->ks3[1], this->ks3[2], + &ivb, DES_ENCRYPT); + return SUCCESS; +} + +/** + * Implementation of crypter_t.get_block_size. + */ +static size_t get_block_size (private_des_crypter_t *this) +{ + return sizeof(des_cblock); +} + +/** + * Implementation of crypter_t.get_key_size. + */ +static size_t get_key_size (private_des_crypter_t *this) +{ + return this->key_size; +} + +/** + * Implementation of crypter_t.set_key for DES. + */ +static status_t set_key(private_des_crypter_t *this, chunk_t key) +{ + if (key.len != sizeof(des_cblock)) + { + return INVALID_ARG; + } + + des_set_key((des_cblock*)(key.ptr), &this->ks); + + return SUCCESS; +} + +/** + * Implementation of crypter_t.set_key for 3DES. + */ +static status_t set_key3(private_des_crypter_t *this, chunk_t key) +{ + if (key.len != 3 * sizeof(des_cblock)) + { + return INVALID_ARG; + } + + des_set_key((des_cblock*)(key.ptr) + 0, &this->ks3[0]); + des_set_key((des_cblock*)(key.ptr) + 1, &this->ks3[1]); + des_set_key((des_cblock*)(key.ptr) + 2, &this->ks3[2]); + + return SUCCESS; +} + +/** + * Implementation of crypter_t.destroy and des_crypter_t.destroy. + */ +static void destroy(private_des_crypter_t *this) +{ + free(this); +} + +/* + * Described in header + */ +des_crypter_t *des_crypter_create(encryption_algorithm_t algo) +{ + private_des_crypter_t *this = malloc_thing(private_des_crypter_t); + + /* functions of crypter_t interface */ + this->public.crypter_interface.get_block_size = (size_t (*) (crypter_t *)) get_block_size; + this->public.crypter_interface.get_key_size = (size_t (*) (crypter_t *)) get_key_size; + this->public.crypter_interface.destroy = (void (*) (crypter_t *)) destroy; + + /* use functions depending on algorithm */ + switch (algo) + { + case ENCR_DES: + this->key_size = sizeof(des_cblock); + this->public.crypter_interface.set_key = (status_t (*) (crypter_t *,chunk_t)) set_key; + this->public.crypter_interface.encrypt = (status_t (*) (crypter_t *, chunk_t,chunk_t, chunk_t *)) encrypt; + this->public.crypter_interface.decrypt = (status_t (*) (crypter_t *, chunk_t , chunk_t, chunk_t *)) decrypt; + break; + case ENCR_3DES: + this->key_size = 3 * sizeof(des_cblock); + this->public.crypter_interface.set_key = (status_t (*) (crypter_t *,chunk_t)) set_key3; + this->public.crypter_interface.encrypt = (status_t (*) (crypter_t *, chunk_t,chunk_t, chunk_t *)) encrypt3; + this->public.crypter_interface.decrypt = (status_t (*) (crypter_t *, chunk_t , chunk_t, chunk_t *)) decrypt3; + break; + default: + free(this); + return NULL; + } + return &(this->public); +} diff --git a/src/libstrongswan/plugins/des/des_crypter.h b/src/libstrongswan/plugins/des/des_crypter.h new file mode 100644 index 000000000..d40d9cf2f --- /dev/null +++ b/src/libstrongswan/plugins/des/des_crypter.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup des_crypter des_crypter + * @{ @ingroup des_p + */ + +#ifndef DES_CRYPTER_H_ +#define DES_CRYPTER_H_ + +typedef struct des_crypter_t des_crypter_t; + +#include <crypto/crypters/crypter.h> + + +/** + * Class implementing the DES and 3DES encryption algorithms. + */ +struct des_crypter_t { + + /** + * The crypter_t interface. + */ + crypter_t crypter_interface; +}; + +/** + * Constructor to create des_crypter_t objects. + * + * @param algo ENCR_DES for single DES, ENCR_3DES for triple DES + * @return des_crypter_t object, NULL if algo not supported + */ +des_crypter_t *des_crypter_create(encryption_algorithm_t algo); + + +#endif /* DES_CRYPTER_H_ @}*/ diff --git a/src/libstrongswan/plugins/des/des_plugin.c b/src/libstrongswan/plugins/des/des_plugin.c new file mode 100644 index 000000000..4fb98c1d2 --- /dev/null +++ b/src/libstrongswan/plugins/des/des_plugin.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "des_plugin.h" + +#include <library.h> +#include "des_crypter.h" + +typedef struct private_des_plugin_t private_des_plugin_t; + +/** + * private data of des_plugin + */ +struct private_des_plugin_t { + + /** + * public functions + */ + des_plugin_t public; +}; + +/** + * Implementation of des_plugin_t.destroy + */ +static void destroy(private_des_plugin_t *this) +{ + lib->crypto->remove_crypter(lib->crypto, + (crypter_constructor_t)des_crypter_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_des_plugin_t *this = malloc_thing(private_des_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_crypter(lib->crypto, ENCR_DES, + (crypter_constructor_t)des_crypter_create); + lib->crypto->add_crypter(lib->crypto, ENCR_3DES, + (crypter_constructor_t)des_crypter_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/des/des_plugin.h b/src/libstrongswan/plugins/des/des_plugin.h new file mode 100644 index 000000000..8cabd082b --- /dev/null +++ b/src/libstrongswan/plugins/des/des_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup des_p des + * @ingroup plugins + * + * @defgroup des_plugin des_plugin + * @{ @ingroup des_p + */ + +#ifndef DES_PLUGIN_H_ +#define DES_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct des_plugin_t des_plugin_t; + +/** + * Plugin implementing DES based algorithms in software. + */ +struct des_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a des_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* DES_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/fips_prf/Makefile.am b/src/libstrongswan/plugins/fips_prf/Makefile.am new file mode 100644 index 000000000..73f28825a --- /dev/null +++ b/src/libstrongswan/plugins/fips_prf/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-fips-prf.la + +libstrongswan_fips_prf_la_SOURCES = fips_prf_plugin.h fips_prf_plugin.c fips_prf.c fips_prf.h +libstrongswan_fips_prf_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/fips_prf/fips_prf.c b/src/libstrongswan/plugins/fips_prf/fips_prf.c new file mode 100644 index 000000000..20b752e30 --- /dev/null +++ b/src/libstrongswan/plugins/fips_prf/fips_prf.c @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "fips_prf.h" + +#include <arpa/inet.h> + +#include <debug.h> + +typedef struct private_fips_prf_t private_fips_prf_t; + +/** + * Private data of a fips_prf_t object. + */ +struct private_fips_prf_t { + /** + * Public fips_prf_t interface. + */ + fips_prf_t public; + + /** + * key of prf function, "b" long + */ + u_int8_t *key; + + /** + * size of "b" in bytes + */ + size_t b; + + /** + * associated hasher when using SHA1 mode + */ + hasher_t *hasher; + + /** + * G function, either SHA1 or DES + */ + void (*g)(private_fips_prf_t *this, u_int8_t t[], chunk_t c, u_int8_t res[]); +}; + +/** + * t used in G(), equals to initial SHA1 value + */ +static u_int8_t t[] = { + 0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA, + 0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0, +}; + + +/** + * sum = (a + b) mod 2 ^ (length * 8) + */ +static void add_mod(size_t length, u_int8_t a[], u_int8_t b[], u_int8_t sum[]) +{ + int i, c = 0; + + for(i = length - 1; i >= 0; i--) + { + u_int32_t tmp; + + tmp = a[i] + b[i] + c; + sum[i] = 0xff & tmp; + c = tmp >> 8; + } +} + +/** + * calculate "chunk mod 2^(length*8)" and save it into buffer + */ +static void chunk_mod(size_t length, chunk_t chunk, u_int8_t buffer[]) +{ + if (chunk.len < length) + { + /* apply seed as least significant bits, others are zero */ + memset(buffer, 0, length - chunk.len); + memcpy(buffer + length - chunk.len, chunk.ptr, chunk.len); + } + else + { + /* use least significant bytes from seed, as we use mod 2^b */ + memcpy(buffer, chunk.ptr + chunk.len - length, length); + } +} + +/** + * Implementation of prf_t.get_bytes. + * + * Test vector: + * + * key: + * 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b, + * 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f, + * 0xeb, 0x5a, 0x38, 0xb6 + * + * seed: + * 0x00 + * + * result: + * 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f, + * 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49, + * 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba, + * 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78, + * 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16 + */ +static void get_bytes(private_fips_prf_t *this, chunk_t seed, u_int8_t w[]) +{ + int i; + u_int8_t xval[this->b]; + u_int8_t xseed[this->b]; + u_int8_t sum[this->b]; + u_int8_t *xkey = this->key; + u_int8_t one[this->b]; + chunk_t xval_chunk = chunk_from_buf(xval); + + memset(one, 0, this->b); + one[this->b - 1] = 0x01; + + /* 3.1 */ + chunk_mod(this->b, seed, xseed); + + /* 3.2 */ + for (i = 0; i < 2; i++) /* twice */ + { + /* a. XVAL = (XKEY + XSEED j) mod 2^b */ + add_mod(this->b, xkey, xseed, xval); + DBG3("XVAL %b", xval, this->b); + /* b. wi = G(t, XVAL ) */ + this->g(this, t, xval_chunk, &w[i * this->b]); + DBG3("w[%d] %b", i, &w[i * this->b], this->b); + /* c. XKEY = (1 + XKEY + wi) mod 2b */ + add_mod(this->b, xkey, &w[i * this->b], sum); + add_mod(this->b, sum, one, xkey); + DBG3("XKEY %b", xkey, this->b); + } + + /* 3.3 done already, mod q not used */ +} + +/** + * Implementation of prf_t.get_block_size. + */ +static size_t get_block_size(private_fips_prf_t *this) +{ + return 2 * this->b; +} +/** + * Implementation of prf_t.allocate_bytes. + */ +static void allocate_bytes(private_fips_prf_t *this, chunk_t seed, chunk_t *chunk) +{ + *chunk = chunk_alloc(get_block_size(this)); + get_bytes(this, seed, chunk->ptr); +} + +/** + * Implementation of prf_t.get_key_size. + */ +static size_t get_key_size(private_fips_prf_t *this) +{ + return this->b; +} + +/** + * Implementation of prf_t.set_key. + */ +static void set_key(private_fips_prf_t *this, chunk_t key) +{ + /* save key as "key mod 2^b" */ + chunk_mod(this->b, key, this->key); +} + +/** + * Implementation of the G() function based on SHA1 + */ +void g_sha1(private_fips_prf_t *this, u_int8_t t[], chunk_t c, u_int8_t res[]) +{ + u_int8_t buf[64]; + + if (c.len < sizeof(buf)) + { + /* pad c with zeros */ + memset(buf, 0, sizeof(buf)); + memcpy(buf, c.ptr, c.len); + c.ptr = buf; + c.len = sizeof(buf); + } + else + { + /* not more than 512 bits can be G()-ed */ + c.len = sizeof(buf); + } + + /* calculate the special (HASH_SHA1_STATE) hash*/ + this->hasher->get_hash(this->hasher, c, res); +} + +/** + * Implementation of prf_t.destroy. + */ +static void destroy(private_fips_prf_t *this) +{ + this->hasher->destroy(this->hasher); + free(this->key); + free(this); +} + +/* + * Described in header. + */ +fips_prf_t *fips_prf_create(pseudo_random_function_t algo) +{ + private_fips_prf_t *this = malloc_thing(private_fips_prf_t); + + this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes; + this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes; + this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size; + this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size; + this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key; + this->public.prf_interface.destroy = (void (*) (prf_t *))destroy; + + switch (algo) + { + case PRF_FIPS_SHA1_160: + { + this->g = g_sha1; + this->b = 20; + this->hasher = lib->crypto->create_hasher(lib->crypto, + HASH_SHA1_NOFINAL); + if (this->hasher == NULL) + { + free(this); + return NULL; + } + break; + } + case PRF_FIPS_DES: + /* not implemented yet */ + default: + free(this); + return NULL; + } + this->key = malloc(this->b); + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/fips_prf/fips_prf.h b/src/libstrongswan/plugins/fips_prf/fips_prf.h new file mode 100644 index 000000000..3fead6b9b --- /dev/null +++ b/src/libstrongswan/plugins/fips_prf/fips_prf.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup fips_prf fips_prf + * @{ @ingroup fips_prf_p + */ + +#ifndef FIPS_PRF_H_ +#define FIPS_PRF_H_ + +typedef struct fips_prf_t fips_prf_t; + +#include <library.h> +#include <crypto/prfs/prf.h> +#include <crypto/hashers/hasher.h> + +/** + * Implementation of prf_t using the FIPS 186-2-change1 standard. + * + * FIPS defines a "General Purpose Random Number Generator" (Revised + * Algorithm for Computing m values of x (Appendix 3.1 of FIPS 186-2)). This + * implementation is not intended for private key generation and therefore does + * not include the "mod q" operation (see FIPS 186-2-change1 p74). + * The FIPS PRF is stateful; the key changes every time when bytes are acquired. + */ +struct fips_prf_t { + + /** + * Generic prf_t interface for this fips_prf_t class. + */ + prf_t prf_interface; +}; + +/** + * Creates a new fips_prf_t object. + * + * FIPS 186-2 defines G() functions used in the PRF function. It can + * be implemented either based on SHA1 or DES. + * The G() function is selected using the algo parameter. + * + * @param algo specific FIPS PRF implementation, specifies G() function + * @return fips_prf_t object, NULL if not supported. + */ +fips_prf_t *fips_prf_create(pseudo_random_function_t algo); + +#endif /* FIPS_PRF_H_ @}*/ diff --git a/src/libstrongswan/plugins/fips_prf/fips_prf_plugin.c b/src/libstrongswan/plugins/fips_prf/fips_prf_plugin.c new file mode 100644 index 000000000..68252932c --- /dev/null +++ b/src/libstrongswan/plugins/fips_prf/fips_prf_plugin.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "fips_prf_plugin.h" + +#include <library.h> +#include "fips_prf.h" + +typedef struct private_fips_prf_plugin_t private_fips_prf_plugin_t; + +/** + * private data of fips_prf_plugin + */ +struct private_fips_prf_plugin_t { + + /** + * public functions + */ + fips_prf_plugin_t public; +}; + +/** + * Implementation of fips_prf_plugin_t.destroy + */ +static void destroy(private_fips_prf_plugin_t *this) +{ + lib->crypto->remove_prf(lib->crypto, + (prf_constructor_t)fips_prf_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_fips_prf_plugin_t *this = malloc_thing(private_fips_prf_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_prf(lib->crypto, PRF_FIPS_SHA1_160, + (prf_constructor_t)fips_prf_create); + + return &this->public.plugin; +} diff --git a/src/libstrongswan/plugins/fips_prf/fips_prf_plugin.h b/src/libstrongswan/plugins/fips_prf/fips_prf_plugin.h new file mode 100644 index 000000000..6816eb66f --- /dev/null +++ b/src/libstrongswan/plugins/fips_prf/fips_prf_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup fips_prf_p fips_prf + * @ingroup plugins + * + * @defgroup fips_prf_plugin fips_prf_plugin + * @{ @ingroup fips_prf_p + */ + +#ifndef FIPS_PRF_PLUGIN_H_ +#define FIPS_PRF_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct fips_prf_plugin_t fips_prf_plugin_t; + +/** + * Plugin implementing the fips_prf algorithm in software. + */ +struct fips_prf_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a fips_prf_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* FIPS_PRF_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/gmp/Makefile.am b/src/libstrongswan/plugins/gmp/Makefile.am new file mode 100644 index 000000000..3d4065c1b --- /dev/null +++ b/src/libstrongswan/plugins/gmp/Makefile.am @@ -0,0 +1,14 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-gmp.la + +libstrongswan_gmp_la_SOURCES = gmp_plugin.h gmp_plugin.c \ + gmp_diffie_hellman.c gmp_diffie_hellman.h \ + gmp_rsa_private_key.c gmp_rsa_private_key.h \ + gmp_rsa_public_key.c gmp_rsa_public_key.h +libstrongswan_gmp_la_LDFLAGS = -module +libstrongswan_gmp_la_LIBADD = -lgmp + diff --git a/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c b/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c new file mode 100644 index 000000000..349ec419e --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c @@ -0,0 +1,569 @@ +/* + * Copyright (C) 1998-2002 D. Hugh Redelmeier. + * Copyright (C) 1999, 2000, 2001 Henry Spencer. + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include <gmp.h> + +#include "gmp_diffie_hellman.h" + +#include <utils/randomizer.h> +#include <debug.h> + + +/** + * Modulus of Group 1 (MODP_768_BIT). + */ +static u_int8_t group1_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80 ,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x3A,0x36,0x20,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; + +/** + * Modulus of Group 2 (MODP_1024_BIT). + */ +static u_int8_t group2_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51,0xEC,0xE6,0x53,0x81,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; + +/** + * Modulus of Group 5 (MODP_1536_BIT). + */ +static u_int8_t group5_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB, + 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04, + 0xF1,0x74,0x6C,0x08,0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; +/** + * Modulus of Group 14 (MODP_2048_BIT). + */ +static u_int8_t group14_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB, + 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04, + 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F, + 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18, + 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAC,0xAA,0x68,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; + +/** + * Modulus of Group 15 (MODP_3072_BIT). + */ +static u_int8_t group15_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB, + 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04, + 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F, + 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18, + 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, + 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, + 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, + 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, + 0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C, + 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2, + 0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E, + 0x4B,0x82,0xD1,0x20,0xA9,0x3A,0xD2,0xCA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; + +/** + * Modulus of Group 16 (MODP_4096_BIT). + */ +static u_int8_t group16_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB, + 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04, + 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F, + 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18, + 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, + 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, + 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, + 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, + 0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C, + 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2, + 0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E, + 0x4B,0x82,0xD1,0x20,0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, + 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C, + 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8, + 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, + 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2, + 0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF, + 0xB8,0x1B,0xDD,0x76,0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9, + 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,0x90,0xA6,0xC0,0x8F, + 0x4D,0xF4,0x35,0xC9,0x34,0x06,0x31,0x99,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; + +/** + * Modulus of Group 17 (MODP_6144_BIT). + */ +static u_int8_t group17_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB, + 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04, + 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F, + 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18, + 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, + 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, + 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, + 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, + 0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C, + 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2, + 0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E, + 0x4B,0x82,0xD1,0x20,0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, + 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C, + 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8, + 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, + 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2, + 0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF, + 0xB8,0x1B,0xDD,0x76,0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9, + 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,0x90,0xA6,0xC0,0x8F, + 0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92,0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26, + 0xC1,0xD4,0xDC,0xB2,0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD, + 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,0x41,0x30,0x01,0xAE, + 0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18, + 0xDA,0x3E,0xDB,0xEB,0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B, + 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,0x2B,0xD7,0xAF,0x42, + 0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC, + 0xF0,0x32,0xEA,0x15,0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6, + 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,0x90,0x0B,0x1C,0x9E, + 0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE, + 0x0F,0x1D,0x45,0xB7,0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA, + 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,0x0F,0x80,0x37,0xE0, + 0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76, + 0xF5,0x50,0xAA,0x3D,0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C, + 0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,0x6E,0x3C,0x04,0x68, + 0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6, + 0xE6,0x94,0xF9,0x1E,0x6D,0xCC,0x40,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; + +/** + * Modulus of Group 18 (MODP_8192_BIT). + */ +static u_int8_t group18_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB, + 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04, + 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F, + 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18, + 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, + 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, + 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, + 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, + 0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C, + 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2, + 0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E, + 0x4B,0x82,0xD1,0x20,0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, + 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C, + 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8, + 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, + 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2, + 0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF, + 0xB8,0x1B,0xDD,0x76,0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9, + 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,0x90,0xA6,0xC0,0x8F, + 0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92,0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26, + 0xC1,0xD4,0xDC,0xB2,0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD, + 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,0x41,0x30,0x01,0xAE, + 0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18, + 0xDA,0x3E,0xDB,0xEB,0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B, + 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,0x2B,0xD7,0xAF,0x42, + 0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC, + 0xF0,0x32,0xEA,0x15,0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6, + 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,0x90,0x0B,0x1C,0x9E, + 0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE, + 0x0F,0x1D,0x45,0xB7,0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA, + 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,0x0F,0x80,0x37,0xE0, + 0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76, + 0xF5,0x50,0xAA,0x3D,0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C, + 0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,0x6E,0x3C,0x04,0x68, + 0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6, + 0xE6,0x94,0xF9,0x1E,0x6D,0xBE,0x11,0x59,0x74,0xA3,0x92,0x6F,0x12,0xFE,0xE5,0xE4, + 0x38,0x77,0x7C,0xB6,0xA9,0x32,0xDF,0x8C,0xD8,0xBE,0xC4,0xD0,0x73,0xB9,0x31,0xBA, + 0x3B,0xC8,0x32,0xB6,0x8D,0x9D,0xD3,0x00,0x74,0x1F,0xA7,0xBF,0x8A,0xFC,0x47,0xED, + 0x25,0x76,0xF6,0x93,0x6B,0xA4,0x24,0x66,0x3A,0xAB,0x63,0x9C,0x5A,0xE4,0xF5,0x68, + 0x34,0x23,0xB4,0x74,0x2B,0xF1,0xC9,0x78,0x23,0x8F,0x16,0xCB,0xE3,0x9D,0x65,0x2D, + 0xE3,0xFD,0xB8,0xBE,0xFC,0x84,0x8A,0xD9,0x22,0x22,0x2E,0x04,0xA4,0x03,0x7C,0x07, + 0x13,0xEB,0x57,0xA8,0x1A,0x23,0xF0,0xC7,0x34,0x73,0xFC,0x64,0x6C,0xEA,0x30,0x6B, + 0x4B,0xCB,0xC8,0x86,0x2F,0x83,0x85,0xDD,0xFA,0x9D,0x4B,0x7F,0xA2,0xC0,0x87,0xE8, + 0x79,0x68,0x33,0x03,0xED,0x5B,0xDD,0x3A,0x06,0x2B,0x3C,0xF5,0xB3,0xA2,0x78,0xA6, + 0x6D,0x2A,0x13,0xF8,0x3F,0x44,0xF8,0x2D,0xDF,0x31,0x0E,0xE0,0x74,0xAB,0x6A,0x36, + 0x45,0x97,0xE8,0x99,0xA0,0x25,0x5D,0xC1,0x64,0xF3,0x1C,0xC5,0x08,0x46,0x85,0x1D, + 0xF9,0xAB,0x48,0x19,0x5D,0xED,0x7E,0xA1,0xB1,0xD5,0x10,0xBD,0x7E,0xE7,0x4D,0x73, + 0xFA,0xF3,0x6B,0xC3,0x1E,0xCF,0xA2,0x68,0x35,0x90,0x46,0xF4,0xEB,0x87,0x9F,0x92, + 0x40,0x09,0x43,0x8B,0x48,0x1C,0x6C,0xD7,0x88,0x9A,0x00,0x2E,0xD5,0xEE,0x38,0x2B, + 0xC9,0x19,0x0D,0xA6,0xFC,0x02,0x6E,0x47,0x95,0x58,0xE4,0x47,0x56,0x77,0xE9,0xAA, + 0x9E,0x30,0x50,0xE2,0x76,0x56,0x94,0xDF,0xC8,0x1F,0x56,0xE8,0x80,0xB9,0x6E,0x71, + 0x60,0xC9,0x80,0xDD,0x98,0xED,0xD3,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +}; + +typedef struct modulus_entry_t modulus_entry_t; + +/** + * Entry of the modulus list. + */ +struct modulus_entry_t { + /** + * Group number as it is defined in file transform_substructure.h. + */ + diffie_hellman_group_t group; + + /** + * Pointer to first byte of modulus (network order). + */ + u_int8_t *modulus; + + /* + * Length of modulus in bytes. + */ + size_t modulus_len; + + /* + * Generator value. + */ + u_int16_t generator; +}; + +/** + * All supported modulus values. + */ +static modulus_entry_t modulus_entries[] = { + {MODP_768_BIT, group1_modulus, sizeof(group1_modulus), 2}, + {MODP_1024_BIT, group2_modulus, sizeof(group2_modulus), 2}, + {MODP_1536_BIT, group5_modulus, sizeof(group5_modulus), 2}, + {MODP_2048_BIT, group14_modulus, sizeof(group14_modulus), 2}, + {MODP_3072_BIT, group15_modulus, sizeof(group15_modulus), 2}, + {MODP_4096_BIT, group16_modulus, sizeof(group16_modulus), 2}, + {MODP_6144_BIT, group17_modulus, sizeof(group17_modulus), 2}, + {MODP_8192_BIT, group18_modulus, sizeof(group18_modulus), 2}, +}; + +typedef struct private_gmp_diffie_hellman_t private_gmp_diffie_hellman_t; + +/** + * Private data of an gmp_diffie_hellman_t object. + */ +struct private_gmp_diffie_hellman_t { + /** + * Public gmp_diffie_hellman_t interface. + */ + gmp_diffie_hellman_t public; + + /** + * Diffie Hellman group number. + */ + u_int16_t group; + + /* + * Generator value. + */ + mpz_t g; + + /** + * My private value. + */ + mpz_t xa; + + /** + * My public value. + */ + mpz_t ya; + + /** + * Other public value. + */ + mpz_t yb; + + /** + * Shared secret. + */ + mpz_t zz; + + /** + * Modulus. + */ + mpz_t p; + + /** + * Modulus length. + */ + size_t p_len; + + /** + * True if shared secret is computed and stored in my_public_value. + */ + bool computed; +}; + +/** + * Implementation of gmp_diffie_hellman_t.set_other_public_value. + */ +static void set_other_public_value(private_gmp_diffie_hellman_t *this, chunk_t value) +{ + mpz_t p_min_1; + + mpz_init(p_min_1); + mpz_sub_ui(p_min_1, this->p, 1); + + mpz_import(this->yb, value.len, 1, 1, 1, 0, value.ptr); + + /* check public value: + * 1. 0 or 1 is invalid as 0^a = 0 and 1^a = 1 + * 2. a public value larger or equal the modulus is invalid */ + if (mpz_cmp_ui(this->yb, 1) > 0 || + mpz_cmp(this->yb, p_min_1) < 0) + { +#ifdef EXTENDED_DH_TEST + /* 3. test if y ^ q mod p = 1, where q = (p - 1)/2. */ + mpz_t q, one; + + mpz_init(q); + mpz_init(one); + mpz_fdiv_q_2exp(q, p_min_1, 1); + mpz_powm(one, this->yb, q, this->p); + mpz_clear(q); + if (mpz_cmp_ui(one, 1) == 0) + { + mpz_powm(this->zz, this->yb, this->xa, this->p); + this->computed = TRUE; + } + else + { + DBG1("public DH value verification failed: y ^ q mod p != 1"); + } + mpz_clear(one); +#else + mpz_powm(this->zz, this->yb, this->xa, this->p); + this->computed = TRUE; +#endif + } + else + { + DBG1("public DH value verification failed: y < 2 || y > p - 1 "); + } + mpz_clear(p_min_1); +} + +/** + * Implementation of gmp_diffie_hellman_t.get_other_public_value. + */ +static status_t get_other_public_value(private_gmp_diffie_hellman_t *this, + chunk_t *value) +{ + if (!this->computed) + { + return FAILED; + } + value->len = this->p_len; + value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->yb); + return SUCCESS; +} + +/** + * Implementation of gmp_diffie_hellman_t.get_my_public_value. + */ +static void get_my_public_value(private_gmp_diffie_hellman_t *this,chunk_t *value) +{ + value->len = this->p_len; + value->ptr = mpz_export(NULL, NULL, 1, value->len, 1, 0, this->ya); +} + +/** + * Implementation of gmp_diffie_hellman_t.get_shared_secret. + */ +static status_t get_shared_secret(private_gmp_diffie_hellman_t *this, chunk_t *secret) +{ + if (!this->computed) + { + return FAILED; + } + secret->len = this->p_len; + secret->ptr = mpz_export(NULL, NULL, 1, secret->len, 1, 0, this->zz); + return SUCCESS; +} + +/** + * Implementation of gmp_diffie_hellman_t.get_dh_group. + */ +static diffie_hellman_group_t get_dh_group(private_gmp_diffie_hellman_t *this) +{ + return this->group; +} + +/** + * Lookup the modulus in modulo table + */ +static status_t set_modulus(private_gmp_diffie_hellman_t *this) +{ + int i; + status_t status = NOT_FOUND; + + for (i = 0; i < (sizeof(modulus_entries) / sizeof(modulus_entry_t)); i++) + { + if (modulus_entries[i].group == this->group) + { + chunk_t chunk; + chunk.ptr = modulus_entries[i].modulus; + chunk.len = modulus_entries[i].modulus_len; + mpz_import(this->p, chunk.len, 1, 1, 1, 0, chunk.ptr); + this->p_len = chunk.len; + mpz_set_ui(this->g, modulus_entries[i].generator); + status = SUCCESS; + break; + } + } + return status; +} + +/** + * Implementation of gmp_diffie_hellman_t.destroy. + */ +static void destroy(private_gmp_diffie_hellman_t *this) +{ + mpz_clear(this->p); + mpz_clear(this->xa); + mpz_clear(this->ya); + mpz_clear(this->yb); + mpz_clear(this->zz); + mpz_clear(this->g); + free(this); +} + +/* + * Described in header. + */ +gmp_diffie_hellman_t *gmp_diffie_hellman_create(diffie_hellman_group_t group) +{ + private_gmp_diffie_hellman_t *this = malloc_thing(private_gmp_diffie_hellman_t); + randomizer_t *randomizer; + chunk_t random; + status_t status; + + /* public functions */ + this->public.dh.get_shared_secret = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_shared_secret; + this->public.dh.set_other_public_value = (void (*)(diffie_hellman_t *, chunk_t )) set_other_public_value; + this->public.dh.get_other_public_value = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_other_public_value; + this->public.dh.get_my_public_value = (void (*)(diffie_hellman_t *, chunk_t *)) get_my_public_value; + this->public.dh.get_dh_group = (diffie_hellman_group_t (*)(diffie_hellman_t *)) get_dh_group; + this->public.dh.destroy = (void (*)(diffie_hellman_t *)) destroy; + + /* private variables */ + this->group = group; + mpz_init(this->p); + mpz_init(this->yb); + mpz_init(this->ya); + mpz_init(this->xa); + mpz_init(this->zz); + mpz_init(this->g); + + this->computed = FALSE; + + /* find a modulus according to group */ + if (set_modulus(this) != SUCCESS) + { + destroy(this); + return NULL; + } + randomizer = randomizer_create(); + status = randomizer->allocate_pseudo_random_bytes( + randomizer, this->p_len, &random); + randomizer->destroy(randomizer); + if (status != SUCCESS) + { + destroy(this); + return NULL; + } + mpz_import(this->xa, random.len, 1, 1, 1, 0, random.ptr); + chunk_free(&random); + + mpz_powm(this->ya, this->g, this->xa, this->p); + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.h b/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.h new file mode 100644 index 000000000..e2d4d6851 --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup gmp_diffie_hellman gmp_diffie_hellman + * @{ @ingroup gmp_p + */ + +#ifndef GMP_DIFFIE_HELLMAN_H_ +#define GMP_DIFFIE_HELLMAN_H_ + +typedef struct gmp_diffie_hellman_t gmp_diffie_hellman_t; + +#include <library.h> + +/** + * Implementation of the Diffie-Hellman algorithm, as in RFC2631. Uses libgmp. + */ +struct gmp_diffie_hellman_t { + + /** + * Implements diffie_hellman_t interface. + */ + diffie_hellman_t dh; +}; + +/** + * Creates a new gmp_diffie_hellman_t object. + * + * @param group Diffie Hellman group number to use + * @return gmp_diffie_hellman_t object, NULL if not supported + */ +gmp_diffie_hellman_t *gmp_diffie_hellman_create(diffie_hellman_group_t group); + +#endif /*GMP_DIFFIE_HELLMAN_H_ @}*/ + diff --git a/src/libstrongswan/plugins/gmp/gmp_plugin.c b/src/libstrongswan/plugins/gmp/gmp_plugin.c new file mode 100644 index 000000000..ffae66933 --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_plugin.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "gmp_plugin.h" + +#include <library.h> +#include "gmp_diffie_hellman.h" +#include "gmp_rsa_private_key.h" +#include "gmp_rsa_public_key.h" + +typedef struct private_gmp_plugin_t private_gmp_plugin_t; + +/** + * private data of gmp_plugin + */ +struct private_gmp_plugin_t { + + /** + * public functions + */ + gmp_plugin_t public; +}; + +/** + * Implementation of gmp_plugin_t.gmptroy + */ +static void destroy(private_gmp_plugin_t *this) +{ + lib->crypto->remove_dh(lib->crypto, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)gmp_rsa_private_key_builder); + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)gmp_rsa_public_key_builder); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_gmp_plugin_t *this = malloc_thing(private_gmp_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_dh(lib->crypto, MODP_768_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->crypto->add_dh(lib->crypto, MODP_1024_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->crypto->add_dh(lib->crypto, MODP_1536_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->crypto->add_dh(lib->crypto, MODP_2048_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->crypto->add_dh(lib->crypto, MODP_3072_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->crypto->add_dh(lib->crypto, MODP_4096_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->crypto->add_dh(lib->crypto, MODP_6144_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + lib->crypto->add_dh(lib->crypto, MODP_8192_BIT, + (dh_constructor_t)gmp_diffie_hellman_create); + + lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, + (builder_constructor_t)gmp_rsa_private_key_builder); + lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + (builder_constructor_t)gmp_rsa_public_key_builder); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/gmp/gmp_plugin.h b/src/libstrongswan/plugins/gmp/gmp_plugin.h new file mode 100644 index 000000000..a853064b7 --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup gmp_p gmp + * @ingroup plugins + * + * @defgroup gmp_plugin gmp_plugin + * @{ @ingroup gmp_p + */ + +#ifndef GMP_PLUGIN_H_ +#define GMP_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct gmp_plugin_t gmp_plugin_t; + +/** + * Plugin implementing asymmetric crypto algorithms using the GNU MP library. + */ +struct gmp_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a gmp_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* GMP_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c new file mode 100644 index 000000000..2315df595 --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c @@ -0,0 +1,844 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include <gmp.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> + +#include "gmp_rsa_private_key.h" +#include "gmp_rsa_public_key.h" + +#include <debug.h> +#include <asn1/asn1.h> +#include <utils/randomizer.h> +#include <crypto/hashers/hasher.h> + +/** + * Public exponent to use for key generation. + */ +#define PUBLIC_EXPONENT 0x10001 + +typedef struct private_gmp_rsa_private_key_t private_gmp_rsa_private_key_t; + +/** + * Private data of a gmp_rsa_private_key_t object. + */ +struct private_gmp_rsa_private_key_t { + /** + * Public interface for this signer. + */ + gmp_rsa_private_key_t public; + + /** + * Version of key, as encoded in PKCS#1 + */ + u_int version; + + /** + * Public modulus. + */ + mpz_t n; + + /** + * Public exponent. + */ + mpz_t e; + + /** + * Private prime 1. + */ + mpz_t p; + + /** + * Private Prime 2. + */ + mpz_t q; + + /** + * Private exponent. + */ + mpz_t d; + + /** + * Private exponent 1. + */ + mpz_t exp1; + + /** + * Private exponent 2. + */ + mpz_t exp2; + + /** + * Private coefficient. + */ + mpz_t coeff; + + /** + * Keysize in bytes. + */ + size_t k; + + /** + * Keyid formed as a SHA-1 hash of a publicKey object + */ + identification_t* keyid; + + /** + * Keyid formed as a SHA-1 hash of a publicKeyInfo object + */ + identification_t* keyid_info; + + /** + * reference count + */ + refcount_t ref; +}; + +/* ASN.1 definition of a PKCS#1 RSA private key */ +static const asn1Object_t privkey_objects[] = { + { 0, "RSAPrivateKey", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ + { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 2 */ + { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 3 */ + { 1, "privateExponent", ASN1_INTEGER, ASN1_BODY }, /* 4 */ + { 1, "prime1", ASN1_INTEGER, ASN1_BODY }, /* 5 */ + { 1, "prime2", ASN1_INTEGER, ASN1_BODY }, /* 6 */ + { 1, "exponent1", ASN1_INTEGER, ASN1_BODY }, /* 7 */ + { 1, "exponent2", ASN1_INTEGER, ASN1_BODY }, /* 8 */ + { 1, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 9 */ + { 1, "otherPrimeInfos", ASN1_SEQUENCE, ASN1_OPT | + ASN1_LOOP }, /* 10 */ + { 2, "otherPrimeInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */ + { 3, "prime", ASN1_INTEGER, ASN1_BODY }, /* 12 */ + { 3, "exponent", ASN1_INTEGER, ASN1_BODY }, /* 13 */ + { 3, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 14 */ + { 1, "end opt or loop", ASN1_EOC, ASN1_END } /* 15 */ +}; + +#define PRIV_KEY_VERSION 1 +#define PRIV_KEY_MODULUS 2 +#define PRIV_KEY_PUB_EXP 3 +#define PRIV_KEY_PRIV_EXP 4 +#define PRIV_KEY_PRIME1 5 +#define PRIV_KEY_PRIME2 6 +#define PRIV_KEY_EXP1 7 +#define PRIV_KEY_EXP2 8 +#define PRIV_KEY_COEFF 9 +#define PRIV_KEY_ROOF 16 + +/** + * defined in rsa_public_key.c + */ +bool gmp_rsa_public_key_build_id(mpz_t n, mpz_t e, identification_t **keyid, + identification_t **keyid_info); + +/** + * Auxiliary function overwriting private key material with + * pseudo-random bytes before releasing it + */ +static void mpz_clear_randomized(mpz_t z) +{ + size_t len = mpz_size(z) * GMP_LIMB_BITS / BITS_PER_BYTE; + u_int8_t *random_bytes = alloca(len); + + randomizer_t *randomizer = randomizer_create(); + + randomizer->get_pseudo_random_bytes(randomizer, len, random_bytes); + + /* overwrite mpz_t with pseudo-random bytes before clearing it */ + mpz_import(z, len, 1, 1, 1, 0, random_bytes); + mpz_clear(z); + + randomizer->destroy(randomizer); +} + +/** + * Create a mpz prime of at least prime_size + */ +static status_t compute_prime(private_gmp_rsa_private_key_t *this, + size_t prime_size, mpz_t *prime) +{ + randomizer_t *randomizer; + chunk_t random_bytes; + status_t status; + + randomizer = randomizer_create(); + mpz_init(*prime); + + do + { + status = randomizer->allocate_random_bytes(randomizer, prime_size, + &random_bytes); + if (status != SUCCESS) + { + randomizer->destroy(randomizer); + mpz_clear(*prime); + return FAILED; + } + /* make sure most significant bit is set */ + random_bytes.ptr[0] = random_bytes.ptr[0] | 0x80; + + mpz_import(*prime, random_bytes.len, 1, 1, 1, 0, random_bytes.ptr); + mpz_nextprime (*prime, *prime); + chunk_free_randomized(&random_bytes); + } + /* check if it isn't too large */ + while (((mpz_sizeinbase(*prime, 2) + 7) / 8) > prime_size); + + randomizer->destroy(randomizer); + return SUCCESS; +} + +/** + * PKCS#1 RSADP function + */ +static chunk_t rsadp(private_gmp_rsa_private_key_t *this, chunk_t data) +{ + mpz_t t1, t2; + chunk_t decrypted; + + mpz_init(t1); + mpz_init(t2); + + mpz_import(t1, data.len, 1, 1, 1, 0, data.ptr); + + mpz_powm(t2, t1, this->exp1, this->p); /* m1 = c^dP mod p */ + mpz_powm(t1, t1, this->exp2, this->q); /* m2 = c^dQ mod Q */ + mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */ + mpz_mod(t2, t2, this->p); + mpz_mul(t2, t2, this->coeff); + mpz_mod(t2, t2, this->p); + + mpz_mul(t2, t2, this->q); /* m = m2 + h q */ + mpz_add(t1, t1, t2); + + decrypted.len = this->k; + decrypted.ptr = mpz_export(NULL, NULL, 1, decrypted.len, 1, 0, t1); + + mpz_clear_randomized(t1); + mpz_clear_randomized(t2); + + return decrypted; +} + +/** + * PKCS#1 RSASP1 function + */ +static chunk_t rsasp1(private_gmp_rsa_private_key_t *this, chunk_t data) +{ + return rsadp(this, data); +} + +/** + * Implementation of gmp_rsa_private_key_t.build_emsa_pkcs1_signature. + */ +static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this, + hash_algorithm_t hash_algorithm, + chunk_t data, chunk_t *signature) +{ + hasher_t *hasher; + chunk_t em, digestInfo, hash; + int hash_oid = hasher_algorithm_to_oid(hash_algorithm); + + if (hash_oid == OID_UNKNOWN) + { + return FALSE; + } + + /* get hasher */ + hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm); + if (hasher == NULL) + { + return FALSE; + } + + /* build hash */ + hasher->allocate_hash(hasher, data, &hash); + hasher->destroy(hasher); + + /* build DER-encoded digestInfo */ + digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm", + asn1_algorithmIdentifier(hash_oid), + asn1_simple_object(ASN1_OCTET_STRING, hash) + ); + chunk_free(&hash); + + /* build chunk to rsa-decrypt: + * EM = 0x00 || 0x01 || PS || 0x00 || T. + * PS = 0xFF padding, with length to fill em + * T = encoded_hash + */ + em.len = this->k; + em.ptr = malloc(em.len); + + /* fill em with padding */ + memset(em.ptr, 0xFF, em.len); + /* set magic bytes */ + *(em.ptr) = 0x00; + *(em.ptr+1) = 0x01; + *(em.ptr + em.len - digestInfo.len - 1) = 0x00; + /* set DER-encoded hash */ + memcpy(em.ptr + em.len - digestInfo.len, digestInfo.ptr, digestInfo.len); + + /* build signature */ + *signature = rsasp1(this, em); + + free(digestInfo.ptr); + free(em.ptr); + + return TRUE; +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static key_type_t get_type(private_gmp_rsa_private_key_t *this) +{ + return KEY_RSA; +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static bool sign(private_gmp_rsa_private_key_t *this, signature_scheme_t scheme, + chunk_t data, chunk_t *signature) +{ + switch (scheme) + { + case SIGN_DEFAULT: + /* default is EMSA-PKCS1 using SHA1 */ + case SIGN_RSA_EMSA_PKCS1_SHA1: + return build_emsa_pkcs1_signature(this, HASH_SHA1, data, signature); + case SIGN_RSA_EMSA_PKCS1_SHA256: + return build_emsa_pkcs1_signature(this, HASH_SHA256, data, signature); + case SIGN_RSA_EMSA_PKCS1_SHA384: + return build_emsa_pkcs1_signature(this, HASH_SHA384, data, signature); + case SIGN_RSA_EMSA_PKCS1_SHA512: + return build_emsa_pkcs1_signature(this, HASH_SHA512, data, signature); + case SIGN_RSA_EMSA_PKCS1_MD5: + return build_emsa_pkcs1_signature(this, HASH_MD5, data, signature); + default: + DBG1("signature scheme %N not supported in RSA", + signature_scheme_names, scheme); + return FALSE; + } +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static bool decrypt(private_gmp_rsa_private_key_t *this, + chunk_t crypto, chunk_t *plain) +{ + DBG1("RSA private key decryption not implemented"); + return FALSE; +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static size_t get_keysize(private_gmp_rsa_private_key_t *this) +{ + return this->k; +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static identification_t* get_id(private_gmp_rsa_private_key_t *this, + id_type_t type) +{ + switch (type) + { + case ID_PUBKEY_INFO_SHA1: + return this->keyid_info; + case ID_PUBKEY_SHA1: + return this->keyid; + default: + return NULL; + } +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static gmp_rsa_public_key_t* get_public_key(private_gmp_rsa_private_key_t *this) +{ + DBG1("creating RSA public key from private key not implemented"); + return NULL; +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static bool belongs_to(private_gmp_rsa_private_key_t *this, public_key_t *public) +{ + identification_t *keyid; + + if (public->get_type(public) != KEY_RSA) + { + return FALSE; + } + keyid = public->get_id(public, ID_PUBKEY_SHA1); + if (keyid && keyid->equals(keyid, this->keyid)) + { + return TRUE; + } + keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1); + if (keyid && keyid->equals(keyid, this->keyid_info)) + { + return TRUE; + } + return FALSE; +} + +/** + * convert a MP integer into a DER coded ASN.1 object + */ +chunk_t gmp_mpz_to_asn1(const mpz_t value) +{ + size_t bits = mpz_sizeinbase(value, 2); /* size in bits */ + chunk_t n; + + n.len = 1 + bits / 8; /* size in bytes */ + n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, value); + + return asn1_wrap(ASN1_INTEGER, "m", n); +} + +/** + * Implementation of private_key_t.get_encoding. + */ +static chunk_t get_encoding(private_gmp_rsa_private_key_t *this) +{ + return asn1_wrap(ASN1_SEQUENCE, "cmmmmmmmm", + ASN1_INTEGER_0, + gmp_mpz_to_asn1(this->n), + gmp_mpz_to_asn1(this->e), + gmp_mpz_to_asn1(this->d), + gmp_mpz_to_asn1(this->p), + gmp_mpz_to_asn1(this->q), + gmp_mpz_to_asn1(this->exp1), + gmp_mpz_to_asn1(this->exp2), + gmp_mpz_to_asn1(this->coeff)); +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static private_gmp_rsa_private_key_t* get_ref(private_gmp_rsa_private_key_t *this) +{ + ref_get(&this->ref); + return this; + +} + +/** + * Implementation of gmp_rsa_private_key.destroy. + */ +static void destroy(private_gmp_rsa_private_key_t *this) +{ + if (ref_put(&this->ref)) + { + mpz_clear_randomized(this->n); + mpz_clear_randomized(this->e); + mpz_clear_randomized(this->p); + mpz_clear_randomized(this->q); + mpz_clear_randomized(this->d); + mpz_clear_randomized(this->exp1); + mpz_clear_randomized(this->exp2); + mpz_clear_randomized(this->coeff); + DESTROY_IF(this->keyid); + DESTROY_IF(this->keyid_info); + free(this); + } +} + +/** + * Check the loaded key if it is valid and usable + */ +static status_t check(private_gmp_rsa_private_key_t *this) +{ + mpz_t t, u, q1; + status_t status = SUCCESS; + + /* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets. + * We actually require more (for security). + */ + if (this->k < 512/8) + { + DBG1("key shorter than 512 bits"); + return FAILED; + } + + /* we picked a max modulus size to simplify buffer allocation */ + if (this->k > 8192/8) + { + DBG1("key larger thant 8192 bits"); + return FAILED; + } + + mpz_init(t); + mpz_init(u); + mpz_init(q1); + + /* check that n == p * q */ + mpz_mul(u, this->p, this->q); + if (mpz_cmp(u, this->n) != 0) + { + status = FAILED; + } + + /* check that e divides neither p-1 nor q-1 */ + mpz_sub_ui(t, this->p, 1); + mpz_mod(t, t, this->e); + if (mpz_cmp_ui(t, 0) == 0) + { + status = FAILED; + } + + mpz_sub_ui(t, this->q, 1); + mpz_mod(t, t, this->e); + if (mpz_cmp_ui(t, 0) == 0) + { + status = FAILED; + } + + /* check that d is e^-1 (mod lcm(p-1, q-1)) */ + /* see PKCS#1v2, aka RFC 2437, for the "lcm" */ + mpz_sub_ui(q1, this->q, 1); + mpz_sub_ui(u, this->p, 1); + mpz_gcd(t, u, q1); /* t := gcd(p-1, q-1) */ + mpz_mul(u, u, q1); /* u := (p-1) * (q-1) */ + mpz_divexact(u, u, t); /* u := lcm(p-1, q-1) */ + + mpz_mul(t, this->d, this->e); + mpz_mod(t, t, u); + if (mpz_cmp_ui(t, 1) != 0) + { + status = FAILED; + } + + /* check that exp1 is d mod (p-1) */ + mpz_sub_ui(u, this->p, 1); + mpz_mod(t, this->d, u); + if (mpz_cmp(t, this->exp1) != 0) + { + status = FAILED; + } + + /* check that exp2 is d mod (q-1) */ + mpz_sub_ui(u, this->q, 1); + mpz_mod(t, this->d, u); + if (mpz_cmp(t, this->exp2) != 0) + { + status = FAILED; + } + + /* check that coeff is (q^-1) mod p */ + mpz_mul(t, this->coeff, this->q); + mpz_mod(t, t, this->p); + if (mpz_cmp_ui(t, 1) != 0) + { + status = FAILED; + } + + mpz_clear_randomized(t); + mpz_clear_randomized(u); + mpz_clear_randomized(q1); + if (status != SUCCESS) + { + DBG1("key integrity tests failed"); + } + return status; +} + +/** + * Internal generic constructor + */ +static private_gmp_rsa_private_key_t *gmp_rsa_private_key_create_empty(void) +{ + private_gmp_rsa_private_key_t *this = malloc_thing(private_gmp_rsa_private_key_t); + + this->public.interface.get_type = (key_type_t (*)(private_key_t *this))get_type; + this->public.interface.sign = (bool (*)(private_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t *signature))sign; + this->public.interface.decrypt = (bool (*)(private_key_t *this, chunk_t crypto, chunk_t *plain))decrypt; + this->public.interface.get_keysize = (size_t (*) (private_key_t *this))get_keysize; + this->public.interface.get_id = (identification_t* (*) (private_key_t *this,id_type_t))get_id; + this->public.interface.get_public_key = (public_key_t* (*)(private_key_t *this))get_public_key; + this->public.interface.belongs_to = (bool (*) (private_key_t *this, public_key_t *public))belongs_to; + this->public.interface.get_encoding = (chunk_t(*)(private_key_t*))get_encoding; + this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref; + this->public.interface.destroy = (void (*)(private_key_t *this))destroy; + + this->keyid = NULL; + this->keyid_info = NULL; + this->ref = 1; + + return this; +} + +/** + * Generate an RSA key of specified key size + */ +static gmp_rsa_private_key_t *generate(size_t key_size) +{ + mpz_t p, q, n, e, d, exp1, exp2, coeff; + mpz_t m, q1, t; + private_gmp_rsa_private_key_t *this = gmp_rsa_private_key_create_empty(); + + key_size = key_size / 8; + + /* Get values of primes p and q */ + if (compute_prime(this, key_size/2, &p) != SUCCESS) + { + free(this); + return NULL; + } + if (compute_prime(this, key_size/2, &q) != SUCCESS) + { + mpz_clear(p); + free(this); + return NULL; + } + + mpz_init(t); + mpz_init(n); + mpz_init(d); + mpz_init(exp1); + mpz_init(exp2); + mpz_init(coeff); + + /* Swapping Primes so p is larger then q */ + if (mpz_cmp(p, q) < 0) + { + mpz_swap(p, q); + } + + mpz_mul(n, p, q); /* n = p*q */ + mpz_init_set_ui(e, PUBLIC_EXPONENT); /* assign public exponent */ + mpz_init_set(m, p); /* m = p */ + mpz_sub_ui(m, m, 1); /* m = m -1 */ + mpz_init_set(q1, q); /* q1 = q */ + mpz_sub_ui(q1, q1, 1); /* q1 = q1 -1 */ + mpz_gcd(t, m, q1); /* t = gcd(p-1, q-1) */ + mpz_mul(m, m, q1); /* m = (p-1)*(q-1) */ + mpz_divexact(m, m, t); /* m = m / t */ + mpz_gcd(t, m, e); /* t = gcd(m, e) */ + + mpz_invert(d, e, m); /* e has an inverse mod m */ + if (mpz_cmp_ui(d, 0) < 0) /* make sure d is positive */ + { + mpz_add(d, d, m); + } + mpz_sub_ui(t, p, 1); /* t = p-1 */ + mpz_mod(exp1, d, t); /* exp1 = d mod p-1 */ + mpz_sub_ui(t, q, 1); /* t = q-1 */ + mpz_mod(exp2, d, t); /* exp2 = d mod q-1 */ + + mpz_invert(coeff, q, p); /* coeff = q^-1 mod p */ + if (mpz_cmp_ui(coeff, 0) < 0) /* make coeff d is positive */ + { + mpz_add(coeff, coeff, p); + } + + mpz_clear_randomized(q1); + mpz_clear_randomized(m); + mpz_clear_randomized(t); + + /* apply values */ + *(this->p) = *p; + *(this->q) = *q; + *(this->n) = *n; + *(this->e) = *e; + *(this->d) = *d; + *(this->exp1) = *exp1; + *(this->exp2) = *exp2; + *(this->coeff) = *coeff; + + /* set key size in bytes */ + this->k = key_size; + + return &this->public; +} + +/** + * load private key from a ASN1 encoded blob + */ +static gmp_rsa_private_key_t *load(chunk_t blob) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + private_gmp_rsa_private_key_t *this = gmp_rsa_private_key_create_empty(); + + mpz_init(this->n); + mpz_init(this->e); + mpz_init(this->p); + mpz_init(this->q); + mpz_init(this->d); + mpz_init(this->exp1); + mpz_init(this->exp2); + mpz_init(this->coeff); + + asn1_init(&ctx, blob, 0, FALSE, TRUE); + + while (objectID < PRIV_KEY_ROOF) + { + if (!extract_object(privkey_objects, &objectID, &object, &level, &ctx)) + { + chunk_free_randomized(&blob); + destroy(this); + return NULL; + } + switch (objectID) + { + case PRIV_KEY_VERSION: + if (object.len > 0 && *object.ptr != 0) + { + chunk_free_randomized(&blob); + destroy(this); + return NULL; + } + break; + case PRIV_KEY_MODULUS: + mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PUB_EXP: + mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PRIV_EXP: + mpz_import(this->d, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PRIME1: + mpz_import(this->p, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PRIME2: + mpz_import(this->q, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_EXP1: + mpz_import(this->exp1, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_EXP2: + mpz_import(this->exp2, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_COEFF: + mpz_import(this->coeff, object.len, 1, 1, 1, 0, object.ptr); + break; + } + objectID++; + } + chunk_free_randomized(&blob); + + this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE; + if (!gmp_rsa_public_key_build_id(this->n, this->e, + &this->keyid, &this->keyid_info)) + { + destroy(this); + return NULL; + } + + if (check(this) != SUCCESS) + { + destroy(this); + return NULL; + } + return &this->public; +} + +typedef struct private_builder_t private_builder_t; +/** + * Builder implementation for key loading/generation + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** loaded/generated private key */ + gmp_rsa_private_key_t *key; +}; + +/** + * Implementation of builder_t.build + */ +static gmp_rsa_private_key_t *build(private_builder_t *this) +{ + gmp_rsa_private_key_t *key = this->key; + + free(this); + return key; +} + +/** + * Implementation of builder_t.add + */ +static void add(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + + if (this->key) + { + DBG1("ignoring surplus build part %N", builder_part_names, part); + return; + } + + switch (part) + { + case BUILD_BLOB_ASN1_DER: + { + va_start(args, part); + this->key = load(va_arg(args, chunk_t)); + va_end(args); + break; + } + case BUILD_KEY_SIZE: + { + va_start(args, part); + this->key = generate(va_arg(args, u_int)); + va_end(args); + break; + } + default: + DBG1("ignoring unsupported build part %N", builder_part_names, part); + break; + } +} + +/** + * Builder construction function + */ +builder_t *gmp_rsa_private_key_builder(key_type_t type) +{ + private_builder_t *this; + + if (type != KEY_RSA) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->key = NULL; + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; + this->public.build = (void*(*)(builder_t *this))build; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.h b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.h new file mode 100644 index 000000000..6f59b2ad2 --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup gmp_rsa_private_key gmp_rsa_private_key + * @{ @ingroup gmp_p + */ + +#ifndef GMP_RSA_PRIVATE_KEY_H_ +#define GMP_RSA_PRIVATE_KEY_H_ + +#include <credentials/keys/private_key.h> + +typedef struct gmp_rsa_private_key_t gmp_rsa_private_key_t; + +/** + * Private_key_t implementation of RSA algorithm using libgmp. + */ +struct gmp_rsa_private_key_t { + + /** + * Implements private_key_t interface + */ + private_key_t interface; +}; + +/** + * Create the builder for a private key. + * + * @param type type of the key, must be KEY_RSA + * @return builder instance + */ +builder_t *gmp_rsa_private_key_builder(key_type_t type); + +#endif /*GMP_RSA_PRIVATE_KEY_H_ @}*/ + diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c new file mode 100644 index 000000000..13ced714d --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c @@ -0,0 +1,574 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include <gmp.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> + +#include "gmp_rsa_public_key.h" + +#include <debug.h> +#include <crypto/hashers/hasher.h> +#include <asn1/asn1.h> +#include <asn1/pem.h> + +/** + * defined in gmp_rsa_private_key.c + */ +extern chunk_t gmp_mpz_to_asn1(const mpz_t value); + +/** + * ASN.1 definition of a subjectPublicKeyInfo structure + */ +static const asn1Object_t pkinfoObjects[] = { + { 0, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "algorithm", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 1, "subjectPublicKey", ASN1_BIT_STRING, ASN1_NONE }, /* 2 */ + { 2, "RSAPublicKey", ASN1_SEQUENCE, ASN1_RAW }, /* 3 */ +}; +#define PKINFO 0 +#define PKINFO_SUBJECT_PK_ALGORITHM 1 +#define PKINFO_SUBJECT_PK 2 +#define PKINFO_gmp_rsa_public_key 3 +#define PKINFO_ROOF 4 + +/* ASN.1 definition of RSApublicKey */ +static const asn1Object_t pubkeyObjects[] = { + { 0, "RSAPublicKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 1 */ + { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 2 */ +}; + +#define PUB_KEY_gmp_rsa_public_key 0 +#define PUB_KEY_MODULUS 1 +#define PUB_KEY_EXPONENT 2 +#define PUB_KEY_ROOF 3 + +/* ASN.1 definition of digestInfo */ +static const asn1Object_t digestInfoObjects[] = { + { 0, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ +}; + +#define DIGEST_INFO 0 +#define DIGEST_INFO_ALGORITHM 1 +#define DIGEST_INFO_DIGEST 2 +#define DIGEST_INFO_ROOF 3 + +typedef struct private_gmp_rsa_public_key_t private_gmp_rsa_public_key_t; + +/** + * Private data structure with signing context. + */ +struct private_gmp_rsa_public_key_t { + /** + * Public interface for this signer. + */ + gmp_rsa_public_key_t public; + + /** + * Public modulus. + */ + mpz_t n; + + /** + * Public exponent. + */ + mpz_t e; + + /** + * Keysize in bytes. + */ + size_t k; + + /** + * Keyid formed as a SHA-1 hash of a publicKeyInfo object + */ + identification_t *keyid_info; + + /** + * Keyid formed as a SHA-1 hash of a publicKey object + */ + identification_t *keyid; + + /** + * reference counter + */ + refcount_t ref; +}; + +/** + * RSAEP algorithm specified in PKCS#1. + */ +static chunk_t rsaep(private_gmp_rsa_public_key_t *this, chunk_t data) +{ + mpz_t m, c; + chunk_t encrypted; + + mpz_init(c); + mpz_init(m); + + mpz_import(m, data.len, 1, 1, 1, 0, data.ptr); + + mpz_powm(c, m, this->e, this->n); + + encrypted.len = this->k; + encrypted.ptr = mpz_export(NULL, NULL, 1, encrypted.len, 1, 0, c); + + mpz_clear(c); + mpz_clear(m); + + return encrypted; +} + +/** + * RSAVP1 algorithm specified in PKCS#1. + */ +static chunk_t rsavp1(private_gmp_rsa_public_key_t *this, chunk_t data) +{ + return rsaep(this, data); +} + +/** + * Verification of an EMPSA PKCS1 signature described in PKCS#1 + */ +static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, + hash_algorithm_t algorithm, + chunk_t data, chunk_t signature) +{ + chunk_t em_ori, em; + bool res = FALSE; + + /* remove any preceding 0-bytes from signature */ + while (signature.len && *(signature.ptr) == 0x00) + { + signature.len -= 1; + signature.ptr++; + } + + if (signature.len > this->k) + { + return INVALID_ARG; + } + + /* unpack signature */ + em_ori = em = rsavp1(this, signature); + + /* result should look like this: + * EM = 0x00 || 0x01 || PS || 0x00 || T. + * PS = 0xFF padding, with length to fill em + * T = oid || hash + */ + + /* check magic bytes */ + if (*(em.ptr) != 0x00 || *(em.ptr+1) != 0x01) + { + goto end; + } + em.ptr += 2; + em.len -= 2; + + /* find magic 0x00 */ + while (em.len > 0) + { + if (*em.ptr == 0x00) + { + /* found magic byte, stop */ + em.ptr++; + em.len--; + break; + } + else if (*em.ptr != 0xFF) + { + /* bad padding, decryption failed ?!*/ + goto end; + } + em.ptr++; + em.len--; + } + + if (em.len == 0) + { + /* no digestInfo found */ + goto end; + } + + /* parse ASN.1-based digestInfo */ + { + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + hash_algorithm_t hash_algorithm = HASH_UNKNOWN; + + asn1_init(&ctx, em, 0, FALSE, FALSE); + + while (objectID < DIGEST_INFO_ROOF) + { + if (!extract_object(digestInfoObjects, &objectID, &object, &level, &ctx)) + { + goto end; + } + switch (objectID) + { + case DIGEST_INFO: + { + if (em.len > object.len) + { + DBG1("digestInfo field in signature is followed by %u surplus bytes", + em.len - object.len); + goto end; + } + break; + } + case DIGEST_INFO_ALGORITHM: + { + int hash_oid = parse_algorithmIdentifier(object, level+1, NULL); + + hash_algorithm = hasher_algorithm_from_oid(hash_oid); + if (hash_algorithm == HASH_UNKNOWN || + (algorithm != HASH_UNKNOWN && hash_algorithm != algorithm)) + { + DBG1("wrong hash algorithm used in signature"); + goto end; + } + break; + } + case DIGEST_INFO_DIGEST: + { + chunk_t hash; + hasher_t *hasher; + + hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm); + if (hasher == NULL) + { + DBG1("hash algorithm %N not supported", + hash_algorithm_names, hash_algorithm); + goto end; + } + + if (object.len != hasher->get_hash_size(hasher)) + { + DBG1("hash size in signature is %u bytes instead of %u " + "bytes", object.len, hasher->get_hash_size(hasher)); + hasher->destroy(hasher); + goto end; + } + + /* build our own hash and compare */ + hasher->allocate_hash(hasher, data, &hash); + hasher->destroy(hasher); + res = memeq(object.ptr, hash.ptr, hash.len); + free(hash.ptr); + break; + } + default: + break; + } + objectID++; + } + } + +end: + free(em_ori.ptr); + return res; +} + +/** + * Implementation of public_key_t.get_type. + */ +static key_type_t get_type(private_gmp_rsa_public_key_t *this) +{ + return KEY_RSA; +} + +/** + * Implementation of public_key_t.verify. + */ +static bool verify(private_gmp_rsa_public_key_t *this, signature_scheme_t scheme, + chunk_t data, chunk_t signature) +{ + switch (scheme) + { + case SIGN_DEFAULT: /* default is EMSA-PKCS1 using included OID */ + return verify_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature); + case SIGN_RSA_EMSA_PKCS1_MD5: + return verify_emsa_pkcs1_signature(this, HASH_MD5, data, signature); + case SIGN_RSA_EMSA_PKCS1_SHA1: + return verify_emsa_pkcs1_signature(this, HASH_SHA1, data, signature); + case SIGN_RSA_EMSA_PKCS1_SHA256: + return verify_emsa_pkcs1_signature(this, HASH_SHA256, data, signature); + case SIGN_RSA_EMSA_PKCS1_SHA384: + return verify_emsa_pkcs1_signature(this, HASH_SHA384, data, signature); + case SIGN_RSA_EMSA_PKCS1_SHA512: + return verify_emsa_pkcs1_signature(this, HASH_SHA512, data, signature); + default: + DBG1("signature scheme %N not supported in RSA", + signature_scheme_names, scheme); + return FALSE; + } +} + +/** + * Implementation of public_key_t.get_keysize. + */ +static bool encrypt(private_gmp_rsa_public_key_t *this, chunk_t crypto, chunk_t *plain) +{ + DBG1("RSA public key encryption not implemented"); + return FALSE; +} + +/** + * Implementation of public_key_t.get_keysize. + */ +static size_t get_keysize(private_gmp_rsa_public_key_t *this) +{ + return this->k; +} + +/** + * Implementation of public_key_t.get_id. + */ +static identification_t *get_id(private_gmp_rsa_public_key_t *this, + id_type_t type) +{ + switch (type) + { + case ID_PUBKEY_INFO_SHA1: + return this->keyid_info; + case ID_PUBKEY_SHA1: + return this->keyid; + default: + return NULL; + } +} + +/* + * Implementation of public_key_t.get_encoding. + */ +static chunk_t get_encoding(private_gmp_rsa_public_key_t *this) +{ + return asn1_wrap(ASN1_SEQUENCE, "mm", + gmp_mpz_to_asn1(this->n), + gmp_mpz_to_asn1(this->e)); +} + +/** + * Implementation of public_key_t.get_ref. + */ +static private_gmp_rsa_public_key_t* get_ref(private_gmp_rsa_public_key_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of gmp_rsa_public_key.destroy. + */ +static void destroy(private_gmp_rsa_public_key_t *this) +{ + if (ref_put(&this->ref)) + { + mpz_clear(this->n); + mpz_clear(this->e); + DESTROY_IF(this->keyid); + DESTROY_IF(this->keyid_info); + free(this); + } +} + +/** + * Generic private constructor + */ +static private_gmp_rsa_public_key_t *gmp_rsa_public_key_create_empty() +{ + private_gmp_rsa_public_key_t *this = malloc_thing(private_gmp_rsa_public_key_t); + + this->public.interface.get_type = (key_type_t (*)(public_key_t *this))get_type; + this->public.interface.verify = (bool (*)(public_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t signature))verify; + this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt; + this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize; + this->public.interface.get_id = (identification_t* (*) (public_key_t *this,id_type_t))get_id; + this->public.interface.get_encoding = (chunk_t(*)(public_key_t*))get_encoding; + this->public.interface.get_ref = (public_key_t* (*)(public_key_t *this))get_ref; + this->public.interface.destroy = (void (*)(public_key_t *this))destroy; + + this->keyid = NULL; + this->keyid_info = NULL; + this->ref = 1; + + return this; +} + +/** + * Build the RSA key identifier from n and e using SHA1 hashed publicKey(Info). + * Also used in rsa_private_key.c. + */ +bool gmp_rsa_public_key_build_id(mpz_t n, mpz_t e, identification_t **keyid, + identification_t **keyid_info) +{ + chunk_t publicKeyInfo, publicKey, hash; + hasher_t *hasher; + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (hasher == NULL) + { + DBG1("SHA1 hash algorithm not supported, unable to use RSA"); + return FALSE; + } + publicKey = asn1_wrap(ASN1_SEQUENCE, "mm", + gmp_mpz_to_asn1(n), + gmp_mpz_to_asn1(e)); + hasher->allocate_hash(hasher, publicKey, &hash); + *keyid = identification_create_from_encoding(ID_PUBKEY_SHA1, hash); + chunk_free(&hash); + + publicKeyInfo = asn1_wrap(ASN1_SEQUENCE, "cm", + asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), + asn1_bitstring("m", publicKey)); + hasher->allocate_hash(hasher, publicKeyInfo, &hash); + *keyid_info = identification_create_from_encoding(ID_PUBKEY_INFO_SHA1, hash); + chunk_free(&hash); + + hasher->destroy(hasher); + chunk_free(&publicKeyInfo); + + return TRUE; +} + +/** + * Load a public key from an ASN1 encoded blob + */ +static gmp_rsa_public_key_t *load(chunk_t blob) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + private_gmp_rsa_public_key_t *this = gmp_rsa_public_key_create_empty(); + + mpz_init(this->n); + mpz_init(this->e); + + asn1_init(&ctx, blob, 0, FALSE, FALSE); + + while (objectID < PUB_KEY_ROOF) + { + if (!extract_object(pubkeyObjects, &objectID, &object, &level, &ctx)) + { + free(blob.ptr); + destroy(this); + return NULL; + } + switch (objectID) + { + case PUB_KEY_MODULUS: + mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr); + break; + case PUB_KEY_EXPONENT: + mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr); + break; + } + objectID++; + } + free(blob.ptr); + this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8; + if (!gmp_rsa_public_key_build_id(this->n, this->e, + &this->keyid, &this->keyid_info)) + { + destroy(this); + return NULL; + } + return &this->public; +} + + +typedef struct private_builder_t private_builder_t; +/** + * Builder implementation for key loading + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** loaded public key */ + gmp_rsa_public_key_t *key; +}; + +/** + * Implementation of builder_t.build + */ +static gmp_rsa_public_key_t *build(private_builder_t *this) +{ + gmp_rsa_public_key_t *key = this->key; + + free(this); + return key; +} + +/** + * Implementation of builder_t.add + */ +static void add(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + + if (this->key) + { + DBG1("ignoring surplus build part %N", builder_part_names, part); + return; + } + + switch (part) + { + case BUILD_BLOB_ASN1_DER: + { + va_start(args, part); + this->key = load(va_arg(args, chunk_t)); + va_end(args); + break; + } + default: + DBG1("ignoring unsupported build part %N", builder_part_names, part); + break; + } +} + +/** + * Builder construction function + */ +builder_t *gmp_rsa_public_key_builder(key_type_t type) +{ + private_builder_t *this; + + if (type != KEY_RSA) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->key = NULL; + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; + this->public.build = (void*(*)(builder_t *this))build; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.h b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.h new file mode 100644 index 000000000..e471cd067 --- /dev/null +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup gmp_rsa_public_key gmp_rsa_public_key + * @{ @ingroup gmp_p + */ + +#ifndef GMP_RSA_PUBLIC_KEY_H_ +#define GMP_RSA_PUBLIC_KEY_H_ + +typedef struct gmp_rsa_public_key_t gmp_rsa_public_key_t; + +#include <credentials/keys/public_key.h> + +/** + * public_key_t implementation of RSA algorithm using libgmp. + */ +struct gmp_rsa_public_key_t { + + /** + * Implements the public_key_t interface + */ + public_key_t interface; +}; + +/** + * Create the builder for a public key. + * + * @param type type of the key, must be KEY_RSA + * @return builder instance + */ +builder_t *gmp_rsa_public_key_builder(key_type_t type); + +#endif /*GMP_RSA_PUBLIC_KEY_H_ @}*/ diff --git a/src/libstrongswan/plugins/hmac/Makefile.am b/src/libstrongswan/plugins/hmac/Makefile.am new file mode 100644 index 000000000..89e0638f3 --- /dev/null +++ b/src/libstrongswan/plugins/hmac/Makefile.am @@ -0,0 +1,11 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-hmac.la + +libstrongswan_hmac_la_SOURCES = hmac_plugin.h hmac_plugin.c hmac.h hmac.c \ + hmac_prf.h hmac_prf.c hmac_signer.h hmac_signer.c +libstrongswan_hmac_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/hmac/hmac.c b/src/libstrongswan/plugins/hmac/hmac.c new file mode 100644 index 000000000..2b41bf4aa --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General hmac License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General hmac License + * for more details. + * + * $Id$ + */ + +#include <string.h> + +#include "hmac.h" + + +typedef struct private_hmac_t private_hmac_t; + +/** + * Private data of a hmac_t object. + * + * The variable names are the same as in the RFC. + */ +struct private_hmac_t { + /** + * Public hmac_t interface. + */ + hmac_t hmac; + + /** + * Block size, as in RFC. + */ + u_int8_t b; + + /** + * Hash function. + */ + hasher_t *h; + + /** + * Previously xor'ed key using opad. + */ + chunk_t opaded_key; + + /** + * Previously xor'ed key using ipad. + */ + chunk_t ipaded_key; +}; + +/** + * Implementation of hmac_t.get_mac. + */ +static void get_mac(private_hmac_t *this, chunk_t data, u_int8_t *out) +{ + /* H(K XOR opad, H(K XOR ipad, text)) + * + * if out is NULL, we append text to the inner hash. + * else, we complete the inner and do the outer. + * + */ + + u_int8_t buffer[this->h->get_hash_size(this->h)]; + chunk_t inner; + + if (out == NULL) + { + /* append data to inner */ + this->h->get_hash(this->h, data, NULL); + } + else + { + /* append and do outer hash */ + inner.ptr = buffer; + inner.len = this->h->get_hash_size(this->h); + + /* complete inner */ + this->h->get_hash(this->h, data, buffer); + + /* do outer */ + this->h->get_hash(this->h, this->opaded_key, NULL); + this->h->get_hash(this->h, inner, out); + + /* reinit for next call */ + this->h->get_hash(this->h, this->ipaded_key, NULL); + } +} + +/** + * Implementation of hmac_t.allocate_mac. + */ +static void allocate_mac(private_hmac_t *this, chunk_t data, chunk_t *out) +{ + /* allocate space and use get_mac */ + if (out == NULL) + { + /* append mode */ + this->hmac.get_mac(&(this->hmac), data, NULL); + } + else + { + out->len = this->h->get_hash_size(this->h); + out->ptr = malloc(out->len); + this->hmac.get_mac(&(this->hmac), data, out->ptr); + } +} + +/** + * Implementation of hmac_t.get_block_size. + */ +static size_t get_block_size(private_hmac_t *this) +{ + return this->h->get_hash_size(this->h); +} + +/** + * Implementation of hmac_t.set_key. + */ +static void set_key(private_hmac_t *this, chunk_t key) +{ + int i; + u_int8_t buffer[this->b]; + + memset(buffer, 0, this->b); + + if (key.len > this->b) + { + /* if key is too long, it will be hashed */ + this->h->get_hash(this->h, key, buffer); + } + else + { + /* if not, just copy it in our pre-padded k */ + memcpy(buffer, key.ptr, key.len); + } + + /* apply ipad and opad to key */ + for (i = 0; i < this->b; i++) + { + this->ipaded_key.ptr[i] = buffer[i] ^ 0x36; + this->opaded_key.ptr[i] = buffer[i] ^ 0x5C; + } + + /* begin hashing of inner pad */ + this->h->reset(this->h); + this->h->get_hash(this->h, this->ipaded_key, NULL); +} + +/** + * Implementation of hmac_t.destroy. + */ +static void destroy(private_hmac_t *this) +{ + this->h->destroy(this->h); + free(this->opaded_key.ptr); + free(this->ipaded_key.ptr); + free(this); +} + +/* + * Described in header + */ +hmac_t *hmac_create(hash_algorithm_t hash_algorithm) +{ + private_hmac_t *this = malloc_thing(private_hmac_t); + + /* set hmac_t methods */ + this->hmac.get_mac = (void (*)(hmac_t *,chunk_t,u_int8_t*))get_mac; + this->hmac.allocate_mac = (void (*)(hmac_t *,chunk_t,chunk_t*))allocate_mac; + this->hmac.get_block_size = (size_t (*)(hmac_t *))get_block_size; + this->hmac.set_key = (void (*)(hmac_t *,chunk_t))set_key; + this->hmac.destroy = (void (*)(hmac_t *))destroy; + + /* set b, according to hasher */ + switch (hash_algorithm) + { + case HASH_SHA1: + case HASH_MD5: + case HASH_SHA256: + this->b = 64; + break; + case HASH_SHA384: + case HASH_SHA512: + this->b = 128; + break; + default: + free(this); + return NULL; + } + + /* build the hasher */ + this->h = lib->crypto->create_hasher(lib->crypto, hash_algorithm); + if (this->h == NULL) + { + free(this); + return NULL; + } + + /* build ipad and opad */ + this->opaded_key.ptr = malloc(this->b); + this->opaded_key.len = this->b; + + this->ipaded_key.ptr = malloc(this->b); + this->ipaded_key.len = this->b; + + return &(this->hmac); +} diff --git a/src/libstrongswan/plugins/hmac/hmac.h b/src/libstrongswan/plugins/hmac/hmac.h new file mode 100644 index 000000000..5f266e133 --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup hmac hmac + * @{ @ingroup hmac_p + */ + +#ifndef HMAC_H_ +#define HMAC_H_ + +typedef struct hmac_t hmac_t; + +#include <crypto/hashers/hasher.h> + +/** + * Message authentication using hash functions. + * + * This class implements the message authenticaion algorithm + * described in RFC2104. It uses a hash function, wich must + * be implemented as a hasher_t class. + */ +struct hmac_t { + /** + * Generate message authentication code. + * + * If buffer is NULL, no result is given back. A next call will + * append the data to already supplied data. If buffer is not NULL, + * the mac of all apended data is calculated, returned and the + * state of the hmac_t is reseted. + * + * @param data chunk of data to authenticate + * @param buffer pointer where the generated bytes will be written + */ + void (*get_mac) (hmac_t *this, chunk_t data, u_int8_t *buffer); + + /** + * Generates message authentication code and allocate space for them. + * + * If chunk is NULL, no result is given back. A next call will + * append the data to already supplied. If chunk is not NULL, + * the mac of all apended data is calculated, returned and the + * state of the hmac_t reset; + * + * @param data chunk of data to authenticate + * @param chunk chunk which will hold generated bytes + */ + void (*allocate_mac) (hmac_t *this, chunk_t data, chunk_t *chunk); + + /** + * Get the block size of this hmac_t object. + * + * @return block size in bytes + */ + size_t (*get_block_size) (hmac_t *this); + + /** + * Set the key for this hmac_t object. + * + * Any key length is accepted. + * + * @param key key to set + */ + void (*set_key) (hmac_t *this, chunk_t key); + + /** + * Destroys a hmac_t object. + */ + void (*destroy) (hmac_t *this); +}; + +/** + * Creates a new hmac_t object. + * + * @param hash_algorithm hash algorithm to use + * @return hmac_t object, NULL if not supported + */ +hmac_t *hmac_create(hash_algorithm_t hash_algorithm); + +#endif /*HMAC_H_ @}*/ diff --git a/src/libstrongswan/plugins/hmac/hmac_plugin.c b/src/libstrongswan/plugins/hmac/hmac_plugin.c new file mode 100644 index 000000000..246fbb031 --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac_plugin.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "hmac_plugin.h" + +#include <library.h> +#include "hmac_signer.h" +#include "hmac_prf.h" + +typedef struct private_hmac_plugin_t private_hmac_plugin_t; + +/** + * private data of hmac_plugin + */ +struct private_hmac_plugin_t { + + /** + * public functions + */ + hmac_plugin_t public; +}; + +/** + * Implementation of hmac_plugin_t.hmactroy + */ +static void destroy(private_hmac_plugin_t *this) +{ + lib->crypto->remove_prf(lib->crypto, + (prf_constructor_t)hmac_prf_create); + lib->crypto->remove_signer(lib->crypto, + (signer_constructor_t)hmac_signer_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_hmac_plugin_t *this = malloc_thing(private_hmac_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_prf(lib->crypto, PRF_HMAC_MD5, + (prf_constructor_t)hmac_prf_create); + lib->crypto->add_prf(lib->crypto, PRF_HMAC_SHA1, + (prf_constructor_t)hmac_prf_create); + lib->crypto->add_prf(lib->crypto, PRF_HMAC_SHA2_256, + (prf_constructor_t)hmac_prf_create); + lib->crypto->add_prf(lib->crypto, PRF_HMAC_SHA2_384, + (prf_constructor_t)hmac_prf_create); + lib->crypto->add_prf(lib->crypto, PRF_HMAC_SHA2_512, + (prf_constructor_t)hmac_prf_create); + + lib->crypto->add_signer(lib->crypto, AUTH_HMAC_MD5_96, + (signer_constructor_t)hmac_signer_create); + lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA1_96, + (signer_constructor_t)hmac_signer_create); + lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA1_128, + (signer_constructor_t)hmac_signer_create); + lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA2_256_128, + (signer_constructor_t)hmac_signer_create); + lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA2_384_192, + (signer_constructor_t)hmac_signer_create); + lib->crypto->add_signer(lib->crypto, AUTH_HMAC_SHA2_512_256, + (signer_constructor_t)hmac_signer_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/hmac/hmac_plugin.h b/src/libstrongswan/plugins/hmac/hmac_plugin.h new file mode 100644 index 000000000..55ba0b5f4 --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup hmac_p hmac + * @ingroup plugins + * + * @defgroup hmac_plugin hmac_plugin + * @{ @ingroup hmac_p + */ + +#ifndef HMAC_PLUGIN_H_ +#define HMAC_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct hmac_plugin_t hmac_plugin_t; + +/** + * Plugin implementing HMAC algorithm to prvoide hash based PRF and signers. + */ +struct hmac_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a hmac_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* HMAC_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/hmac/hmac_prf.c b/src/libstrongswan/plugins/hmac/hmac_prf.c new file mode 100644 index 000000000..02159bb1b --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac_prf.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "hmac_prf.h" + +#include "hmac.h" + + +typedef struct private_hmac_prf_t private_hmac_prf_t; + +/** + * Private data of a hma_prf_t object. + */ +struct private_hmac_prf_t { + /** + * Public hmac_prf_t interface. + */ + hmac_prf_t public; + + /** + * Hmac to use for generation. + */ + hmac_t *hmac; +}; + +/** + * Implementation of prf_t.get_bytes. + */ +static void get_bytes(private_hmac_prf_t *this, chunk_t seed, u_int8_t *buffer) +{ + this->hmac->get_mac(this->hmac, seed, buffer); +} + +/** + * Implementation of prf_t.allocate_bytes. + */ +static void allocate_bytes(private_hmac_prf_t *this, chunk_t seed, chunk_t *chunk) +{ + this->hmac->allocate_mac(this->hmac, seed, chunk); +} + +/** + * Implementation of prf_t.get_block_size. + */ +static size_t get_block_size(private_hmac_prf_t *this) +{ + return this->hmac->get_block_size(this->hmac); +} + +/** + * Implementation of prf_t.get_block_size. + */ +static size_t get_key_size(private_hmac_prf_t *this) +{ + /* for HMAC prfs, IKEv2 uses block size as key size */ + return this->hmac->get_block_size(this->hmac); +} + +/** + * Implementation of prf_t.set_key. + */ +static void set_key(private_hmac_prf_t *this, chunk_t key) +{ + this->hmac->set_key(this->hmac, key); +} + +/** + * Implementation of prf_t.destroy. + */ +static void destroy(private_hmac_prf_t *this) +{ + this->hmac->destroy(this->hmac); + free(this); +} + +/* + * Described in header. + */ +hmac_prf_t *hmac_prf_create(pseudo_random_function_t algo) +{ + private_hmac_prf_t *this; + hash_algorithm_t hash; + + switch (algo) + { + case PRF_HMAC_SHA1: + hash = HASH_SHA1; + break; + case PRF_HMAC_MD5: + hash = HASH_MD5; + break; + case PRF_HMAC_SHA2_256: + hash = HASH_SHA256; + break; + case PRF_HMAC_SHA2_384: + hash = HASH_SHA384; + break; + case PRF_HMAC_SHA2_512: + hash = HASH_SHA512; + break; + default: + return NULL; + } + + this = malloc_thing(private_hmac_prf_t); + this->hmac = hmac_create(hash); + if (this->hmac == NULL) + { + free(this); + return NULL; + } + + this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes; + this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes; + this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size; + this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size; + this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key; + this->public.prf_interface.destroy = (void (*) (prf_t *))destroy; + + return &(this->public); +} + diff --git a/src/libstrongswan/plugins/hmac/hmac_prf.h b/src/libstrongswan/plugins/hmac/hmac_prf.h new file mode 100644 index 000000000..46d05f03a --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac_prf.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup hmac_prf hmac_prf + * @{ @ingroup hmac_p + */ + +#ifndef PRF_HMAC_H_ +#define PRF_HMAC_H_ + +typedef struct hmac_prf_t hmac_prf_t; + +#include <crypto/prfs/prf.h> + +/** + * Implementation of prf_t interface using the HMAC algorithm. + * + * This simply wraps a hmac_t in a prf_t. More a question of + * interface matching. + */ +struct hmac_prf_t { + + /** + * Generic prf_t interface for this hmac_prf_t class. + */ + prf_t prf_interface; +}; + +/** + * Creates a new hmac_prf_t object. + * + * @param algo algorithm to implement + * @return hmac_prf_t object, NULL if hash not supported + */ +hmac_prf_t *hmac_prf_create(pseudo_random_function_t algo); + +#endif /*PRF_HMAC_SHA1_H_ @}*/ diff --git a/src/libstrongswan/plugins/hmac/hmac_signer.c b/src/libstrongswan/plugins/hmac/hmac_signer.c new file mode 100644 index 000000000..1b6f80d7b --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac_signer.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include <string.h> + +#include "hmac_signer.h" +#include "hmac.h" + +typedef struct private_hmac_signer_t private_hmac_signer_t; + +/** + * Private data structure with signing context. + */ +struct private_hmac_signer_t { + /** + * Public interface of hmac_signer_t. + */ + hmac_signer_t public; + + /** + * Assigned hmac function. + */ + hmac_t *hmac; + + /** + * Block size (truncation of HMAC Hash) + */ + size_t block_size; +}; + +/** + * Implementation of signer_t.get_signature. + */ +static void get_signature(private_hmac_signer_t *this, + chunk_t data, u_int8_t *buffer) +{ + if (buffer == NULL) + { /* append mode */ + this->hmac->get_mac(this->hmac, data, NULL); + } + else + { + u_int8_t mac[this->hmac->get_block_size(this->hmac)]; + + this->hmac->get_mac(this->hmac, data, mac); + memcpy(buffer, mac, this->block_size); + } +} + +/** + * Implementation of signer_t.allocate_signature. + */ +static void allocate_signature (private_hmac_signer_t *this, + chunk_t data, chunk_t *chunk) +{ + if (chunk == NULL) + { /* append mode */ + this->hmac->get_mac(this->hmac, data, NULL); + } + else + { + u_int8_t mac[this->hmac->get_block_size(this->hmac)]; + + this->hmac->get_mac(this->hmac, data, mac); + + chunk->ptr = malloc(this->block_size); + chunk->len = this->block_size; + + memcpy(chunk->ptr, mac, this->block_size); + } +} + +/** + * Implementation of signer_t.verify_signature. + */ +static bool verify_signature(private_hmac_signer_t *this, + chunk_t data, chunk_t signature) +{ + u_int8_t mac[this->hmac->get_block_size(this->hmac)]; + + this->hmac->get_mac(this->hmac, data, mac); + + if (signature.len != this->block_size) + { + return FALSE; + } + return memeq(signature.ptr, mac, this->block_size); +} + +/** + * Implementation of signer_t.get_key_size. + */ +static size_t get_key_size(private_hmac_signer_t *this) +{ + return this->hmac->get_block_size(this->hmac); +} + +/** + * Implementation of signer_t.get_block_size. + */ +static size_t get_block_size(private_hmac_signer_t *this) +{ + return this->block_size; +} + +/** + * Implementation of signer_t.set_key. + */ +static void set_key(private_hmac_signer_t *this, chunk_t key) +{ + this->hmac->set_key(this->hmac, key); +} + +/** + * Implementation of signer_t.destroy. + */ +static status_t destroy(private_hmac_signer_t *this) +{ + this->hmac->destroy(this->hmac); + free(this); + return SUCCESS; +} + +/* + * Described in header + */ +hmac_signer_t *hmac_signer_create(integrity_algorithm_t algo) +{ + private_hmac_signer_t *this; + size_t trunc; + hash_algorithm_t hash; + + switch (algo) + { + case AUTH_HMAC_SHA1_96: + hash = HASH_SHA1; + trunc = 12; + break; + case AUTH_HMAC_SHA1_128: + hash = HASH_SHA1; + trunc = 16; + break; + case AUTH_HMAC_MD5_96: + hash = HASH_MD5; + trunc = 12; + break; + case AUTH_HMAC_SHA2_256_128: + hash = HASH_SHA256; + trunc = 16; + break; + case AUTH_HMAC_SHA2_384_192: + hash = HASH_SHA384; + trunc = 24; + break; + case AUTH_HMAC_SHA2_512_256: + hash = HASH_SHA512; + trunc = 32; + break; + default: + return NULL; + } + + this = malloc_thing(private_hmac_signer_t); + this->hmac = hmac_create(hash); + if (this->hmac == NULL) + { + free(this); + return NULL; + } + /* prevent invalid truncation */ + this->block_size = min(trunc, this->hmac->get_block_size(this->hmac)); + + /* interface functions */ + this->public.signer_interface.get_signature = (void (*) (signer_t*, chunk_t, u_int8_t*))get_signature; + this->public.signer_interface.allocate_signature = (void (*) (signer_t*, chunk_t, chunk_t*))allocate_signature; + this->public.signer_interface.verify_signature = (bool (*) (signer_t*, chunk_t, chunk_t))verify_signature; + this->public.signer_interface.get_key_size = (size_t (*) (signer_t*))get_key_size; + this->public.signer_interface.get_block_size = (size_t (*) (signer_t*))get_block_size; + this->public.signer_interface.set_key = (void (*) (signer_t*,chunk_t))set_key; + this->public.signer_interface.destroy = (void (*) (signer_t*))destroy; + + return &(this->public); +} + diff --git a/src/libstrongswan/plugins/hmac/hmac_signer.h b/src/libstrongswan/plugins/hmac/hmac_signer.h new file mode 100644 index 000000000..969f482e7 --- /dev/null +++ b/src/libstrongswan/plugins/hmac/hmac_signer.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup hmac_signer hmac_signer + * @{ @ingroup hmac_p + */ + +#ifndef HMAC_SIGNER_H_ +#define HMAC_SIGNER_H_ + +typedef struct hmac_signer_t hmac_signer_t; + +#include <crypto/signers/signer.h> + +/** + * Implementation of signer_t interface using HMAC. + * + * HMAC uses a standard hash function implemented in a hasher_t to build a MAC. + */ +struct hmac_signer_t { + + /** + * generic signer_t interface for this signer + */ + signer_t signer_interface; +}; + +/** + * Creates a new hmac_signer_t. + * + * HMAC signatures are often truncated to shorten them to a more usable, but + * still secure enough length. + * Block size must be equal or smaller then the hash algorithms + * hash. + * + * @param algo algorithm to implement + * @return hmac_signer_t, NULL if not supported + */ +hmac_signer_t *hmac_signer_create(integrity_algorithm_t algo); + +#endif /*HMAC_SIGNER_H_ @}*/ diff --git a/src/libstrongswan/plugins/ldap/Makefile.am b/src/libstrongswan/plugins/ldap/Makefile.am new file mode 100644 index 000000000..ac6b4be00 --- /dev/null +++ b/src/libstrongswan/plugins/ldap/Makefile.am @@ -0,0 +1,11 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-ldap.la + +libstrongswan_ldap_la_SOURCES = ldap_plugin.h ldap_plugin.c ldap_fetcher.h ldap_fetcher.c +libstrongswan_ldap_la_LDFLAGS = -module +libstrongswan_ldap_la_LIBADD = -lldap -llber + diff --git a/src/libstrongswan/plugins/ldap/ldap_fetcher.c b/src/libstrongswan/plugins/ldap/ldap_fetcher.c new file mode 100644 index 000000000..501927d33 --- /dev/null +++ b/src/libstrongswan/plugins/ldap/ldap_fetcher.c @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2007 Andreas Steffen + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#ifndef LDAP_DEPRECATED +#define LDAP_DEPRECATED 1 +#endif /* LDAP_DEPRECATED */ +#include <ldap.h> + +#include <errno.h> + +#include <library.h> +#include <debug.h> + +#include "ldap_fetcher.h" + +#define DEFAULT_TIMEOUT 10 + +typedef struct private_ldap_fetcher_t private_ldap_fetcher_t; + +/** + * Private Data of a ldap_fetcher_t object. + */ +struct private_ldap_fetcher_t { + /** + * Public data + */ + ldap_fetcher_t public; + + /** + * timeout to use for fetches + */ + u_int timeout; +}; + +/** + * Parses the result returned by an ldap query + */ +static bool parse(LDAP *ldap, LDAPMessage *result, chunk_t *response) +{ + LDAPMessage *entry = ldap_first_entry(ldap, result); + bool success = FALSE; + + if (entry) + { + BerElement *ber = NULL; + char *attr; + + attr = ldap_first_attribute(ldap, entry, &ber); + if (attr) + { + struct berval **values = ldap_get_values_len(ldap, entry, attr); + + if (values) + { + if (values[0]) + { + *response = chunk_alloc(values[0]->bv_len); + memcpy(response->ptr, values[0]->bv_val, response->len); + success = TRUE; + } + else + { + DBG1("LDAP response contains no values"); + } + ldap_value_free_len(values); + } + else + { + DBG1("getting LDAP values failed: %s", + ldap_err2string(ldap_result2error(ldap, entry, 0))); + } + ldap_memfree(attr); + } + else + { + DBG1("finding LDAP attributes failed: %s", + ldap_err2string(ldap_result2error(ldap, entry, 0))); + } + ber_free(ber, 0); + } + else + { + DBG1("finding first LDAP entry failed: %s", + ldap_err2string(ldap_result2error(ldap, entry, 0))); + } + return success; +} + + +static status_t fetch(private_ldap_fetcher_t *this, char *url, + chunk_t *result, va_list args) +{ + LDAP *ldap; + LDAPURLDesc *lurl; + LDAPMessage *msg; + int res; + int ldap_version = LDAP_VERSION3; + struct timeval timeout; + status_t status = FAILED; + + if (!strneq(url, "ldap", 4)) + { + return NOT_SUPPORTED; + } + if (ldap_url_parse(url, &lurl) != LDAP_SUCCESS) + { + return NOT_SUPPORTED; + } + ldap = ldap_init(lurl->lud_host, lurl->lud_port); + if (ldap == NULL) + { + DBG1("LDAP initialization failed: %s", strerror(errno)); + ldap_free_urldesc(lurl); + return FAILED; + } + + timeout.tv_sec = this->timeout; + timeout.tv_usec = 0; + + ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version); + ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout); + + DBG1("sending LDAP request to '%s'...", url); + + res = ldap_simple_bind_s(ldap, NULL, NULL); + if (res == LDAP_SUCCESS) + { + res = ldap_search_st(ldap, lurl->lud_dn, lurl->lud_scope, + lurl->lud_filter, lurl->lud_attrs, + 0, &timeout, &msg); + + if (res == LDAP_SUCCESS) + { + if (parse(ldap, msg, result)) + { + status = SUCCESS; + } + ldap_msgfree(msg); + } + else + { + DBG1("LDAP search failed: %s", ldap_err2string(res)); + } + } + else + { + DBG1("LDAP bind to '%s' failed: %s", url, ldap_err2string(res)); + } + ldap_unbind_s(ldap); + ldap_free_urldesc(lurl); + return status; +} + + +/** + * Implementation of fetcher_t.set_option. + */ +static bool set_option(private_ldap_fetcher_t *this, fetcher_option_t option, ...) +{ + va_list args; + + va_start(args, option); + switch (option) + { + case FETCH_TIMEOUT: + { + this->timeout = va_arg(args, u_int); + return TRUE; + } + default: + return FALSE; + } +} + +/** + * Implements ldap_fetcher_t.destroy + */ +static void destroy(private_ldap_fetcher_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +ldap_fetcher_t *ldap_fetcher_create() +{ + private_ldap_fetcher_t *this = malloc_thing(private_ldap_fetcher_t); + + this->public.interface.fetch = (status_t(*)(fetcher_t*,char*,chunk_t*))fetch; + this->public.interface.set_option = (bool(*)(fetcher_t*, fetcher_option_t option, ...))set_option; + this->public.interface.destroy = (void (*)(fetcher_t*))destroy; + + this->timeout = DEFAULT_TIMEOUT; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/ldap/ldap_fetcher.h b/src/libstrongswan/plugins/ldap/ldap_fetcher.h new file mode 100644 index 000000000..bde60c799 --- /dev/null +++ b/src/libstrongswan/plugins/ldap/ldap_fetcher.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ldap_fetcher ldap_fetcher + * @{ @ingroup ldap_p + */ + +#ifndef LDAP_FETCHER_H_ +#define LDAP_FETCHER_H_ + +typedef struct ldap_fetcher_t ldap_fetcher_t; + +/** + * Fetcher implementation using OpenLDAP. + */ +struct ldap_fetcher_t { + + /** + * Implements fetcher interface + */ + fetcher_t interface; +}; + +/** + * Create a ldap_fetcher instance. + */ +ldap_fetcher_t *ldap_fetcher_create(); + +#endif /* LDAP_FETCHER_H_ @}*/ diff --git a/src/libstrongswan/plugins/ldap/ldap_plugin.c b/src/libstrongswan/plugins/ldap/ldap_plugin.c new file mode 100644 index 000000000..f063ef791 --- /dev/null +++ b/src/libstrongswan/plugins/ldap/ldap_plugin.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "ldap_plugin.h" + +#include <library.h> +#include "ldap_fetcher.h" + +typedef struct private_ldap_plugin_t private_ldap_plugin_t; + +/** + * private data of ldap_plugin + */ +struct private_ldap_plugin_t { + + /** + * public functions + */ + ldap_plugin_t public; +}; + +/** + * Implementation of ldap_plugin_t.destroy + */ +static void destroy(private_ldap_plugin_t *this) +{ + lib->fetcher->remove_fetcher(lib->fetcher, + (fetcher_constructor_t)ldap_fetcher_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_ldap_plugin_t *this = malloc_thing(private_ldap_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->fetcher->add_fetcher(lib->fetcher, + (fetcher_constructor_t)ldap_fetcher_create, "ldap://"); + lib->fetcher->add_fetcher(lib->fetcher, + (fetcher_constructor_t)ldap_fetcher_create, "ldaps://"); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/ldap/ldap_plugin.h b/src/libstrongswan/plugins/ldap/ldap_plugin.h new file mode 100644 index 000000000..7b2bb3232 --- /dev/null +++ b/src/libstrongswan/plugins/ldap/ldap_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ldap_p ldap + * @ingroup plugins + * + * @defgroup ldap_plugin ldap_plugin + * @{ @ingroup ldap_p + */ + +#ifndef LDAP_PLUGIN_H_ +#define LDAP_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct ldap_plugin_t ldap_plugin_t; + +/** + * Plugin implementing LDAP fetcher using OpenLDAP. + */ +struct ldap_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a ldap_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* LDAP_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/md5/Makefile.am b/src/libstrongswan/plugins/md5/Makefile.am new file mode 100644 index 000000000..0a9c5cbf4 --- /dev/null +++ b/src/libstrongswan/plugins/md5/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-md5.la + +libstrongswan_md5_la_SOURCES = md5_plugin.h md5_plugin.c md5_hasher.c md5_hasher.h +libstrongswan_md5_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/md5/md5_hasher.c b/src/libstrongswan/plugins/md5/md5_hasher.c new file mode 100644 index 000000000..8b24f8cb2 --- /dev/null +++ b/src/libstrongswan/plugins/md5/md5_hasher.c @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * Copyright (C) 1991-1992, RSA Data Security, Inc. Created 1991. + * All rights reserved. + * + * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. + * Ported to fulfill hasher_t interface. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include <string.h> + +#include "md5_hasher.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 u_int8_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 +}; + +/* + * ugly macro stuff + */ +/* 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) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + + + +typedef struct private_md5_hasher_t private_md5_hasher_t; + +/** + * Private data structure with hasing context. + */ +struct private_md5_hasher_t { + /** + * Public interface for this hasher. + */ + md5_hasher_t public; + + /* + * State of the hasher. + */ + u_int32_t state[5]; + u_int32_t count[2]; + u_int8_t buffer[64]; +}; + + +#if BYTE_ORDER != LITTLE_ENDIAN + +/* Encodes input (u_int32_t) into output (u_int8_t). Assumes len is + * a multiple of 4. + */ +static void Encode (u_int8_t *output, u_int32_t *input, size_t len) +{ + size_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[j] = (u_int8_t)(input[i] & 0xff); + output[j+1] = (u_int8_t)((input[i] >> 8) & 0xff); + output[j+2] = (u_int8_t)((input[i] >> 16) & 0xff); + output[j+3] = (u_int8_t)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (u_int8_t) into output (u_int32_t). Assumes len is + * a multiple of 4. + */ +static void Decode(u_int32_t *output, u_int8_t *input, size_t len) +{ + size_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[i] = ((u_int32_t)input[j]) | (((u_int32_t)input[j+1]) << 8) | + (((u_int32_t)input[j+2]) << 16) | (((u_int32_t)input[j+3]) << 24); + } +} + +#elif BYTE_ORDER == LITTLE_ENDIAN + #define Encode memcpy + #define Decode memcpy +#endif + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform(u_int32_t state[4], u_int8_t block[64]) +{ + u_int32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + 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; +} + +/* MD5 block update operation. Continues an MD5 message-digest + * operation, processing another message block, and updating the + * context. + */ +static void MD5Update(private_md5_hasher_t *this, u_int8_t *input, size_t inputLen) +{ + u_int32_t i; + size_t index, partLen; + + /* Compute number of bytes mod 64 */ + index = (u_int8_t)((this->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((this->count[0] += (inputLen << 3)) < (inputLen << 3)) + { + this->count[1]++; + } + this->count[1] += (inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) + { + memcpy(&this->buffer[index], input, partLen); + MD5Transform (this->state, this->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + { + MD5Transform (this->state, &input[i]); + } + index = 0; + } + else + { + i = 0; + } + + /* Buffer remaining input */ + memcpy(&this->buffer[index], &input[i], inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + * the message digest and zeroizing the context. + */ +static void MD5Final (private_md5_hasher_t *this, u_int8_t digest[16]) +{ + u_int8_t bits[8]; + size_t index, padLen; + + /* Save number of bits */ + Encode (bits, this->count, 8); + + /* Pad out to 56 mod 64. */ + index = (size_t)((this->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (this, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (this, bits, 8); + + if (digest != NULL) /* Bill Simpson's padding */ + { + /* store state in digest */ + Encode (digest, this->state, 16); + } +} + + + +/** + * Implementation of hasher_t.get_hash. + */ +static void get_hash(private_md5_hasher_t *this, chunk_t chunk, u_int8_t *buffer) +{ + MD5Update(this, chunk.ptr, chunk.len); + if (buffer != NULL) + { + MD5Final(this, buffer); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + } +} + + +/** + * Implementation of hasher_t.allocate_hash. + */ +static void allocate_hash(private_md5_hasher_t *this, chunk_t chunk, chunk_t *hash) +{ + chunk_t allocated_hash; + + MD5Update(this, chunk.ptr, chunk.len); + if (hash != NULL) + { + allocated_hash.ptr = malloc(HASH_SIZE_MD5); + allocated_hash.len = HASH_SIZE_MD5; + + MD5Final(this, allocated_hash.ptr); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + + *hash = allocated_hash; + } +} + +/** + * Implementation of hasher_t.get_hash_size. + */ +static size_t get_hash_size(private_md5_hasher_t *this) +{ + return HASH_SIZE_MD5; +} + +/** + * Implementation of hasher_t.reset. + */ +static void reset(private_md5_hasher_t *this) +{ + this->state[0] = 0x67452301; + this->state[1] = 0xefcdab89; + this->state[2] = 0x98badcfe; + this->state[3] = 0x10325476; + this->count[0] = 0; + this->count[1] = 0; +} + +/** + * Implementation of hasher_t.destroy. + */ +static void destroy(private_md5_hasher_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +md5_hasher_t *md5_hasher_create(hash_algorithm_t algo) +{ + private_md5_hasher_t *this; + + if (algo != HASH_MD5) + { + return NULL; + } + this = malloc_thing(private_md5_hasher_t); + + this->public.hasher_interface.get_hash = (void (*) (hasher_t*, chunk_t, u_int8_t*))get_hash; + this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash; + this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size; + this->public.hasher_interface.reset = (void (*) (hasher_t*))reset; + this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy; + + /* initialize */ + reset(this); + + return &(this->public); +} diff --git a/src/libstrongswan/plugins/md5/md5_hasher.h b/src/libstrongswan/plugins/md5/md5_hasher.h new file mode 100644 index 000000000..d4a0417ab --- /dev/null +++ b/src/libstrongswan/plugins/md5/md5_hasher.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup md5_hasher md5_hasher + * @{ @ingroup md5_p + */ + +#ifndef MD5_HASHER_H_ +#define MD5_HASHER_H_ + +typedef struct md5_hasher_t md5_hasher_t; + +#include <crypto/hashers/hasher.h> + +/** + * Implementation of hasher_t interface using the MD5 algorithm. + */ +struct md5_hasher_t { + + /** + * Generic hasher_t interface for this hasher. + */ + hasher_t hasher_interface; +}; + +/** + * Creates a new md5_hasher_t. + * + * @param algo hash algorithm, must be HASH_MD5 + * @return md5_hasher_t object, NULL if not supported + */ +md5_hasher_t *md5_hasher_create(hash_algorithm_t algo); + +#endif /*MD5_HASHER_H_@}*/ diff --git a/src/libstrongswan/plugins/md5/md5_plugin.c b/src/libstrongswan/plugins/md5/md5_plugin.c new file mode 100644 index 000000000..94ff04d9d --- /dev/null +++ b/src/libstrongswan/plugins/md5/md5_plugin.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "md5_plugin.h" + +#include <library.h> +#include "md5_hasher.h" + +typedef struct private_md5_plugin_t private_md5_plugin_t; + +/** + * private data of md5_plugin + */ +struct private_md5_plugin_t { + + /** + * public functions + */ + md5_plugin_t public; +}; + +/** + * Implementation of md5_plugin_t.destroy + */ +static void destroy(private_md5_plugin_t *this) +{ + lib->crypto->remove_hasher(lib->crypto, + (hasher_constructor_t)md5_hasher_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_md5_plugin_t *this = malloc_thing(private_md5_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_hasher(lib->crypto, HASH_MD5, + (hasher_constructor_t)md5_hasher_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/md5/md5_plugin.h b/src/libstrongswan/plugins/md5/md5_plugin.h new file mode 100644 index 000000000..e8e8dd535 --- /dev/null +++ b/src/libstrongswan/plugins/md5/md5_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup md5_p md5 + * @ingroup plugins + * + * @defgroup md5_plugin md5_plugin + * @{ @ingroup md5_p + */ + +#ifndef MD5_PLUGIN_H_ +#define MD5_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct md5_plugin_t md5_plugin_t; + +/** + * Plugin implementing the MD5 hash algorithm in software. + */ +struct md5_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a md5_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* MD5_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/mysql/Makefile.am b/src/libstrongswan/plugins/mysql/Makefile.am new file mode 100644 index 000000000..ec94b8fda --- /dev/null +++ b/src/libstrongswan/plugins/mysql/Makefile.am @@ -0,0 +1,12 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-mysql.la + +libstrongswan_mysql_la_SOURCES = mysql_plugin.h mysql_plugin.c \ + mysql_database.h mysql_database.c +libstrongswan_mysql_la_LDFLAGS = -module +libstrongswan_mysql_la_LIBADD = -lmysqlclient_r + diff --git a/src/libstrongswan/plugins/mysql/mysql_database.c b/src/libstrongswan/plugins/mysql/mysql_database.c new file mode 100644 index 000000000..0fd3d5368 --- /dev/null +++ b/src/libstrongswan/plugins/mysql/mysql_database.c @@ -0,0 +1,686 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#define _GNU_SOURCE +#include <string.h> +#include <pthread.h> +#include <mysql/mysql.h> + +#include "mysql_database.h" + +#include <debug.h> +#include <utils/mutex.h> +#include <utils/linked_list.h> + + +typedef struct private_mysql_database_t private_mysql_database_t; + +/** + * private data of mysql_database + */ +struct private_mysql_database_t { + + /** + * public functions + */ + mysql_database_t public; + + /** + * connection pool, contains conn_t + */ + linked_list_t *pool; + + /** + * mutex to lock pool + */ + mutex_t *mutex; + + /** + * hostname to connect to + */ + char *host; + + /** + * username to use + */ + char *username; + + /** + * password + */ + char *password; + + /** + * database name + */ + char *database; + + /** + * tcp port + */ + int port; +}; + +typedef struct conn_t conn_t; + +/** + * connection pool entry + */ +struct conn_t { + + /** + * MySQL database connection + */ + MYSQL *mysql; + + /** + * connection in use? + */ + bool in_use; +}; + +/** + * Release a mysql connection + */ +static void conn_release(conn_t *conn) +{ + conn->in_use = FALSE; +} +/** + * thread specific initialization flag + */ +pthread_key_t initialized; + +/** + * Initialize a thread for mysql usage + */ +static void thread_initialize() +{ + if (pthread_getspecific(initialized) == NULL) + { + pthread_setspecific(initialized, (void*)TRUE); + mysql_thread_init(); + } +} + +/** + * mysql library initialization function + */ +bool mysql_database_init() +{ + if (mysql_library_init(0, NULL, NULL)) + { + return FALSE; + } + if (pthread_key_create(&initialized, (void*)mysql_thread_end)) + { + mysql_library_end(); + return FALSE; + } + return TRUE; +} + +/** + * mysql library cleanup function + */ +void mysql_database_deinit() +{ + pthread_key_delete(initialized); + mysql_thread_end(); + /* mysql_library_end(); would be the clean way, however, it hangs... */ +} + +/** + * Destroy a mysql connection + */ +static void conn_destroy(conn_t *this) +{ + mysql_close(this->mysql); + free(this); +} + +/** + * Acquire/Reuse a mysql connection + */ +static conn_t *conn_get(private_mysql_database_t *this) +{ + conn_t *current, *found = NULL; + enumerator_t *enumerator; + + thread_initialize(); + + while (TRUE) + { + this->mutex->lock(this->mutex); + enumerator = this->pool->create_enumerator(this->pool); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (!current->in_use) + { + found = current; + found->in_use = TRUE; + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + if (found) + { /* check connection if found, release if ping fails */ + if (mysql_ping(found->mysql) == 0) + { + break; + } + this->mutex->lock(this->mutex); + this->pool->remove(this->pool, found, NULL); + this->mutex->unlock(this->mutex); + conn_destroy(found); + found = NULL; + continue; + } + break; + } + if (found == NULL) + { + found = malloc_thing(conn_t); + found->in_use = TRUE; + found->mysql = mysql_init(NULL); + if (!mysql_real_connect(found->mysql, this->host, this->username, + this->password, this->database, this->port, + NULL, 0)) + { + DBG1("connecting to mysql://%s:***@%s:%d/%s failed: %s", + this->username, this->host, this->port, this->database, + mysql_error(found->mysql)); + conn_destroy(found); + found = NULL; + } + else + { + this->mutex->lock(this->mutex); + this->pool->insert_last(this->pool, found); + DBG1("increased MySQL connection pool size to %d", + this->pool->get_count(this->pool)); + this->mutex->unlock(this->mutex); + } + } + return found; +} + +/** + * Create and run a MySQL stmt using a sql string and args + */ +static MYSQL_STMT* run(MYSQL *mysql, char *sql, va_list *args) +{ + MYSQL_STMT *stmt; + int params; + + stmt = mysql_stmt_init(mysql); + if (stmt == NULL) + { + DBG1("creating MySQL statement failed: %s", mysql_error(mysql)); + return NULL; + } + if (mysql_stmt_prepare(stmt, sql, strlen(sql))) + { + DBG1("preparing MySQL statement failed: %s", mysql_stmt_error(stmt)); + mysql_stmt_close(stmt); + return NULL; + } + params = mysql_stmt_param_count(stmt); + if (params > 0) + { + int i; + MYSQL_BIND *bind; + + bind = alloca(sizeof(MYSQL_BIND) * params); + memset(bind, 0, sizeof(MYSQL_BIND) * params); + + for (i = 0; i < params; i++) + { + switch (va_arg(*args, db_type_t)) + { + case DB_INT: + { + bind[i].buffer_type = MYSQL_TYPE_LONG; + bind[i].buffer = (char*)alloca(sizeof(int)); + *(int*)bind[i].buffer = va_arg(*args, int); + bind[i].buffer_length = sizeof(int); + break; + } + case DB_UINT: + { + bind[i].buffer_type = MYSQL_TYPE_LONG; + bind[i].buffer = (char*)alloca(sizeof(u_int)); + *(u_int*)bind[i].buffer = va_arg(*args, u_int); + bind[i].buffer_length = sizeof(u_int); + bind[i].is_unsigned = TRUE; + break; + } + case DB_TEXT: + { + bind[i].buffer_type = MYSQL_TYPE_STRING;; + bind[i].buffer = va_arg(*args, char*); + bind[i].buffer_length = strlen(bind[i].buffer); + break; + } + case DB_BLOB: + { + chunk_t chunk = va_arg(*args, chunk_t); + bind[i].buffer_type = MYSQL_TYPE_BLOB; + bind[i].buffer = chunk.ptr; + bind[i].buffer_length = chunk.len; + break; + } + case DB_DOUBLE: + { + bind[i].buffer_type = MYSQL_TYPE_DOUBLE; + bind[i].buffer = (char*)alloca(sizeof(double)); + *(double*)bind[i].buffer = va_arg(*args, double); + bind[i].buffer_length = sizeof(double); + break; + } + case DB_NULL: + { + bind[i].buffer_type = MYSQL_TYPE_NULL; + break; + } + default: + DBG1("invalid data type supplied"); + mysql_stmt_close(stmt); + return NULL; + } + } + if (mysql_stmt_bind_param(stmt, bind)) + { + DBG1("binding MySQL param failed: %s", mysql_stmt_error(stmt)); + mysql_stmt_close(stmt); + return NULL; + } + } + if (mysql_stmt_execute(stmt)) + { + DBG1("executing MySQL statement failed: %s", mysql_stmt_error(stmt)); + mysql_stmt_close(stmt); + return NULL; + } + return stmt; +} + +typedef struct { + /** implements enumerator_t */ + enumerator_t public; + /** associated MySQL statement */ + MYSQL_STMT *stmt; + /** result bindings */ + MYSQL_BIND *bind; + /** pooled connection handle */ + conn_t *conn; + /** value for INT, UINT, double */ + union { + void *p_void;; + int *p_int; + u_int *p_uint; + double *p_double; + } val; + /* length for TEXT and BLOB */ + unsigned long *length; +} mysql_enumerator_t; + +/** + * create a mysql enumerator + */ +static void mysql_enumerator_destroy(mysql_enumerator_t *this) +{ + int columns, i; + + columns = mysql_stmt_field_count(this->stmt); + + for (i = 0; i < columns; i++) + { + switch (this->bind[i].buffer_type) + { + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_BLOB: + { + free(this->bind[i].buffer); + break; + } + default: + break; + } + } + mysql_stmt_close(this->stmt); + conn_release(this->conn); + free(this->bind); + free(this->val.p_void); + free(this->length); + free(this); +} + +/** + * Implementation of database.query().enumerate + */ +static bool mysql_enumerator_enumerate(mysql_enumerator_t *this, ...) +{ + int i, columns; + va_list args; + + columns = mysql_stmt_field_count(this->stmt); + + /* free/reset data set of previous call */ + for (i = 0; i < columns; i++) + { + switch (this->bind[i].buffer_type) + { + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_BLOB: + { + free(this->bind[i].buffer); + this->bind[i].buffer = NULL; + this->bind[i].buffer_length = 0; + this->bind[i].length = &this->length[i]; + this->length[i] = 0; + break; + } + default: + break; + } + } + + switch (mysql_stmt_fetch(this->stmt)) + { + case 0: + case MYSQL_DATA_TRUNCATED: + break; + case MYSQL_NO_DATA: + return FALSE; + default: + DBG1("fetching MySQL row failed: %s", mysql_stmt_error(this->stmt)); + return FALSE; + } + + va_start(args, this); + for (i = 0; i < columns; i++) + { + switch (this->bind[i].buffer_type) + { + case MYSQL_TYPE_LONG: + { + if (this->bind[i].is_unsigned) + { + u_int *value = va_arg(args, u_int*); + *value = this->val.p_uint[i]; + } + else + { + int *value = va_arg(args, int*); + *value = this->val.p_int[i]; + } + break; + } + case MYSQL_TYPE_STRING: + { + char **value = va_arg(args, char**); + this->bind[i].buffer = malloc(this->length[i]+1); + this->bind[i].buffer_length = this->length[i]; + *value = this->bind[i].buffer; + mysql_stmt_fetch_column(this->stmt, &this->bind[i], i, 0); + ((char*)this->bind[i].buffer)[this->length[i]] = '\0'; + break; + } + case MYSQL_TYPE_BLOB: + { + chunk_t *value = va_arg(args, chunk_t*); + this->bind[i].buffer = malloc(this->length[i]); + this->bind[i].buffer_length = this->length[i]; + value->ptr = this->bind[i].buffer; + value->len = this->length[i]; + mysql_stmt_fetch_column(this->stmt, &this->bind[i], i, 0); + break; + } + case MYSQL_TYPE_DOUBLE: + { + double *value = va_arg(args, double*); + *value = this->val.p_double[i]; + break; + } + default: + break; + } + } + return TRUE; +} + +/** + * Implementation of database_t.query. + */ +static enumerator_t* query(private_mysql_database_t *this, char *sql, ...) +{ + MYSQL_STMT *stmt; + va_list args; + mysql_enumerator_t *enumerator = NULL; + conn_t *conn; + + conn = conn_get(this); + if (!conn) + { + return NULL; + } + + va_start(args, sql); + stmt = run(conn->mysql, sql, &args); + if (stmt) + { + int columns, i; + + enumerator = malloc_thing(mysql_enumerator_t); + enumerator->public.enumerate = (void*)mysql_enumerator_enumerate; + enumerator->public.destroy = (void*)mysql_enumerator_destroy; + enumerator->stmt = stmt; + enumerator->conn = conn; + columns = mysql_stmt_field_count(stmt); + enumerator->bind = calloc(columns, sizeof(MYSQL_BIND)); + enumerator->length = calloc(columns, sizeof(unsigned long)); + enumerator->val.p_void = calloc(columns, sizeof(enumerator->val)); + for (i = 0; i < columns; i++) + { + switch (va_arg(args, db_type_t)) + { + case DB_INT: + { + enumerator->bind[i].buffer_type = MYSQL_TYPE_LONG; + enumerator->bind[i].buffer = (char*)&enumerator->val.p_int[i]; + break; + } + case DB_UINT: + { + enumerator->bind[i].buffer_type = MYSQL_TYPE_LONG; + enumerator->bind[i].buffer = (char*)&enumerator->val.p_uint[i]; + enumerator->bind[i].is_unsigned = TRUE; + break; + } + case DB_TEXT: + { + enumerator->bind[i].buffer_type = MYSQL_TYPE_STRING; + enumerator->bind[i].length = &enumerator->length[i]; + break; + } + case DB_BLOB: + { + enumerator->bind[i].buffer_type = MYSQL_TYPE_BLOB; + enumerator->bind[i].length = &enumerator->length[i]; + break; + } + case DB_DOUBLE: + { + enumerator->bind[i].buffer_type = MYSQL_TYPE_DOUBLE; + enumerator->bind[i].buffer = (char*)&enumerator->val.p_double[i]; + break; + } + default: + DBG1("invalid result data type supplied"); + mysql_enumerator_destroy(enumerator); + va_end(args); + return NULL; + } + } + if (mysql_stmt_bind_result(stmt, enumerator->bind)) + { + DBG1("binding MySQL result failed: %s", mysql_stmt_error(stmt)); + mysql_enumerator_destroy(enumerator); + enumerator = NULL; + } + } + else + { + conn_release(conn); + } + va_end(args); + return (enumerator_t*)enumerator; +} + +/** + * Implementation of database_t.execute. + */ +static int execute(private_mysql_database_t *this, int *rowid, char *sql, ...) +{ + MYSQL_STMT *stmt; + va_list args; + conn_t *conn; + int affected = -1; + + conn = conn_get(this); + if (!conn) + { + return -1; + } + va_start(args, sql); + stmt = run(conn->mysql, sql, &args); + if (stmt) + { + if (rowid) + { + *rowid = mysql_stmt_insert_id(stmt); + } + affected = mysql_stmt_affected_rows(stmt); + mysql_stmt_close(stmt); + } + va_end(args); + conn_release(conn); + return affected; +} + +/** + * Implementation of database_t.destroy + */ +static void destroy(private_mysql_database_t *this) +{ + this->pool->destroy_function(this->pool, (void*)conn_destroy); + this->mutex->destroy(this->mutex); + free(this->host); + free(this->username); + free(this->password); + free(this->database); + free(this); +} + +static bool parse_uri(private_mysql_database_t *this, char *uri) +{ + char *username, *password, *host, *port = "0", *database, *pos; + + /** + * parse mysql://username:pass@host:port/database uri + */ + username = strdupa(uri + 8); + pos = strchr(username, ':'); + if (pos) + { + *pos = '\0'; + password = pos + 1; + pos = strrchr(password, '@'); + if (pos) + { + *pos = '\0'; + host = pos + 1; + pos = strrchr(host, ':'); + if (pos) + { + *pos = '\0'; + port = pos + 1; + pos = strchr(port, '/'); + } + else + { + pos = strchr(host, '/'); + } + if (pos) + { + *pos = '\0'; + database = pos + 1; + + this->host = strdup(host); + this->username = strdup(username); + this->password = strdup(password); + this->database = strdup(database); + this->port = atoi(port); + return TRUE; + } + } + } + DBG1("parsing MySQL database uri '%s' failed", uri); + return FALSE; +} + + +/* + * see header file + */ +mysql_database_t *mysql_database_create(char *uri) +{ + conn_t *conn; + private_mysql_database_t *this; + + if (!strneq(uri, "mysql://", 8)) + { + return NULL; + } + + this = malloc_thing(private_mysql_database_t); + + this->public.db.query = (enumerator_t* (*)(database_t *this, char *sql, ...))query; + this->public.db.execute = (int (*)(database_t *this, int *rowid, char *sql, ...))execute; + this->public.db.destroy = (void(*)(database_t*))destroy; + + if (!parse_uri(this, uri)) + { + free(this); + return NULL; + } + this->mutex = mutex_create(MUTEX_DEFAULT); + this->pool = linked_list_create(); + + /* check connectivity */ + conn = conn_get(this); + if (!conn) + { + destroy(this); + return NULL; + } + conn_release(conn); + return &this->public; +} + diff --git a/src/libstrongswan/plugins/mysql/mysql_database.h b/src/libstrongswan/plugins/mysql/mysql_database.h new file mode 100644 index 000000000..d04aa79fa --- /dev/null +++ b/src/libstrongswan/plugins/mysql/mysql_database.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup mysql_database mysql_database + * @{ @ingroup mysql_p + */ + +#ifndef MYSQL_DATABASE_H_ +#define MYSQL_DATABASE_H_ + +#include <database/database.h> + +typedef struct mysql_database_t mysql_database_t; + +/** + * MySQL databse_t implementation. + */ +struct mysql_database_t { + + /** + * Implements database_t + */ + database_t db; +}; + +/** + * Create a mysql_database instance. + * + * @param uri connection URI, mysql://user:pass@host:port/database + */ +mysql_database_t *mysql_database_create(char *uri); + +/** + * MySQL client library initialization function + * + * @return FALSE if initialization failed + */ +bool mysql_database_init(); + +/** + * Mysql client library cleanup function + */ +void mysql_database_deinit(); + +#endif /* MYSQL_DATABASE_H_ @}*/ diff --git a/src/libstrongswan/plugins/mysql/mysql_plugin.c b/src/libstrongswan/plugins/mysql/mysql_plugin.c new file mode 100644 index 000000000..907c746e3 --- /dev/null +++ b/src/libstrongswan/plugins/mysql/mysql_plugin.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "mysql_plugin.h" + +#include <library.h> +#include <debug.h> +#include "mysql_database.h" + +typedef struct private_mysql_plugin_t private_mysql_plugin_t; + +/** + * private data of mysql_plugin + */ +struct private_mysql_plugin_t { + + /** + * public functions + */ + mysql_plugin_t public; +}; + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(private_mysql_plugin_t *this) +{ + lib->db->remove_database(lib->db, + (database_constructor_t)mysql_database_create); + mysql_database_deinit(); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_mysql_plugin_t *this; + + if (!mysql_database_init()) + { + DBG1("MySQL client library initialization failed"); + return NULL; + } + + this = malloc_thing(private_mysql_plugin_t); + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->db->add_database(lib->db, + (database_constructor_t)mysql_database_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/mysql/mysql_plugin.h b/src/libstrongswan/plugins/mysql/mysql_plugin.h new file mode 100644 index 000000000..dbcabaafe --- /dev/null +++ b/src/libstrongswan/plugins/mysql/mysql_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup mysql_p mysql + * @ingroup plugins + * + * @defgroup mysql_plugin mysql_plugin + * @{ @ingroup mysql_p + */ + +#ifndef MYSQL_PLUGIN_H_ +#define MYSQL_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct mysql_plugin_t mysql_plugin_t; + +/** + * Plugin implementing mysql database connectivity. + */ +struct mysql_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a mysql_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* MYSQL_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/plugin.h b/src/libstrongswan/plugins/plugin.h new file mode 100644 index 000000000..cf0b728a3 --- /dev/null +++ b/src/libstrongswan/plugins/plugin.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup plugin plugin + * @{ @ingroup plugins + */ + +#ifndef PLUGIN_H_ +#define PLUGIN_H_ + +typedef struct plugin_t plugin_t; + +/** + * Interface definition of a plugin. + */ +struct plugin_t { + + /** + * Destroy a plugin instance. + */ + void (*destroy)(plugin_t *this); +}; + + +/** + * Plugin constructor function definiton. + * + * Each plugin has a constructor functions. This function is called on daemon + * startup to initialize each plugin. + * The plugin function is named plugin_create(). + * + * @return plugin_t instance + */ +typedef plugin_t *(*plugin_constructor_t)(void); + +#endif /* PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/plugin_loader.c b/src/libstrongswan/plugins/plugin_loader.c new file mode 100644 index 000000000..215ed53d6 --- /dev/null +++ b/src/libstrongswan/plugins/plugin_loader.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "plugin_loader.h" + +#include <dlfcn.h> + +#include <debug.h> +#include <utils/linked_list.h> +#include <plugins/plugin.h> + +typedef struct private_plugin_loader_t private_plugin_loader_t; + +/** + * private data of plugin_loader + */ +struct private_plugin_loader_t { + + /** + * public functions + */ + plugin_loader_t public; + + /** + * list of loaded plugins + */ + linked_list_t *plugins; +}; + +/** + * Implementation of plugin_loader_t.load_plugins. + */ +static int load(private_plugin_loader_t *this, char *path, char *prefix) +{ + enumerator_t *enumerator; + char *file, *ending, *rel; + void *handle; + int count = 0; + + enumerator = enumerator_create_directory(path); + if (!enumerator) + { + DBG1("opening plugin directory %s failed", path); + return 0; + } + DBG1("loading plugins from %s", path); + while (enumerator->enumerate(enumerator, &rel, &file, NULL)) + { + plugin_t *plugin; + plugin_constructor_t constructor; + + ending = file + strlen(file) - 3; + if (ending <= file || !streq(ending, ".so")) + { /* only process .so libraries */ + continue; + } + if (!strneq(prefix, rel, strlen(prefix))) + { + continue; + } + handle = dlopen(file, RTLD_LAZY); + if (handle == NULL) + { + DBG1("loading plugin %s failed: %s", rel, dlerror()); + continue; + } + constructor = dlsym(handle, "plugin_create"); + if (constructor == NULL) + { + DBG1("plugin %s has no plugin_create() function, skipped", rel); + dlclose(handle); + continue; + } + plugin = constructor(); + if (plugin == NULL) + { + DBG1("plugin %s constructor failed, skipping", rel); + dlclose(handle); + continue; + } + DBG1("plugin %s loaded successfully", rel); + /* insert in front to destroy them in reverse order */ + this->plugins->insert_last(this->plugins, plugin); + /* we do not store or free dlopen() handles, leak_detective requires + * the modules to keep loaded until leak report */ + count++; + } + enumerator->destroy(enumerator); + return count; +} + +/** + * Implementation of plugin_loader_t.destroy + */ +static void destroy(private_plugin_loader_t *this) +{ + this->plugins->destroy_offset(this->plugins, offsetof(plugin_t, destroy)); + free(this); +} + +/* + * see header file + */ +plugin_loader_t *plugin_loader_create() +{ + private_plugin_loader_t *this = malloc_thing(private_plugin_loader_t); + + this->public.load = (int(*)(plugin_loader_t*, char *path, char *prefix))load; + this->public.destroy = (void(*)(plugin_loader_t*))destroy; + + this->plugins = linked_list_create(); + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/plugin_loader.h b/src/libstrongswan/plugins/plugin_loader.h new file mode 100644 index 000000000..455332556 --- /dev/null +++ b/src/libstrongswan/plugins/plugin_loader.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup plugin_loader plugin_loader + * @{ @ingroup plugin + */ + +#ifndef PLUGIN_LOADER_H_ +#define PLUGIN_LOADER_H_ + +typedef struct plugin_loader_t plugin_loader_t; + +/** + * The plugin_loader loads plugins from a directory and initializes them + */ +struct plugin_loader_t { + + /** + * Load plugins from a directory. + * + * @param path path containing loadable plugins + * @param prefix prefix of plugin libraries to load + * @return number of successfully loaded plugins + */ + int (*load)(plugin_loader_t *this, char *path, char *prefix); + + /** + * Unload loaded plugins, destroy plugin_loader instance. + */ + void (*destroy)(plugin_loader_t *this); +}; + +/** + * Create a plugin_loader instance. + * + * @return plugin loader instance + */ +plugin_loader_t *plugin_loader_create(); + +#endif /* PLUGIN_LOADER_H_ @}*/ diff --git a/src/libstrongswan/plugins/sha1/Makefile.am b/src/libstrongswan/plugins/sha1/Makefile.am new file mode 100644 index 000000000..299e85083 --- /dev/null +++ b/src/libstrongswan/plugins/sha1/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-sha1.la + +libstrongswan_sha1_la_SOURCES = sha1_plugin.h sha1_plugin.c sha1_hasher.c sha1_hasher.h +libstrongswan_sha1_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/sha1/sha1_hasher.c b/src/libstrongswan/plugins/sha1/sha1_hasher.c new file mode 100644 index 000000000..97a2f207f --- /dev/null +++ b/src/libstrongswan/plugins/sha1/sha1_hasher.c @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * Ported from Steve Reid's <steve@edmweb.com> implementation + * "SHA1 in C" found in strongSwan. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include <string.h> +#include <arpa/inet.h> + +#include "sha1_hasher.h" + +/* + * ugly macro stuff + */ +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +#if BYTE_ORDER == LITTLE_ENDIAN + #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) |(rol(block->l[i],8)&0x00FF00FF)) +#elif BYTE_ORDER == BIG_ENDIAN + #define blk0(i) block->l[i] +#else + #error "Endianness not defined!" +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +typedef struct private_sha1_hasher_t private_sha1_hasher_t; + +/** + * Private data structure with hasing context. + */ +struct private_sha1_hasher_t { + /** + * Public interface for this hasher. + */ + sha1_hasher_t public; + + /** + * implemented algorithm + */ + hash_algorithm_t algo; + + /* + * State of the hasher. + */ + u_int32_t state[5]; + u_int32_t count[2]; + u_int8_t buffer[64]; +}; + +/* + * Hash a single 512-bit block. This is the core of the algorithm. * + */ +static void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]) +{ + u_int32_t a, b, c, d, e; + typedef union { + u_int8_t c[64]; + u_int32_t l[16]; + } CHAR64LONG16; + CHAR64LONG16 block[1]; /* use array to appear as a pointer */ + memcpy(block, buffer, 64); + + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; + memset(block, '\0', sizeof(block)); +} + +/* + * Run your data through this. + */ +static void SHA1Update(private_sha1_hasher_t* this, u_int8_t *data, u_int32_t len) +{ + u_int32_t i; + u_int32_t j; + + j = this->count[0]; + if ((this->count[0] += len << 3) < j) + { + this->count[1]++; + } + this->count[1] += (len>>29); + j = (j >> 3) & 63; + if ((j + len) > 63) + { + memcpy(&this->buffer[j], data, (i = 64-j)); + SHA1Transform(this->state, this->buffer); + for ( ; i + 63 < len; i += 64) + { + SHA1Transform(this->state, &data[i]); + } + j = 0; + } + else + { + i = 0; + } + memcpy(&this->buffer[j], &data[i], len - i); +} + + +/* + * Add padding and return the message digest. + */ +static void SHA1Final(private_sha1_hasher_t *this, u_int8_t *digest) +{ + u_int32_t i; + u_int8_t finalcount[8]; + u_int8_t c; + + for (i = 0; i < 8; i++) + { + finalcount[i] = (u_int8_t)((this->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + c = 0200; + SHA1Update(this, &c, 1); + while ((this->count[0] & 504) != 448) + { + c = 0000; + SHA1Update(this, &c, 1); + } + SHA1Update(this, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) + { + digest[i] = (u_int8_t)((this->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } +} + +/** + * Implementation of hasher_t.reset. + */ +static void reset(private_sha1_hasher_t *this) +{ + this->state[0] = 0x67452301; + this->state[1] = 0xEFCDAB89; + this->state[2] = 0x98BADCFE; + this->state[3] = 0x10325476; + this->state[4] = 0xC3D2E1F0; + this->count[0] = 0; + this->count[1] = 0; +} + +/** + * copy hasher state to buf + */ +static void state_to_buf(private_sha1_hasher_t *this, u_int8_t *buffer) +{ + u_int32_t *hash = (u_int32_t*)buffer; + hash[0] = htonl(this->state[0]); + hash[1] = htonl(this->state[1]); + hash[2] = htonl(this->state[2]); + hash[3] = htonl(this->state[3]); + hash[4] = htonl(this->state[4]); +} + +/** + * Implementation of hasher_t.get_hash. + */ +static void get_hash(private_sha1_hasher_t *this, chunk_t chunk, u_int8_t *buffer) +{ + SHA1Update(this, chunk.ptr, chunk.len); + if (buffer != NULL) + { + if (this->algo == HASH_SHA1_NOFINAL) + { + state_to_buf(this, buffer); + } + else + { + SHA1Final(this, buffer); + } + reset(this); + } +} + + +/** + * Implementation of hasher_t.allocate_hash. + */ +static void allocate_hash(private_sha1_hasher_t *this, chunk_t chunk, chunk_t *hash) +{ + SHA1Update(this, chunk.ptr, chunk.len); + if (hash != NULL) + { + hash->ptr = malloc(HASH_SIZE_SHA1); + hash->len = HASH_SIZE_SHA1; + + if (this->algo == HASH_SHA1_NOFINAL) + { + state_to_buf(this, hash->ptr); + } + else + { + SHA1Final(this, hash->ptr); + } + reset(this); + } +} + +/** + * Implementation of hasher_t.get_hash_size. + */ +static size_t get_hash_size(private_sha1_hasher_t *this) +{ + return HASH_SIZE_SHA1; +} + +/** + * Implementation of hasher_t.destroy. + */ +static void destroy(private_sha1_hasher_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +sha1_hasher_t *sha1_hasher_create(hash_algorithm_t algo) +{ + private_sha1_hasher_t *this; + if (algo != HASH_SHA1 && algo != HASH_SHA1_NOFINAL) + { + return NULL; + } + this = malloc_thing(private_sha1_hasher_t); + this->algo = algo; + this->public.hasher_interface.get_hash = (void (*) (hasher_t*, chunk_t, u_int8_t*))get_hash; + this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash; + this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size; + this->public.hasher_interface.reset = (void (*) (hasher_t*))reset; + this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy; + + /* initialize */ + reset(this); + + return &(this->public); +} diff --git a/src/libstrongswan/plugins/sha1/sha1_hasher.h b/src/libstrongswan/plugins/sha1/sha1_hasher.h new file mode 100644 index 000000000..aff0eae11 --- /dev/null +++ b/src/libstrongswan/plugins/sha1/sha1_hasher.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup sha1_hasher sha1_hasher + * @{ @ingroup sha1_p + */ + +#ifndef SHA1_HASHER_H_ +#define SHA1_HASHER_H_ + +typedef struct sha1_hasher_t sha1_hasher_t; + +#include <crypto/hashers/hasher.h> + +/** + * Implementation of hasher_t interface using the SHA1 algorithm. + */ +struct sha1_hasher_t { + + /** + * Implements hasher_t interface. + */ + hasher_t hasher_interface; +}; + +/** + * Creates a new sha1_hasher_t. + * + * This implementation supports two algorithms, HASH_SHA1 and HASH_SHA1_NOFINAL + * + * @param algo algorithm + * @return sha1_hasher_t object + */ +sha1_hasher_t *sha1_hasher_create(hash_algorithm_t algo); + +#endif /*SHA1_HASHER_H_ @}*/ diff --git a/src/libstrongswan/plugins/sha1/sha1_plugin.c b/src/libstrongswan/plugins/sha1/sha1_plugin.c new file mode 100644 index 000000000..4a69c4e76 --- /dev/null +++ b/src/libstrongswan/plugins/sha1/sha1_plugin.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "sha1_plugin.h" + +#include <library.h> +#include "sha1_hasher.h" + +typedef struct private_sha1_plugin_t private_sha1_plugin_t; + +/** + * private data of sha1_plugin + */ +struct private_sha1_plugin_t { + + /** + * public functions + */ + sha1_plugin_t public; +}; + +/** + * Implementation of sha1_plugin_t.destroy + */ +static void destroy(private_sha1_plugin_t *this) +{ + lib->crypto->remove_hasher(lib->crypto, + (hasher_constructor_t)sha1_hasher_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_sha1_plugin_t *this = malloc_thing(private_sha1_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_hasher(lib->crypto, HASH_SHA1, + (hasher_constructor_t)sha1_hasher_create); + lib->crypto->add_hasher(lib->crypto, HASH_SHA1_NOFINAL, + (hasher_constructor_t)sha1_hasher_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/sha1/sha1_plugin.h b/src/libstrongswan/plugins/sha1/sha1_plugin.h new file mode 100644 index 000000000..82ab04c86 --- /dev/null +++ b/src/libstrongswan/plugins/sha1/sha1_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup sha1_p sha1 + * @ingroup plugins + * + * @defgroup sha1_plugin sha1_plugin + * @{ @ingroup sha1_p + */ + +#ifndef SHA1_PLUGIN_H_ +#define SHA1_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct sha1_plugin_t sha1_plugin_t; + +/** + * Plugin implementing the SHA1 algorithm in software. + */ +struct sha1_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a sha1_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* SHA1_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/sha2/Makefile.am b/src/libstrongswan/plugins/sha2/Makefile.am new file mode 100644 index 000000000..066e49476 --- /dev/null +++ b/src/libstrongswan/plugins/sha2/Makefile.am @@ -0,0 +1,10 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-sha2.la + +libstrongswan_sha2_la_SOURCES = sha2_plugin.h sha2_plugin.c sha2_hasher.c sha2_hasher.h +libstrongswan_sha2_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/sha2/sha2_hasher.c b/src/libstrongswan/plugins/sha2/sha2_hasher.c new file mode 100644 index 000000000..1ec397086 --- /dev/null +++ b/src/libstrongswan/plugins/sha2/sha2_hasher.c @@ -0,0 +1,632 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * Copyright (C) 2001 Jari Ruusu. + * + * Ported from strongSwans implementation written by Jari Ruusu. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include <string.h> + +#include "sha2_hasher.h" + + +typedef struct private_sha512_hasher_t private_sha512_hasher_t; + +/** + * Private data structure with hasing context for SHA384 and SHA512 + */ +struct private_sha512_hasher_t { + /** + * Public interface for this hasher. + */ + sha2_hasher_t public; + + unsigned char sha_out[128]; /* results are here, bytes 0..47/0..63 */ + u_int64_t sha_H[8]; + u_int64_t sha_blocks; + u_int64_t sha_blocksMSB; + int sha_bufCnt; +}; + + +typedef struct private_sha256_hasher_t private_sha256_hasher_t; + +/** + * Private data structure with hasing context for SHA256 + */ +struct private_sha256_hasher_t { + /** + * Public interface for this hasher. + */ + sha2_hasher_t public; + + unsigned char sha_out[64]; /* results are here, bytes 0...31 */ + u_int32_t sha_H[8]; + u_int64_t sha_blocks; + int sha_bufCnt; +}; + + +static const u_int32_t sha256_hashInit[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, + 0x1f83d9ab, 0x5be0cd19 +}; + +static const u_int32_t sha256_K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +static const u_int64_t sha512_hashInit[8] = { + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +static const u_int64_t sha384_hashInit[8] = { + 0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, + 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL +}; + +static const u_int64_t sha512_K[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, + 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, + 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, + 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, + 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, + 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, + 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, + 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, + 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, + 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, + 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, + 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, + 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, + 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + + +/* set macros for SHA256 */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define R(x,y) ((y) >> (x)) + +#define S(x,y) (((y) >> (x)) | ((y) << (32 - (x)))) +#define uSig0(x) ((S(2,(x))) ^ (S(13,(x))) ^ (S(22,(x)))) +#define uSig1(x) ((S(6,(x))) ^ (S(11,(x))) ^ (S(25,(x)))) +#define lSig0(x) ((S(7,(x))) ^ (S(18,(x))) ^ (R(3,(x)))) +#define lSig1(x) ((S(17,(x))) ^ (S(19,(x))) ^ (R(10,(x)))) + +/** + * Single block SHA256 transformation + */ +static void sha256_transform(private_sha256_hasher_t *ctx, + const unsigned char *datap) +{ + register int j; + u_int32_t a, b, c, d, e, f, g, h; + u_int32_t T1, T2, W[64], Wm2, Wm15; + + /* read the data, big endian byte order */ + j = 0; + do { + W[j] = (((u_int32_t)(datap[0]))<<24) | (((u_int32_t)(datap[1]))<<16) | + (((u_int32_t)(datap[2]))<<8 ) | ((u_int32_t)(datap[3])); + datap += 4; + } while(++j < 16); + + /* initialize variables a...h */ + a = ctx->sha_H[0]; + b = ctx->sha_H[1]; + c = ctx->sha_H[2]; + d = ctx->sha_H[3]; + e = ctx->sha_H[4]; + f = ctx->sha_H[5]; + g = ctx->sha_H[6]; + h = ctx->sha_H[7]; + + /* apply compression function */ + j = 0; + do + { + if(j >= 16) + { + Wm2 = W[j - 2]; + Wm15 = W[j - 15]; + W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16]; + } + T1 = h + uSig1(e) + Ch(e,f,g) + sha256_K[j] + W[j]; + T2 = uSig0(a) + Maj(a,b,c); + h = g; g = f; f = e; + e = d + T1; + d = c; c = b; b = a; + a = T1 + T2; + } while(++j < 64); + + /* compute intermediate hash value */ + ctx->sha_H[0] += a; + ctx->sha_H[1] += b; + ctx->sha_H[2] += c; + ctx->sha_H[3] += d; + ctx->sha_H[4] += e; + ctx->sha_H[5] += f; + ctx->sha_H[6] += g; + ctx->sha_H[7] += h; + + ctx->sha_blocks++; +} + +/** + * Update SHA256 hash + */ +static void sha256_write(private_sha256_hasher_t *ctx, + const unsigned char *datap, int length) +{ + while(length > 0) + { + if(!ctx->sha_bufCnt) + { + while(length >= sizeof(ctx->sha_out)) + { + sha256_transform(ctx, datap); + datap += sizeof(ctx->sha_out); + length -= sizeof(ctx->sha_out); + } + if(!length) return; + } + ctx->sha_out[ctx->sha_bufCnt] = *datap++; + length--; + if(++ctx->sha_bufCnt == sizeof(ctx->sha_out)) + { + sha256_transform(ctx, &ctx->sha_out[0]); + ctx->sha_bufCnt = 0; + } + } +} + +/** + * finalize SHA256 hash + */ +static void sha256_final(private_sha256_hasher_t *ctx) +{ + register int j; + u_int64_t bitLength; + u_int32_t i; + unsigned char padByte, *datap; + + bitLength = (ctx->sha_blocks << 9) | (ctx->sha_bufCnt << 3); + padByte = 0x80; + sha256_write(ctx, &padByte, 1); + + /* pad extra space with zeroes */ + padByte = 0; + while(ctx->sha_bufCnt != 56) + { + sha256_write(ctx, &padByte, 1); + } + + /* write bit length, big endian byte order */ + ctx->sha_out[56] = bitLength >> 56; + ctx->sha_out[57] = bitLength >> 48; + ctx->sha_out[58] = bitLength >> 40; + ctx->sha_out[59] = bitLength >> 32; + ctx->sha_out[60] = bitLength >> 24; + ctx->sha_out[61] = bitLength >> 16; + ctx->sha_out[62] = bitLength >> 8; + ctx->sha_out[63] = bitLength; + sha256_transform(ctx, &ctx->sha_out[0]); + + /* return results in ctx->sha_out[0...31] */ + datap = &ctx->sha_out[0]; + j = 0; + do { + i = ctx->sha_H[j]; + datap[0] = i >> 24; + datap[1] = i >> 16; + datap[2] = i >> 8; + datap[3] = i; + datap += 4; + } while(++j < 8); +} + +/* update macros for SHA512 */ +#undef S +#undef uSig0 +#undef uSig1 +#undef lSig0 +#undef lSig1 +#define S(x,y) (((y) >> (x)) | ((y) << (64 - (x)))) +#define uSig0(x) ((S(28,(x))) ^ (S(34,(x))) ^ (S(39,(x)))) +#define uSig1(x) ((S(14,(x))) ^ (S(18,(x))) ^ (S(41,(x)))) +#define lSig0(x) ((S(1,(x))) ^ (S(8,(x))) ^ (R(7,(x)))) +#define lSig1(x) ((S(19,(x))) ^ (S(61,(x))) ^ (R(6,(x)))) + +/** + * Single block SHA384/SHA512 transformation + */ +static void sha512_transform(private_sha512_hasher_t *ctx, + const unsigned char *datap) +{ + register int j; + u_int64_t a, b, c, d, e, f, g, h; + u_int64_t T1, T2, W[80], Wm2, Wm15; + + /* read the data, big endian byte order */ + j = 0; + do { + W[j] = (((u_int64_t)(datap[0]))<<56) | (((u_int64_t)(datap[1]))<<48) | + (((u_int64_t)(datap[2]))<<40) | (((u_int64_t)(datap[3]))<<32) | + (((u_int64_t)(datap[4]))<<24) | (((u_int64_t)(datap[5]))<<16) | + (((u_int64_t)(datap[6]))<<8 ) | ((u_int64_t)(datap[7])); + datap += 8; + } while(++j < 16); + + /* initialize variables a...h */ + a = ctx->sha_H[0]; + b = ctx->sha_H[1]; + c = ctx->sha_H[2]; + d = ctx->sha_H[3]; + e = ctx->sha_H[4]; + f = ctx->sha_H[5]; + g = ctx->sha_H[6]; + h = ctx->sha_H[7]; + + /* apply compression function */ + j = 0; + do { + if(j >= 16) { + Wm2 = W[j - 2]; + Wm15 = W[j - 15]; + W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16]; + } + T1 = h + uSig1(e) + Ch(e,f,g) + sha512_K[j] + W[j]; + T2 = uSig0(a) + Maj(a,b,c); + h = g; g = f; f = e; + e = d + T1; + d = c; c = b; b = a; + a = T1 + T2; + } while(++j < 80); + + /* compute intermediate hash value */ + ctx->sha_H[0] += a; + ctx->sha_H[1] += b; + ctx->sha_H[2] += c; + ctx->sha_H[3] += d; + ctx->sha_H[4] += e; + ctx->sha_H[5] += f; + ctx->sha_H[6] += g; + ctx->sha_H[7] += h; + + ctx->sha_blocks++; + if(!ctx->sha_blocks) ctx->sha_blocksMSB++; +} + +/** + * Update a SHA384/SHA512 hash + */ +static void sha512_write(private_sha512_hasher_t *ctx, + const unsigned char *datap, int length) +{ + while(length > 0) + { + if(!ctx->sha_bufCnt) + { + while(length >= sizeof(ctx->sha_out)) + { + sha512_transform(ctx, datap); + datap += sizeof(ctx->sha_out); + length -= sizeof(ctx->sha_out); + } + if(!length) return; + } + ctx->sha_out[ctx->sha_bufCnt] = *datap++; + length--; + if(++ctx->sha_bufCnt == sizeof(ctx->sha_out)) + { + sha512_transform(ctx, &ctx->sha_out[0]); + ctx->sha_bufCnt = 0; + } + } +} + +/** + * Finalize a SHA384/SHA512 hash + */ +static void sha512_final(private_sha512_hasher_t *ctx) +{ + register int j; + u_int64_t bitLength, bitLengthMSB; + u_int64_t i; + unsigned char padByte, *datap; + + bitLength = (ctx->sha_blocks << 10) | (ctx->sha_bufCnt << 3); + bitLengthMSB = (ctx->sha_blocksMSB << 10) | (ctx->sha_blocks >> 54); + padByte = 0x80; + sha512_write(ctx, &padByte, 1); + + /* pad extra space with zeroes */ + padByte = 0; + while(ctx->sha_bufCnt != 112) + { + sha512_write(ctx, &padByte, 1); + } + + /* write bit length, big endian byte order */ + ctx->sha_out[112] = bitLengthMSB >> 56; + ctx->sha_out[113] = bitLengthMSB >> 48; + ctx->sha_out[114] = bitLengthMSB >> 40; + ctx->sha_out[115] = bitLengthMSB >> 32; + ctx->sha_out[116] = bitLengthMSB >> 24; + ctx->sha_out[117] = bitLengthMSB >> 16; + ctx->sha_out[118] = bitLengthMSB >> 8; + ctx->sha_out[119] = bitLengthMSB; + ctx->sha_out[120] = bitLength >> 56; + ctx->sha_out[121] = bitLength >> 48; + ctx->sha_out[122] = bitLength >> 40; + ctx->sha_out[123] = bitLength >> 32; + ctx->sha_out[124] = bitLength >> 24; + ctx->sha_out[125] = bitLength >> 16; + ctx->sha_out[126] = bitLength >> 8; + ctx->sha_out[127] = bitLength; + sha512_transform(ctx, &ctx->sha_out[0]); + + /* return results in ctx->sha_out[0...63] */ + datap = &ctx->sha_out[0]; + j = 0; + do { + i = ctx->sha_H[j]; + datap[0] = i >> 56; + datap[1] = i >> 48; + datap[2] = i >> 40; + datap[3] = i >> 32; + datap[4] = i >> 24; + datap[5] = i >> 16; + datap[6] = i >> 8; + datap[7] = i; + datap += 8; + } while(++j < 8); +} + +/** + * Implementation of hasher_t.get_hash for SHA256. + */ +static void get_hash256(private_sha256_hasher_t *this, + chunk_t chunk, u_int8_t *buffer) +{ + sha256_write(this, chunk.ptr, chunk.len); + if (buffer != NULL) + { + sha256_final(this); + memcpy(buffer, this->sha_out, HASH_SIZE_SHA256); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + } +} + +/** + * Implementation of hasher_t.get_hash for SHA384. + */ +static void get_hash384(private_sha512_hasher_t *this, + chunk_t chunk, u_int8_t *buffer) +{ + sha512_write(this, chunk.ptr, chunk.len); + if (buffer != NULL) + { + sha512_final(this); + memcpy(buffer, this->sha_out, HASH_SIZE_SHA384); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + } +} + +/** + * Implementation of hasher_t.get_hash for SHA512. + */ +static void get_hash512(private_sha512_hasher_t *this, + chunk_t chunk, u_int8_t *buffer) +{ + sha512_write(this, chunk.ptr, chunk.len); + if (buffer != NULL) + { + sha512_final(this); + memcpy(buffer, this->sha_out, HASH_SIZE_SHA512); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + } +} + +/** + * Implementation of hasher_t.allocate_hash for SHA256. + */ +static void allocate_hash256(private_sha256_hasher_t *this, + chunk_t chunk, chunk_t *hash) +{ + chunk_t allocated_hash; + + sha256_write(this, chunk.ptr, chunk.len); + if (hash != NULL) + { + sha256_final(this); + allocated_hash = chunk_alloc(HASH_SIZE_SHA256); + memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA256); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + *hash = allocated_hash; + } +} + +/** + * Implementation of hasher_t.allocate_hash for SHA384. + */ +static void allocate_hash384(private_sha512_hasher_t *this, + chunk_t chunk, chunk_t *hash) +{ + chunk_t allocated_hash; + + sha512_write(this, chunk.ptr, chunk.len); + if (hash != NULL) + { + sha512_final(this); + allocated_hash = chunk_alloc(HASH_SIZE_SHA384); + memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA384); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + *hash = allocated_hash; + } +} + +/** + * Implementation of hasher_t.allocate_hash for SHA512. + */ +static void allocate_hash512(private_sha512_hasher_t *this, + chunk_t chunk, chunk_t *hash) +{ + chunk_t allocated_hash; + + sha512_write(this, chunk.ptr, chunk.len); + if (hash != NULL) + { + sha512_final(this); + allocated_hash = chunk_alloc(HASH_SIZE_SHA512); + memcpy(allocated_hash.ptr, this->sha_out, HASH_SIZE_SHA512); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + *hash = allocated_hash; + } +} + +/** + * Implementation of hasher_t.get_hash_size for SHA256. + */ +static size_t get_hash_size256(private_sha256_hasher_t *this) +{ + return HASH_SIZE_SHA256; +} + +/** + * Implementation of hasher_t.get_hash_size for SHA384. + */ +static size_t get_hash_size384(private_sha512_hasher_t *this) +{ + return HASH_SIZE_SHA384; +} + +/** + * Implementation of hasher_t.get_hash_size for SHA512. + */ +static size_t get_hash_size512(private_sha512_hasher_t *this) +{ + return HASH_SIZE_SHA512; +} + +/** + * Implementation of hasher_t.reset for SHA256 + */ +static void reset256(private_sha256_hasher_t *ctx) +{ + memcpy(&ctx->sha_H[0], &sha256_hashInit[0], sizeof(ctx->sha_H)); + ctx->sha_blocks = 0; + ctx->sha_bufCnt = 0; +} + +/** + * Implementation of hasher_t.reset for SHA384 + */ +static void reset384(private_sha512_hasher_t *ctx) +{ + memcpy(&ctx->sha_H[0], &sha384_hashInit[0], sizeof(ctx->sha_H)); + ctx->sha_blocks = 0; + ctx->sha_blocksMSB = 0; + ctx->sha_bufCnt = 0; +} + +/** + * Implementation of hasher_t.reset for SHA512 + */ +static void reset512(private_sha512_hasher_t *ctx) +{ + memcpy(&ctx->sha_H[0], &sha512_hashInit[0], sizeof(ctx->sha_H)); + ctx->sha_blocks = 0; + ctx->sha_blocksMSB = 0; + ctx->sha_bufCnt = 0; +} + +/** + * Implementation of hasher_t.destroy. + */ +static void destroy(sha2_hasher_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm) +{ + sha2_hasher_t *this; + + switch (algorithm) + { + case HASH_SHA256: + this = (sha2_hasher_t*)malloc_thing(private_sha256_hasher_t); + this->hasher_interface.reset = (void(*)(hasher_t*))reset256; + this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size256; + this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash256; + this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash256; + break; + case HASH_SHA384: + /* uses SHA512 data structure */ + this = (sha2_hasher_t*)malloc_thing(private_sha512_hasher_t); + this->hasher_interface.reset = (void(*)(hasher_t*))reset384; + this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size384; + this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash384; + this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash384; + break; + case HASH_SHA512: + this = (sha2_hasher_t*)malloc_thing(private_sha512_hasher_t); + this->hasher_interface.reset = (void(*)(hasher_t*))reset512; + this->hasher_interface.get_hash_size = (size_t(*)(hasher_t*))get_hash_size512; + this->hasher_interface.get_hash = (void(*)(hasher_t*,chunk_t,u_int8_t*))get_hash512; + this->hasher_interface.allocate_hash = (void(*)(hasher_t*,chunk_t,chunk_t*))allocate_hash512; + break; + default: + return NULL; + } + this->hasher_interface.destroy = (void(*)(hasher_t*))destroy; + + /* initialize */ + this->hasher_interface.reset(&this->hasher_interface); + + return this; +} diff --git a/src/libstrongswan/plugins/sha2/sha2_hasher.h b/src/libstrongswan/plugins/sha2/sha2_hasher.h new file mode 100644 index 000000000..6d732495a --- /dev/null +++ b/src/libstrongswan/plugins/sha2/sha2_hasher.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup sha2_hasher sha2_hasher + * @{ @ingroup sha2_p + */ + +#ifndef SHA2_HASHER_H_ +#define SHA2_HASHER_H_ + +typedef struct sha2_hasher_t sha2_hasher_t; + +#include <crypto/hashers/hasher.h> + +/** + * Implementation of hasher_t interface using the SHA2 algorithms. + * + * SHA2 is an other name for the SHA-256, SHA-384 and SHA-512 variants of + * the SHA hash algorithm. + */ +struct sha2_hasher_t { + + /** + * Generic hasher_t interface for this hasher. + */ + hasher_t hasher_interface; +}; + +/** + * Creates a new sha2_hasher_t. + * + * @param algorithm HASH_SHA256, HASH_SHA384 or HASH_SHA512 + * @return sha2_hasher_t object, NULL if not supported + */ +sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm); + +#endif /* SHA2_HASHER_H_ @}*/ diff --git a/src/libstrongswan/plugins/sha2/sha2_plugin.c b/src/libstrongswan/plugins/sha2/sha2_plugin.c new file mode 100644 index 000000000..993fa8793 --- /dev/null +++ b/src/libstrongswan/plugins/sha2/sha2_plugin.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "sha2_plugin.h" + +#include <library.h> +#include "sha2_hasher.h" + +typedef struct private_sha2_plugin_t private_sha2_plugin_t; + +/** + * private data of sha2_plugin + */ +struct private_sha2_plugin_t { + + /** + * public functions + */ + sha2_plugin_t public; +}; + +/** + * Implementation of sha2_plugin_t.destroy + */ +static void destroy(private_sha2_plugin_t *this) +{ + lib->crypto->remove_hasher(lib->crypto, + (hasher_constructor_t)sha2_hasher_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_sha2_plugin_t *this = malloc_thing(private_sha2_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->crypto->add_hasher(lib->crypto, HASH_SHA256, + (hasher_constructor_t)sha2_hasher_create); + lib->crypto->add_hasher(lib->crypto, HASH_SHA384, + (hasher_constructor_t)sha2_hasher_create); + lib->crypto->add_hasher(lib->crypto, HASH_SHA512, + (hasher_constructor_t)sha2_hasher_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/sha2/sha2_plugin.h b/src/libstrongswan/plugins/sha2/sha2_plugin.h new file mode 100644 index 000000000..859597758 --- /dev/null +++ b/src/libstrongswan/plugins/sha2/sha2_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup sha2_p sha2 + * @ingroup plugins + * + * @defgroup sha2_plugin sha2_plugin + * @{ @ingroup sha2_p + */ + +#ifndef SHA2_PLUGIN_H_ +#define SHA2_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct sha2_plugin_t sha2_plugin_t; + +/** + * Plugin implementing the SHA256, SHA384 and SHA512 algorithms in software. + */ +struct sha2_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a sha2_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* SHA2_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/sqlite/Makefile.am b/src/libstrongswan/plugins/sqlite/Makefile.am new file mode 100644 index 000000000..7c3017abf --- /dev/null +++ b/src/libstrongswan/plugins/sqlite/Makefile.am @@ -0,0 +1,12 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-sqlite.la + +libstrongswan_sqlite_la_SOURCES = sqlite_plugin.h sqlite_plugin.c \ + sqlite_database.h sqlite_database.c +libstrongswan_sqlite_la_LDFLAGS = -module +libstrongswan_sqlite_la_LIBADD = -lsqlite3 + diff --git a/src/libstrongswan/plugins/sqlite/sqlite_database.c b/src/libstrongswan/plugins/sqlite/sqlite_database.c new file mode 100644 index 000000000..06a89c68f --- /dev/null +++ b/src/libstrongswan/plugins/sqlite/sqlite_database.c @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "sqlite_database.h" + +#include <sqlite3.h> +#include <library.h> +#include <debug.h> +#include <utils/mutex.h> + +typedef struct private_sqlite_database_t private_sqlite_database_t; + +/** + * private data of sqlite_database + */ +struct private_sqlite_database_t { + + /** + * public functions + */ + sqlite_database_t public; + + /** + * sqlite database connection + */ + sqlite3 *db; + + /** + * mutex used to lock execute() + */ + mutex_t *mutex; +}; + +/** + * Create and run a sqlite stmt using a sql string and args + */ +static sqlite3_stmt* run(private_sqlite_database_t *this, char *sql, + va_list *args) +{ + sqlite3_stmt *stmt; + int params, i, res = SQLITE_OK; + + if (sqlite3_prepare_v2(this->db, sql, -1, &stmt, NULL) == SQLITE_OK) + { + params = sqlite3_bind_parameter_count(stmt); + for (i = 1; i <= params; i++) + { + switch (va_arg(*args, db_type_t)) + { + case DB_INT: + { + res = sqlite3_bind_int(stmt, i, va_arg(*args, int)); + break; + } + case DB_UINT: + { + res = sqlite3_bind_int64(stmt, i, va_arg(*args, u_int)); + break; + } + case DB_TEXT: + { + const char *text = va_arg(*args, const char*); + res = sqlite3_bind_text(stmt, i, text, -1, SQLITE_STATIC); + break; + } + case DB_BLOB: + { + chunk_t c = va_arg(*args, chunk_t); + res = sqlite3_bind_blob(stmt, i, c.ptr, c.len, SQLITE_STATIC); + break; + } + case DB_DOUBLE: + { + res = sqlite3_bind_double(stmt, i, va_arg(*args, double)); + break; + } + case DB_NULL: + { + res = sqlite3_bind_null(stmt, i); + break; + } + default: + { + res = SQLITE_MISUSE; + break; + } + } + if (res != SQLITE_OK) + { + break; + } + } + } + if (res != SQLITE_OK) + { + sqlite3_finalize(stmt); + return NULL; + } + return stmt; +} + +typedef struct { + /** implements enumerator_t */ + enumerator_t public; + /** associated sqlite statement */ + sqlite3_stmt *stmt; + /** number of result columns */ + int count; + /** column types */ + db_type_t *columns; +} sqlite_enumerator_t; + +/** + * destroy a sqlite enumerator + */ +static void sqlite_enumerator_destroy(sqlite_enumerator_t *this) +{ + sqlite3_finalize(this->stmt); + free(this->columns); + free(this); +} + +/** + * Implementation of database.query().enumerate + */ +static bool sqlite_enumerator_enumerate(sqlite_enumerator_t *this, ...) +{ + int i; + va_list args; + + if (sqlite3_step(this->stmt) != SQLITE_ROW) + { + return FALSE; + } + va_start(args, this); + for (i = 0; i < this->count; i++) + { + switch (this->columns[i]) + { + case DB_INT: + { + int *value = va_arg(args, int*); + *value = sqlite3_column_int(this->stmt, i); + break; + } + case DB_UINT: + { + u_int *value = va_arg(args, u_int*); + *value = (u_int)sqlite3_column_int64(this->stmt, i); + break; + } + case DB_TEXT: + { + const unsigned char **value = va_arg(args, const unsigned char**); + *value = sqlite3_column_text(this->stmt, i); + break; + } + case DB_BLOB: + { + chunk_t *chunk = va_arg(args, chunk_t*); + chunk->len = sqlite3_column_bytes(this->stmt, i); + chunk->ptr = (u_char*)sqlite3_column_blob(this->stmt, i); + break; + } + case DB_DOUBLE: + { + double *value = va_arg(args, double*); + *value = sqlite3_column_double(this->stmt, i); + break; + } + default: + return FALSE; + } + } + va_end(args); + return TRUE; +} + +/** + * Implementation of database_t.query. + */ +static enumerator_t* query(private_sqlite_database_t *this, char *sql, ...) +{ + sqlite3_stmt *stmt; + va_list args; + sqlite_enumerator_t *enumerator = NULL; + int i; + + + va_start(args, sql); + stmt = run(this, sql, &args); + if (stmt) + { + enumerator = malloc_thing(sqlite_enumerator_t); + enumerator->public.enumerate = (void*)sqlite_enumerator_enumerate; + enumerator->public.destroy = (void*)sqlite_enumerator_destroy; + enumerator->stmt = stmt; + enumerator->count = sqlite3_column_count(stmt); + enumerator->columns = malloc(sizeof(db_type_t) * enumerator->count); + for (i = 0; i < enumerator->count; i++) + { + enumerator->columns[i] = va_arg(args, db_type_t); + } + } + va_end(args); + return (enumerator_t*)enumerator; +} + +/** + * Implementation of database_t.execute. + */ +static int execute(private_sqlite_database_t *this, int *rowid, char *sql, ...) +{ + sqlite3_stmt *stmt; + int affected = -1; + va_list args; + + /* we need a lock to get our rowid/changes correctly */ + this->mutex->lock(this->mutex); + va_start(args, sql); + stmt = run(this, sql, &args); + va_end(args); + if (stmt) + { + if (sqlite3_step(stmt) == SQLITE_DONE) + { + if (rowid) + { + *rowid = sqlite3_last_insert_rowid(this->db); + } + affected = sqlite3_changes(this->db); + } + sqlite3_finalize(stmt); + } + this->mutex->unlock(this->mutex); + return affected; +} + +/** + * Implementation of database_t.destroy + */ +static void destroy(private_sqlite_database_t *this) +{ + sqlite3_close(this->db); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * see header file + */ +sqlite_database_t *sqlite_database_create(char *uri) +{ + char *file; + private_sqlite_database_t *this; + + /** + * parse sqlite:///path/to/file.db uri + */ + if (!strneq(uri, "sqlite://", 9)) + { + return NULL; + } + file = uri + 9; + + this = malloc_thing(private_sqlite_database_t); + + this->public.db.query = (enumerator_t* (*)(database_t *this, char *sql, ...))query; + this->public.db.execute = (int (*)(database_t *this, int *rowid, char *sql, ...))execute; + this->public.db.destroy = (void(*)(database_t*))destroy; + + if (sqlite3_open(file, &this->db) != SQLITE_OK) + { + DBG1("opening SQLite database '%s' failed", file); + destroy(this); + return NULL; + } + this->mutex = mutex_create(MUTEX_DEFAULT); + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/sqlite/sqlite_database.h b/src/libstrongswan/plugins/sqlite/sqlite_database.h new file mode 100644 index 000000000..795785627 --- /dev/null +++ b/src/libstrongswan/plugins/sqlite/sqlite_database.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup sqlite_database sqlite_database + * @{ @ingroup sqlite_p + */ + +#ifndef SQLITE_DATABASE_H_ +#define SQLITE_DATABASE_H_ + +#include <database/database.h> + +typedef struct sqlite_database_t sqlite_database_t; + +/** + * sqlite databse_t implementation. + */ +struct sqlite_database_t { + + /** + * Implements database_t + */ + database_t db; +}; + +/** + * Create a sqlite_database instance. + * + * @param uri connection URI, sqlite:///path/to/file.db + */ +sqlite_database_t *sqlite_database_create(char *uri); + +#endif /* SQLITE_DATABASE_H_ @}*/ diff --git a/src/libstrongswan/plugins/sqlite/sqlite_plugin.c b/src/libstrongswan/plugins/sqlite/sqlite_plugin.c new file mode 100644 index 000000000..e31b572fa --- /dev/null +++ b/src/libstrongswan/plugins/sqlite/sqlite_plugin.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "sqlite_plugin.h" + +#include <library.h> +#include "sqlite_database.h" + +typedef struct private_sqlite_plugin_t private_sqlite_plugin_t; + +/** + * private data of sqlite_plugin + */ +struct private_sqlite_plugin_t { + + /** + * public functions + */ + sqlite_plugin_t public; +}; + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(private_sqlite_plugin_t *this) +{ + lib->db->remove_database(lib->db, + (database_constructor_t)sqlite_database_create); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_sqlite_plugin_t *this = malloc_thing(private_sqlite_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->db->add_database(lib->db, + (database_constructor_t)sqlite_database_create); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/sqlite/sqlite_plugin.h b/src/libstrongswan/plugins/sqlite/sqlite_plugin.h new file mode 100644 index 000000000..07bf9618f --- /dev/null +++ b/src/libstrongswan/plugins/sqlite/sqlite_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup sqlite_p sqlite + * @ingroup plugins + * + * @defgroup sqlite_plugin sqlite_plugin + * @{ @ingroup sqlite_p + */ + +#ifndef SQLITE_PLUGIN_H_ +#define SQLITE_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct sqlite_plugin_t sqlite_plugin_t; + +/** + * Plugin implementing sqlite database connectivity + */ +struct sqlite_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a sqlite_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* SQLITE_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/Makefile.am b/src/libstrongswan/plugins/x509/Makefile.am new file mode 100644 index 000000000..12441b357 --- /dev/null +++ b/src/libstrongswan/plugins/x509/Makefile.am @@ -0,0 +1,13 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-x509.la + +libstrongswan_x509_la_SOURCES = x509_plugin.h x509_plugin.c \ + x509_cert.h x509_cert.c x509_crl.h x509_crl.c \ + x509_ocsp_request.h x509_ocsp_request.c \ + x509_ocsp_response.h x509_ocsp_response.c +libstrongswan_x509_la_LDFLAGS = -module + diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c new file mode 100644 index 000000000..47a841c51 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_cert.c @@ -0,0 +1,1273 @@ +/* + * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann + * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss + * Copyright (C) 2002 Mario Strasser + * Copyright (C) 2000-2006 Andreas Steffen + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#define _GNU_SOURCE + +#include "x509_cert.h" + +#include <gmp.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> + +#include <crypto/hashers/hasher.h> +#include <library.h> +#include <debug.h> +#include <asn1/oid.h> +#include <asn1/asn1.h> +#include <asn1/pem.h> +#include <utils/linked_list.h> +#include <utils/identification.h> + +/** + * Different kinds of generalNames + */ +typedef enum { + GN_OTHER_NAME = 0, + GN_RFC822_NAME = 1, + GN_DNS_NAME = 2, + GN_X400_ADDRESS = 3, + GN_DIRECTORY_NAME = 4, + GN_EDI_PARTY_NAME = 5, + GN_URI = 6, + GN_IP_ADDRESS = 7, + GN_REGISTERED_ID = 8, +} generalNames_t; + + +typedef struct private_x509_cert_t private_x509_cert_t; + +/** + * Private data of a x509_cert_t object. + */ +struct private_x509_cert_t { + /** + * Public interface for this certificate. + */ + x509_cert_t public; + + /** + * DER encoded X.509 certificate + */ + chunk_t certificate; + + /** + * X.509 certificate body over which signature is computed + */ + chunk_t tbsCertificate; + + /** + * Version of the X.509 certificate + */ + u_int version; + + /** + * Serial number of the X.509 certificate + */ + chunk_t serialNumber; + + /** + * ID representing the certificate issuer + */ + identification_t *issuer; + + /** + * Start time of certificate validity + */ + time_t notBefore; + + /** + * End time of certificate validity + */ + time_t notAfter; + + /** + * ID representing the certificate subject + */ + identification_t *subject; + + /** + * List of subjectAltNames as identification_t + */ + linked_list_t *subjectAltNames; + + /** + * List of crlDistributionPoints as allocated char* + */ + linked_list_t *crl_uris; + + /** + * List ocspAccessLocations as identification_t + */ + linked_list_t *ocsp_uris; + + /** + * certificates embedded public key + */ + public_key_t *public_key; + + /** + * Subject Key Identifier + */ + chunk_t subjectKeyID; + + /** + * Authority Key Identifier + */ + identification_t *authKeyIdentifier; + + /** + * Authority Key Serial Number + */ + chunk_t authKeySerialNumber; + + /** + * x509 constraints and other flags + */ + x509_flag_t flags; + + /** + * Signature algorithm + */ + int algorithm; + + /** + * Signature + */ + chunk_t signature; + + /** + * reference count + */ + refcount_t ref; +}; + +/** + * ASN.1 definition of generalName + */ +static const asn1Object_t generalNameObjects[] = { + { 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 0 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */ + { 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT|ASN1_BODY }, /* 2 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */ + { 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 4 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ + { 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT|ASN1_BODY }, /* 6 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ + { 0, "directoryName", ASN1_CONTEXT_C_4, ASN1_OPT|ASN1_BODY }, /* 8 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ + { 0, "ediPartyName", ASN1_CONTEXT_C_5, ASN1_OPT|ASN1_BODY }, /* 10 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ + { 0, "URI", ASN1_CONTEXT_S_6, ASN1_OPT|ASN1_BODY }, /* 12 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */ + { 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT|ASN1_BODY }, /* 14 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */ + { 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT|ASN1_BODY }, /* 16 */ + { 0, "end choice", ASN1_EOC, ASN1_END } /* 17 */ +}; + +#define GN_OBJ_OTHER_NAME 0 +#define GN_OBJ_RFC822_NAME 2 +#define GN_OBJ_DNS_NAME 4 +#define GN_OBJ_X400_ADDRESS 6 +#define GN_OBJ_DIRECTORY_NAME 8 +#define GN_OBJ_EDI_PARTY_NAME 10 +#define GN_OBJ_URI 12 +#define GN_OBJ_IP_ADDRESS 14 +#define GN_OBJ_REGISTERED_ID 16 +#define GN_OBJ_ROOF 18 + +/** + * ASN.1 definition of otherName + */ +static const asn1Object_t otherNameObjects[] = { + {0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */ + {0, "value", ASN1_CONTEXT_C_0, ASN1_BODY } /* 1 */ +}; + +#define ON_OBJ_ID_TYPE 0 +#define ON_OBJ_VALUE 1 +#define ON_OBJ_ROOF 2 + +/** + * ASN.1 definition of a basicConstraints extension + */ +static const asn1Object_t basicConstraintsObjects[] = { + { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "CA", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 1 */ + { 1, "pathLenConstraint", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 2 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */ +}; + +#define BASIC_CONSTRAINTS_CA 1 +#define BASIC_CONSTRAINTS_ROOF 4 + +/** + * ASN.1 definition of a keyIdentifier + */ +static const asn1Object_t keyIdentifierObjects[] = { + { 0, "keyIdentifier", ASN1_OCTET_STRING, ASN1_BODY } /* 0 */ +}; + +/** + * ASN.1 definition of a authorityKeyIdentifier extension + */ +static const asn1Object_t authorityKeyIdentifierObjects[] = { + { 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "keyIdentifier", ASN1_CONTEXT_S_0, ASN1_OPT|ASN1_OBJ }, /* 1 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ + { 1, "authorityCertIssuer", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_OBJ }, /* 3 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */ + { 1, "authorityCertSerialNumber",ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 5 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */ +}; + +#define AUTH_KEY_ID_KEY_ID 1 +#define AUTH_KEY_ID_CERT_ISSUER 3 +#define AUTH_KEY_ID_CERT_SERIAL 5 +#define AUTH_KEY_ID_ROOF 7 + +/** + * ASN.1 definition of a authorityInfoAccess extension + */ +static const asn1Object_t authorityInfoAccessObjects[] = { + { 0, "authorityInfoAccess", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "accessDescription", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "accessMethod", ASN1_OID, ASN1_BODY }, /* 2 */ + { 2, "accessLocation", ASN1_EOC, ASN1_RAW }, /* 3 */ + { 0, "end loop", ASN1_EOC, ASN1_END } /* 4 */ +}; + +#define AUTH_INFO_ACCESS_METHOD 2 +#define AUTH_INFO_ACCESS_LOCATION 3 +#define AUTH_INFO_ACCESS_ROOF 5 + +/** + * ASN.1 definition of a extendedKeyUsage extension + */ +static const asn1Object_t extendedKeyUsageObjects[] = { + { 0, "extendedKeyUsage", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "keyPurposeID", ASN1_OID, ASN1_BODY }, /* 1 */ + { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ +}; + +#define EXT_KEY_USAGE_PURPOSE_ID 1 +#define EXT_KEY_USAGE_ROOF 3 + +/** + * ASN.1 definition of generalNames + */ +static const asn1Object_t generalNamesObjects[] = { + { 0, "generalNames", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "generalName", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */ +}; + +#define GENERAL_NAMES_GN 1 +#define GENERAL_NAMES_ROOF 3 + + +/** + * ASN.1 definition of crlDistributionPoints + */ +static const asn1Object_t crlDistributionPointsObjects[] = { + { 0, "crlDistributionPoints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "DistributionPoint", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "distributionPoint", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 2 */ + { 3, "fullName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ }, /* 3 */ + { 3, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ + { 3, "nameRelToCRLIssuer",ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 5 */ + { 3, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ + { 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 8 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ + { 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT|ASN1_BODY }, /* 10 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ + { 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */ +}; + +#define CRL_DIST_POINTS_FULLNAME 3 +#define CRL_DIST_POINTS_ROOF 13 + +/** + * ASN.1 definition of an X.509v3 x509_cert + */ +static const asn1Object_t certObjects[] = { + { 0, "x509", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ + { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */ + { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ + { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */ + { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */ + { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ + { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */ + { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */ + { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */ + { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ + { 2, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_NONE }, /* 11 */ + { 3, "algorithm", ASN1_EOC, ASN1_RAW }, /* 12 */ + { 3, "subjectPublicKey", ASN1_BIT_STRING, ASN1_NONE }, /* 13 */ + { 4, "RSAPublicKey", ASN1_SEQUENCE, ASN1_RAW }, /* 14 */ + { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 15 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 16 */ + { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 17 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 18 */ + { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 19 */ + { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */ + { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */ + { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */ + { 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 23 */ + { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */ + { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ + { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */ + { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */ +}; + +#define X509_OBJ_TBS_CERTIFICATE 1 +#define X509_OBJ_VERSION 3 +#define X509_OBJ_SERIAL_NUMBER 4 +#define X509_OBJ_SIG_ALG 5 +#define X509_OBJ_ISSUER 6 +#define X509_OBJ_NOT_BEFORE 8 +#define X509_OBJ_NOT_AFTER 9 +#define X509_OBJ_SUBJECT 10 +#define X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM 12 +#define X509_OBJ_SUBJECT_PUBLIC_KEY 13 +#define X509_OBJ_RSA_PUBLIC_KEY 14 +#define X509_OBJ_EXTN_ID 22 +#define X509_OBJ_CRITICAL 23 +#define X509_OBJ_EXTN_VALUE 24 +#define X509_OBJ_ALGORITHM 27 +#define X509_OBJ_SIGNATURE 28 +#define X509_OBJ_ROOF 29 + + +static u_char ASN1_sAN_oid_buf[] = { + 0x06, 0x03, 0x55, 0x1D, 0x11 +}; +static const chunk_t ASN1_subjectAltName_oid = chunk_from_buf(ASN1_sAN_oid_buf); + +/** + * extracts the basicConstraints extension + */ +static bool parse_basicConstraints(chunk_t blob, int level0) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + bool isCA = FALSE; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < BASIC_CONSTRAINTS_ROOF) { + + if (!extract_object(basicConstraintsObjects, &objectID, &object,&level, &ctx)) + { + break; + } + if (objectID == BASIC_CONSTRAINTS_CA) + { + isCA = object.len && *object.ptr; + DBG2(" %s", isCA ? "TRUE" : "FALSE"); + } + objectID++; + } + return isCA; +} + +/* + * extracts an otherName + */ +static bool parse_otherName(chunk_t blob, int level0) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + int oid = OID_UNKNOWN; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < ON_OBJ_ROOF) + { + if (!extract_object(otherNameObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + switch (objectID) + { + case ON_OBJ_ID_TYPE: + oid = known_oid(object); + break; + case ON_OBJ_VALUE: + if (oid == OID_XMPP_ADDR) + { + if (!parse_asn1_simple_object(&object, ASN1_UTF8STRING, + level + 1, "xmppAddr")) + { + return FALSE; + } + } + break; + default: + break; + } + objectID++; + } + return TRUE; +} + +/* + * extracts a generalName + */ +static identification_t *parse_generalName(chunk_t blob, int level0) +{ + asn1_ctx_t ctx; + chunk_t object; + int objectID = 0; + u_int level; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < GN_OBJ_ROOF) + { + id_type_t id_type = ID_ANY; + + if (!extract_object(generalNameObjects, &objectID, &object, &level, &ctx)) + { + return NULL; + } + switch (objectID) + { + case GN_OBJ_RFC822_NAME: + id_type = ID_RFC822_ADDR; + break; + case GN_OBJ_DNS_NAME: + id_type = ID_FQDN; + break; + case GN_OBJ_URI: + id_type = ID_DER_ASN1_GN_URI; + break; + case GN_OBJ_DIRECTORY_NAME: + id_type = ID_DER_ASN1_DN; + break; + case GN_OBJ_IP_ADDRESS: + id_type = ID_IPV4_ADDR; + break; + case GN_OBJ_OTHER_NAME: + if (!parse_otherName(object, level + 1)) + return NULL; + break; + case GN_OBJ_X400_ADDRESS: + case GN_OBJ_EDI_PARTY_NAME: + case GN_OBJ_REGISTERED_ID: + break; + default: + break; + } + if (id_type != ID_ANY) + { + identification_t *gn = identification_create_from_encoding(id_type, object); + DBG2(" '%D'", gn); + return gn; + } + objectID++; + } + return NULL; +} + + +/** + * extracts one or several GNs and puts them into a chained list + */ +void parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, blob, level0, implicit, FALSE); + while (objectID < GENERAL_NAMES_ROOF) + { + if (!extract_object(generalNamesObjects, &objectID, &object, &level, &ctx)) + { + return; + } + if (objectID == GENERAL_NAMES_GN) + { + identification_t *gn = parse_generalName(object, level+1); + + if (gn != NULL) + { + list->insert_last(list, (void *)gn); + } + } + objectID++; + } + return; +} + +/** + * extracts a keyIdentifier + */ +static chunk_t parse_keyIdentifier(chunk_t blob, int level0, bool implicit) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, blob, level0, implicit, FALSE); + if (!extract_object(keyIdentifierObjects, &objectID, &object, &level, &ctx)) + { + return chunk_empty; + } + return object; +} + +/** + * extracts an authoritykeyIdentifier + */ +identification_t* x509_parse_authorityKeyIdentifier(chunk_t blob, int level0, + chunk_t *authKeySerialNumber) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + identification_t *authKeyIdentifier = NULL; + + *authKeySerialNumber = chunk_empty; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < AUTH_KEY_ID_ROOF) + { + if (!extract_object(authorityKeyIdentifierObjects, &objectID, &object, &level, &ctx)) + { + return NULL; + } + switch (objectID) + { + case AUTH_KEY_ID_KEY_ID: + { + chunk_t authKeyID = parse_keyIdentifier(object, level+1, TRUE); + + if (authKeyID.ptr == NULL) + { + return NULL; + } + authKeyIdentifier = identification_create_from_encoding( + ID_PUBKEY_SHA1, authKeyID); + break; + } + case AUTH_KEY_ID_CERT_ISSUER: + { + /* TODO: parse_generalNames(object, level+1, TRUE); */ + break; + } + case AUTH_KEY_ID_CERT_SERIAL: + *authKeySerialNumber = object; + break; + default: + break; + } + objectID++; + } + return authKeyIdentifier; +} + +/** + * extracts an authorityInfoAcess location + */ +static void parse_authorityInfoAccess(chunk_t blob, int level0, + private_x509_cert_t *this) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + int accessMethod = OID_UNKNOWN; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < AUTH_INFO_ACCESS_ROOF) + { + if (!extract_object(authorityInfoAccessObjects, &objectID, &object, &level, &ctx)) + { + return; + } + switch (objectID) + { + case AUTH_INFO_ACCESS_METHOD: + accessMethod = known_oid(object); + break; + case AUTH_INFO_ACCESS_LOCATION: + { + switch (accessMethod) + { + case OID_OCSP: + case OID_CA_ISSUERS: + { + identification_t *id; + char *uri; + + id = parse_generalName(object, level+1); + if (id == NULL) + { /* parsing went wrong - abort */ + return; + } + DBG2(" '%D'", id); + if (accessMethod == OID_OCSP && + asprintf(&uri, "%D", id) > 0) + { + this->ocsp_uris->insert_last(this->ocsp_uris, uri); + } + id->destroy(id); + } + break; + default: + /* unkown accessMethod, ignoring */ + break; + } + break; + } + default: + break; + } + objectID++; + } +} + +/** + * extracts extendedKeyUsage OIDs + */ +static bool parse_extendedKeyUsage(chunk_t blob, int level0) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < EXT_KEY_USAGE_ROOF) + { + if (!extract_object(extendedKeyUsageObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + if (objectID == EXT_KEY_USAGE_PURPOSE_ID && + known_oid(object) == OID_OCSP_SIGNING) + { + return TRUE; + } + objectID++; + } + return FALSE; +} + +/** + * extracts one or several crlDistributionPoints into a list + */ +static void parse_crlDistributionPoints(chunk_t blob, int level0, + private_x509_cert_t *this) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + linked_list_t *list; + identification_t *id; + char *uri; + + list = linked_list_create(); + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < CRL_DIST_POINTS_ROOF) + { + if (!extract_object(crlDistributionPointsObjects, &objectID, &object, &level, &ctx)) + { + list->destroy_offset(list, offsetof(identification_t, destroy)); + return; + } + if (objectID == CRL_DIST_POINTS_FULLNAME) + { /* append extracted generalNames to existing chained list */ + parse_generalNames(object, level+1, TRUE, list); + + while (list->remove_last(list, (void**)&id) == SUCCESS) + { + if (asprintf(&uri, "%D", id) > 0) + { + this->crl_uris->insert_last(this->crl_uris, uri); + } + id->destroy(id); + } + } + objectID++; + } + list->destroy(list); +} + +/** + * Parses an X.509v3 certificate + */ +static bool parse_certificate(private_x509_cert_t *this) +{ + asn1_ctx_t ctx; + bool critical; + chunk_t object; + u_int level; + int objectID = 0; + int extn_oid = OID_UNKNOWN; + int key_alg = 0; + int sig_alg = 0; + chunk_t subjectPublicKey = chunk_empty; + + asn1_init(&ctx, this->certificate, 0, FALSE, FALSE); + while (objectID < X509_OBJ_ROOF) + { + if (!extract_object(certObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + /* those objects which will parsed further need the next higher level */ + level++; + switch (objectID) + { + case X509_OBJ_TBS_CERTIFICATE: + this->tbsCertificate = object; + break; + case X509_OBJ_VERSION: + this->version = (object.len) ? (1+(u_int)*object.ptr) : 1; + DBG2(" v%d", this->version); + break; + case X509_OBJ_SERIAL_NUMBER: + this->serialNumber = object; + break; + case X509_OBJ_SIG_ALG: + sig_alg = parse_algorithmIdentifier(object, level, NULL); + break; + case X509_OBJ_ISSUER: + this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); + DBG2(" '%D'", this->issuer); + break; + case X509_OBJ_NOT_BEFORE: + this->notBefore = parse_time(object, level); + break; + case X509_OBJ_NOT_AFTER: + this->notAfter = parse_time(object, level); + break; + case X509_OBJ_SUBJECT: + this->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object); + DBG2(" '%D'", this->subject); + break; + case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM: + key_alg = parse_algorithmIdentifier(object, level, NULL); + break; + case X509_OBJ_SUBJECT_PUBLIC_KEY: + if (ctx.blobs[4].len > 0 && *ctx.blobs[4].ptr == 0x00) + { + /* skip initial bit string octet defining 0 unused bits */ + ctx.blobs[4].ptr++; ctx.blobs[4].len--; + } + break; + case X509_OBJ_RSA_PUBLIC_KEY: + subjectPublicKey = object; + switch (key_alg) + { + case OID_RSA_ENCRYPTION: + this->public_key = lib->creds->create(lib->creds, + CRED_PUBLIC_KEY, KEY_RSA, + BUILD_BLOB_ASN1_DER, chunk_clone(subjectPublicKey), + BUILD_END); + break; + default: + DBG1("parsing key type %d failed", key_alg); + return FALSE; + } + break; + case X509_OBJ_EXTN_ID: + extn_oid = known_oid(object); + break; + case X509_OBJ_CRITICAL: + critical = object.len && *object.ptr; + DBG2(" %s", critical ? "TRUE" : "FALSE"); + break; + case X509_OBJ_EXTN_VALUE: + { + switch (extn_oid) + { + case OID_SUBJECT_KEY_ID: + this->subjectKeyID = parse_keyIdentifier(object, level, FALSE); + break; + case OID_SUBJECT_ALT_NAME: + parse_generalNames(object, level, FALSE, this->subjectAltNames); + break; + case OID_BASIC_CONSTRAINTS: + if (parse_basicConstraints(object, level)) + { + this->flags |= X509_CA; + } + break; + case OID_CRL_DISTRIBUTION_POINTS: + parse_crlDistributionPoints(object, level, this); + break; + case OID_AUTHORITY_KEY_ID: + this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object, + level, &this->authKeySerialNumber); + break; + case OID_AUTHORITY_INFO_ACCESS: + parse_authorityInfoAccess(object, level, this); + break; + case OID_EXTENDED_KEY_USAGE: + if (parse_extendedKeyUsage(object, level)) + { + this->flags |= X509_OCSP_SIGNER; + } + break; + case OID_NS_REVOCATION_URL: + case OID_NS_CA_REVOCATION_URL: + case OID_NS_CA_POLICY_URL: + case OID_NS_COMMENT: + if (!parse_asn1_simple_object(&object, ASN1_IA5STRING, + level, oid_names[extn_oid].name)) + return FALSE; + break; + default: + break; + } + break; + } + case X509_OBJ_ALGORITHM: + this->algorithm = parse_algorithmIdentifier(object, level, NULL); + if (this->algorithm != sig_alg) + { + DBG1(" signature algorithms do not agree"); + return FALSE; + } + break; + case X509_OBJ_SIGNATURE: + this->signature = object; + break; + default: + break; + } + objectID++; + } + return TRUE; +} + +/** + * Implementation of certificate_t.get_type + */ +static certificate_type_t get_type(private_x509_cert_t *this) +{ + return CERT_X509; +} + +/** + * Implementation of certificate_t.get_subject + */ +static identification_t* get_subject(private_x509_cert_t *this) +{ + return this->subject; +} + +/** + * Implementation of certificate_t.get_issuer + */ +static identification_t* get_issuer(private_x509_cert_t *this) +{ + return this->issuer; +} + +/** + * Implementation of certificate_t.has_subject. + */ +static id_match_t has_subject(private_x509_cert_t *this, identification_t *subject) +{ + identification_t *current; + enumerator_t *enumerator; + id_match_t match, best; + + best = this->subject->matches(this->subject, subject); + enumerator = this->subjectAltNames->create_enumerator(this->subjectAltNames); + while (enumerator->enumerate(enumerator, ¤t)) + { + match = current->matches(current, subject); + if (match > best) + { + best = match; + } + } + enumerator->destroy(enumerator); + return best; +} + +/** + * Implementation of certificate_t.has_subject. + */ +static id_match_t has_issuer(private_x509_cert_t *this, identification_t *issuer) +{ + /* issuerAltNames currently not supported */ + return this->issuer->matches(this->issuer, issuer); +} + +/** + * Implementation of certificate_t.issued_by + */ +static bool issued_by(private_x509_cert_t *this, certificate_t *issuer, + bool sigcheck) +{ + public_key_t *key; + signature_scheme_t scheme; + bool valid; + x509_t *x509 = (x509_t*)issuer; + + if (&this->public.interface.interface == issuer && + (this->flags & X509_SELF_SIGNED)) + { + return TRUE; + } + if (issuer->get_type(issuer) != CERT_X509) + { + return FALSE; + } + if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer))) + { + return FALSE; + } + if (!(x509->get_flags(x509) & X509_CA)) + { + return FALSE; + } + if (!sigcheck) + { + return TRUE; + } + /* TODO: generic OID to scheme mapper? */ + switch (this->algorithm) + { + case OID_MD5_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_MD5; + break; + case OID_SHA1_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + break; + case OID_SHA256_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA256; + break; + case OID_SHA384_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA384; + break; + case OID_SHA512_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA512; + break; + default: + return FALSE; + } + key = issuer->get_public_key(issuer); + if (key == NULL) + { + return FALSE; + } + /* TODO: add a lightweight check option (comparing auth/subject keyids only) */ + valid = key->verify(key, scheme, this->tbsCertificate, this->signature); + key->destroy(key); + return valid; +} + +/** + * Implementation of certificate_t.get_public_key + */ +static public_key_t* get_public_key(private_x509_cert_t *this) +{ + this->public_key->get_ref(this->public_key); + return this->public_key; +} + +/** + * Implementation of certificate_t.asdf + */ +static private_x509_cert_t* get_ref(private_x509_cert_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of x509_cert_t.set_flags. + */ +static void set_flags(private_x509_cert_t *this, x509_flag_t flags) +{ + this->flags = flags; +} + +/** + * Implementation of x509_cert_t.get_flags. + */ +static x509_flag_t get_flags(private_x509_cert_t *this) +{ + return this->flags; +} + +/** + * Implementation of x509_cert_t.get_validity. + */ +static bool get_validity(private_x509_cert_t *this, time_t *when, + time_t *not_before, time_t *not_after) +{ + time_t t; + + if (when) + { + t = *when; + } + else + { + t = time(NULL); + } + if (not_after) + { + *not_after = this->notAfter; + } + if (not_before) + { + *not_before = this->notBefore; + } + return (t >= this->notBefore && t <= this->notAfter); +} + +/** + * Implementation of certificate_t.get_encoding. + */ +static chunk_t get_encoding(private_x509_cert_t *this) +{ + return chunk_clone(this->certificate); +} + +/** + * Implementation of certificate_t.equals. + */ +static bool equals(private_x509_cert_t *this, certificate_t *other) +{ + if (this == (private_x509_cert_t*)other) + { + return TRUE; + } + if (other->get_type(other) != CERT_X509) + { + return FALSE; + } + /* check if we have the same X509 implementation */ + if (other->equals == (void*)equals) + { + if (this->signature.len == 0) + { + return FALSE; + } + return chunk_equals(this->signature, ((private_x509_cert_t*)other)->signature); + } + /* TODO: compare against other implementation */ + return FALSE; +} + +/** + * Implementation of x509_t.get_serial. + */ +static chunk_t get_serial(private_x509_cert_t *this) +{ + return this->serialNumber; +} + +/** + * Implementation of x509_t.get_authKeyIdentifier. + */ +static identification_t *get_authKeyIdentifier(private_x509_cert_t *this) +{ + return this->authKeyIdentifier; +} + +/** + * Implementation of x509_cert_t.create_subjectAltName_enumerator. + */ +static enumerator_t* create_subjectAltName_enumerator(private_x509_cert_t *this) +{ + return this->subjectAltNames->create_enumerator(this->subjectAltNames); +} + +/** + * Implementation of x509_cert_t.create_ocsp_uri_enumerator. + */ +static enumerator_t* create_ocsp_uri_enumerator(private_x509_cert_t *this) +{ + return this->ocsp_uris->create_enumerator(this->ocsp_uris); +} + +/** + * Implementation of x509_cert_t.create_crl_uri_enumerator. + */ +static enumerator_t* create_crl_uri_enumerator(private_x509_cert_t *this) +{ + return this->crl_uris->create_enumerator(this->crl_uris); +} + +/** + * Implementation of certificate_t.asdf + */ +static void destroy(private_x509_cert_t *this) +{ + if (ref_put(&this->ref)) + { + this->subjectAltNames->destroy_offset(this->subjectAltNames, + offsetof(identification_t, destroy)); + this->crl_uris->destroy_function(this->crl_uris, free); + this->ocsp_uris->destroy_function(this->ocsp_uris, free); + DESTROY_IF(this->issuer); + DESTROY_IF(this->subject); + DESTROY_IF(this->public_key); + DESTROY_IF(this->authKeyIdentifier); + chunk_free(&this->certificate); + free(this); + } +} + +/** + * load x509 certificate from a chunk + */ +static x509_cert_t *load(chunk_t chunk) +{ + private_x509_cert_t *this = malloc_thing(private_x509_cert_t); + + this->public.interface.interface.get_type = (certificate_type_t (*)(certificate_t *this))get_type; + this->public.interface.interface.get_subject = (identification_t* (*)(certificate_t *this))get_subject; + this->public.interface.interface.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; + this->public.interface.interface.has_subject = (id_match_t (*)(certificate_t*, identification_t *subject))has_subject; + this->public.interface.interface.has_issuer = (id_match_t (*)(certificate_t*, identification_t *issuer))has_issuer; + this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by; + this->public.interface.interface.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key; + this->public.interface.interface.get_validity = (bool (*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity; + this->public.interface.interface.get_encoding = (chunk_t (*)(certificate_t*))get_encoding; + this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t *other))equals; + this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t *this))get_ref; + this->public.interface.interface.destroy = (void (*)(certificate_t *this))destroy; + this->public.interface.set_flags = (void (*)(x509_t*, x509_flag_t flags))set_flags; + this->public.interface.get_flags = (x509_flag_t (*)(x509_t*))get_flags; + this->public.interface.get_serial = (chunk_t (*)(x509_t*))get_serial; + this->public.interface.get_authKeyIdentifier = (identification_t* (*)(x509_t*))get_authKeyIdentifier; + this->public.interface.create_subjectAltName_enumerator = (enumerator_t* (*)(x509_t*))create_subjectAltName_enumerator; + this->public.interface.create_crl_uri_enumerator = (enumerator_t* (*)(x509_t*))create_crl_uri_enumerator; + this->public.interface.create_ocsp_uri_enumerator = (enumerator_t* (*)(x509_t*))create_ocsp_uri_enumerator; + + this->certificate = chunk; + this->public_key = NULL; + this->subject = NULL; + this->issuer = NULL; + this->subjectAltNames = linked_list_create(); + this->crl_uris = linked_list_create(); + this->ocsp_uris = linked_list_create(); + this->subjectKeyID = chunk_empty; + this->authKeyIdentifier = NULL; + this->authKeySerialNumber = chunk_empty; + this->flags = 0; + this->ref = 1; + + if (!parse_certificate(this)) + { + destroy(this); + return NULL; + } + if (issued_by(this, &this->public.interface.interface, FALSE)) + { + this->flags |= X509_SELF_SIGNED; + } + return &this->public; +} + +typedef struct private_builder_t private_builder_t; +/** + * Builder implementation for certificate loading + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** loaded certificate */ + x509_cert_t *cert; +}; + +/** + * Implementation of builder_t.build + */ +static x509_cert_t *build(private_builder_t *this) +{ + x509_cert_t *cert = this->cert; + + free(this); + return cert; +} + +/** + * Implementation of builder_t.add + */ +static void add(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + + if (this->cert) + { + DBG1("ignoring surplus build part %N", builder_part_names, part); + return; + } + + switch (part) + { + case BUILD_BLOB_ASN1_DER: + { + va_start(args, part); + this->cert = load(va_arg(args, chunk_t)); + va_end(args); + break; + } + default: + DBG1("ignoring unsupported build part %N", builder_part_names, part); + break; + } +} + +/** + * Builder construction function + */ +builder_t *x509_cert_builder(certificate_type_t type) +{ + private_builder_t *this; + + if (type != CERT_X509) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->cert = NULL; + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; + this->public.build = (void*(*)(builder_t *this))build; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/x509/x509_cert.h b/src/libstrongswan/plugins/x509/x509_cert.h new file mode 100644 index 000000000..be6e41b4d --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_cert.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup x509_cert x509_cert + * @{ @ingroup x509_p + */ + +#ifndef X509_CERT_H_ +#define X509_CERT_H_ + +typedef struct x509_cert_t x509_cert_t; + +#include <credentials/certificates/x509.h> + +/** + * Implementation of x509_t/certificate_t using own ASN1 parser. + */ +struct x509_cert_t { + + /** + * Implements the x509_t interface + */ + x509_t interface; +}; + +/** + * Create the building facility for x509 certificates + * + * @param type certificate type, CERT_X509 only + * @return builder instance to build certificate + */ +builder_t *x509_cert_builder(certificate_type_t type); + +#endif /* X509_CERT_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_crl.c b/src/libstrongswan/plugins/x509/x509_crl.c new file mode 100644 index 000000000..7e2bdf2b6 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_crl.c @@ -0,0 +1,717 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "x509_crl.h" + +typedef struct private_x509_crl_t private_x509_crl_t; +typedef struct revoked_t revoked_t; + +#include <debug.h> +#include <library.h> +#include <asn1/asn1.h> +#include <credentials/certificates/x509.h> + +/** + * entry for a revoked certificate + */ +struct revoked_t { + /** + * serial of the revoked certificate + */ + chunk_t serial; + + /** + * date of revocation + */ + time_t date; + + /** + * reason for revocation + */ + crl_reason_t reason; +}; + +/** + * private data of x509_crl + */ +struct private_x509_crl_t { + + /** + * public functions + */ + x509_crl_t public; + + /** + * X.509 crl in DER format + */ + chunk_t certificateList; + + /** + * X.509 crl body over which signature is computed + */ + chunk_t tbsCertList; + + /** + * Version of the X.509 crl + */ + u_int version; + + /** + * ID representing the crl issuer + */ + identification_t *issuer; + + /** + * CRL number + */ + chunk_t crlNumber; + + /** + * Time when the crl was generated + */ + time_t thisUpdate; + + /** + * Time when an update crl will be available + */ + time_t nextUpdate; + + /** + * list of revoked certificates as revoked_t + */ + linked_list_t *revoked; + + /** + * Authority Key Identifier + */ + identification_t *authKeyIdentifier; + + /** + * Authority Key Serial Number + */ + chunk_t authKeySerialNumber; + + /** + * Signature algorithm + */ + int algorithm; + + /** + * Signature + */ + chunk_t signature; + + /** + * reference counter + */ + refcount_t ref; +}; + +/** + * from x509_cert + */ +extern identification_t* x509_parse_authorityKeyIdentifier( + chunk_t blob, int level0, + chunk_t *authKeySerialNumber); + +/** + * ASN.1 definition of an X.509 certificate revocation list + */ +static const asn1Object_t crlObjects[] = { + { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ + { 2, "version", ASN1_INTEGER, ASN1_OPT | + ASN1_BODY }, /* 2 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ + { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */ + { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ + { 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */ + { 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */ + { 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT | + ASN1_LOOP }, /* 8 */ + { 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */ + { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */ + { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */ + { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT | + ASN1_LOOP }, /* 12 */ + { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */ + { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */ + { 6, "critical", ASN1_BOOLEAN, ASN1_DEF | + ASN1_BODY }, /* 15 */ + { 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */ + { 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */ + { 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */ + { 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */ + { 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */ + { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */ + { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */ + { 5, "critical", ASN1_BOOLEAN, ASN1_DEF | + ASN1_BODY }, /* 23 */ + { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */ + { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ + { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */ + { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */ + }; + +#define CRL_OBJ_TBS_CERT_LIST 1 +#define CRL_OBJ_VERSION 2 +#define CRL_OBJ_SIG_ALG 4 +#define CRL_OBJ_ISSUER 5 +#define CRL_OBJ_THIS_UPDATE 6 +#define CRL_OBJ_NEXT_UPDATE 7 +#define CRL_OBJ_USER_CERTIFICATE 10 +#define CRL_OBJ_REVOCATION_DATE 11 +#define CRL_OBJ_CRL_ENTRY_EXTN_ID 14 +#define CRL_OBJ_CRL_ENTRY_CRITICAL 15 +#define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16 +#define CRL_OBJ_EXTN_ID 22 +#define CRL_OBJ_CRITICAL 23 +#define CRL_OBJ_EXTN_VALUE 24 +#define CRL_OBJ_ALGORITHM 27 +#define CRL_OBJ_SIGNATURE 28 +#define CRL_OBJ_ROOF 29 + +/** + * Parses an X.509 Certificate Revocation List (CRL) + */ +static bool parse(private_x509_crl_t *this) +{ + asn1_ctx_t ctx; + bool critical; + chunk_t extnID; + chunk_t userCertificate = chunk_empty; + revoked_t *revoked = NULL; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, this->certificateList, 0, FALSE, FALSE); + while (objectID < CRL_OBJ_ROOF) + { + if (!extract_object(crlObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + + /* those objects which will parsed further need the next higher level */ + level++; + + switch (objectID) + { + case CRL_OBJ_TBS_CERT_LIST: + this->tbsCertList = object; + break; + case CRL_OBJ_VERSION: + this->version = (object.len) ? (1+(u_int)*object.ptr) : 1; + DBG2(" v%d", this->version); + break; + case CRL_OBJ_SIG_ALG: + this->algorithm = parse_algorithmIdentifier(object, level, NULL); + break; + case CRL_OBJ_ISSUER: + this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); + DBG2(" '%D'", this->issuer); + break; + case CRL_OBJ_THIS_UPDATE: + this->thisUpdate = parse_time(object, level); + break; + case CRL_OBJ_NEXT_UPDATE: + this->nextUpdate = parse_time(object, level); + break; + case CRL_OBJ_USER_CERTIFICATE: + userCertificate = object; + break; + case CRL_OBJ_REVOCATION_DATE: + revoked = malloc_thing(revoked_t); + revoked->serial = userCertificate; + revoked->date = parse_time(object, level); + revoked->reason = CRL_UNSPECIFIED; + this->revoked->insert_last(this->revoked, (void *)revoked); + break; + case CRL_OBJ_CRL_ENTRY_EXTN_ID: + case CRL_OBJ_EXTN_ID: + extnID = object; + break; + case CRL_OBJ_CRL_ENTRY_CRITICAL: + case CRL_OBJ_CRITICAL: + critical = object.len && *object.ptr; + DBG2(" %s", critical ? "TRUE" : "FALSE"); + break; + case CRL_OBJ_CRL_ENTRY_EXTN_VALUE: + case CRL_OBJ_EXTN_VALUE: + { + int extn_oid = known_oid(extnID); + + if (revoked && extn_oid == OID_CRL_REASON_CODE) + { + if (*object.ptr == ASN1_ENUMERATED && + asn1_length(&object) == 1) + { + revoked->reason = *object.ptr; + } + DBG2(" '%N'", crl_reason_names, revoked->reason); + } + else if (extn_oid == OID_AUTHORITY_KEY_ID) + { + + this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object, + level, &this->authKeySerialNumber); + } + else if (extn_oid == OID_CRL_NUMBER) + { + if (!parse_asn1_simple_object(&object, ASN1_INTEGER, + level, "crlNumber")) + { + return FALSE; + } + this->crlNumber = object; + } + } + break; + case CRL_OBJ_ALGORITHM: + { + int algo = parse_algorithmIdentifier(object, level, NULL); + if (this->algorithm != algo) + { + DBG1(" signature algorithms do not agree"); + return FALSE; + } + break; + } + case CRL_OBJ_SIGNATURE: + this->signature = object; + break; + default: + break; + } + objectID++; + } + return TRUE; +} + +/** + * enumerator filter callback for create_enumerator + */ +static bool filter(void *data, revoked_t *revoked, chunk_t *serial, void *p2, + time_t *date, void *p3, crl_reason_t *reason) +{ + if (serial) + { + *serial = revoked->serial; + } + if (date) + { + *date = revoked->date; + } + if (reason) + { + *reason = revoked->reason; + } + return TRUE; +} + +/** + * Implementation of crl_t.is_newer. + */ +static bool is_newer(private_x509_crl_t *this, crl_t *that) +{ + chunk_t that_crlNumber = that->get_serial(that); + bool new; + + /* compare crlNumbers if available - otherwise use thisUpdate */ + if (this->crlNumber.ptr != NULL && that_crlNumber.ptr != NULL) + { + new = chunk_compare(this->crlNumber, that_crlNumber) > 0; + DBG1(" crl #%#B is %s - existing crl #%#B %s", + &this->crlNumber, new ? "newer":"not newer", + &that_crlNumber, new ? "replaced":"retained"); + } + else + { + certificate_t *this_cert = &this->public.crl.certificate; + certificate_t *that_cert = &that->certificate; + + time_t this_update, that_update, now = time(NULL); + + this_cert->get_validity(this_cert, &now, &this_update, NULL); + that_cert->get_validity(that_cert, &now, &that_update, NULL); + new = this_update > that_update; + DBG1(" crl from %#T is %s - existing crl from %#T %s", + &this_update, FALSE, new ? "newer":"not newer", + &that_update, FALSE, new ? "replaced":"retained"); + } + return new; +} + +/** + * Implementation of crl_t.get_serial. + */ +static chunk_t get_serial(private_x509_crl_t *this) +{ + return this->crlNumber; +} + +/** + * Implementation of crl_t.get_authKeyIdentifier. + */ +static identification_t* get_authKeyIdentifier(private_x509_crl_t *this) +{ + return this->authKeyIdentifier; +} +/** + * Implementation of crl_t.create_enumerator. + */ +static enumerator_t* create_enumerator(private_x509_crl_t *this) +{ + return enumerator_create_filter( + this->revoked->create_enumerator(this->revoked), + (void*)filter, NULL, NULL); +} + +/** + * Implementation of certificate_t.get_type + */ +static certificate_type_t get_type(private_x509_crl_t *this) +{ + return CERT_X509_CRL; +} + +/** + * Implementation of certificate_t.get_subject + */ +static identification_t* get_subject(private_x509_crl_t *this) +{ + return this->issuer; +} + +/** + * Implementation of certificate_t.get_issuer + */ +static identification_t* get_issuer(private_x509_crl_t *this) +{ + return this->issuer; +} + +/** + * Implementation of certificate_t.has_subject. + */ +static id_match_t has_subject(private_x509_crl_t *this, identification_t *subject) +{ + return ID_MATCH_NONE; +} + +/** + * Implementation of certificate_t.has_issuer. + */ +static id_match_t has_issuer(private_x509_crl_t *this, identification_t *issuer) +{ + id_match_t match; + + if (issuer->get_type(issuer) == ID_PUBKEY_SHA1) + { + if (this->authKeyIdentifier) + { + match = issuer->matches(issuer, this->authKeyIdentifier); + } + else + { + match = ID_MATCH_NONE; + } + } + else + { + match = this->issuer->matches(this->issuer, issuer); + } + return match; +} + +/** + * Implementation of certificate_t.issued_by + */ +static bool issued_by(private_x509_crl_t *this, certificate_t *issuer, + bool sigcheck) +{ + public_key_t *key; + signature_scheme_t scheme; + bool valid; + x509_t *x509 = (x509_t*)issuer; + + /* check if issuer is an X.509 CA certificate */ + if (issuer->get_type(issuer) != CERT_X509) + { + return FALSE; + } + if (!(x509->get_flags(x509) & X509_CA)) + { + return FALSE; + } + + /* get the public key of the issuer */ + key = issuer->get_public_key(issuer); + + /* compare keyIdentifiers if available, otherwise use DNs */ + if (this->authKeyIdentifier && key) + { + identification_t *subjectKeyIdentifier = key->get_id(key, ID_PUBKEY_SHA1); + + if (!subjectKeyIdentifier->equals(subjectKeyIdentifier, + this->authKeyIdentifier)) + { + return FALSE; + } + } + else + { + if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer))) + { + return FALSE; + } + } + + if (!sigcheck) + { + return TRUE; + } + /* TODO: generic OID to scheme mapper? */ + switch (this->algorithm) + { + case OID_MD5_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_MD5; + break; + case OID_SHA1_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + break; + case OID_SHA256_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA256; + break; + case OID_SHA384_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA384; + break; + case OID_SHA512_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA512; + break; + default: + return FALSE; + } + if (key == NULL) + { + return FALSE; + } + valid = key->verify(key, scheme, this->tbsCertList, this->signature); + key->destroy(key); + return valid; +} + +/** + * Implementation of certificate_t.get_public_key + */ +static public_key_t* get_public_key(private_x509_crl_t *this) +{ + return NULL; +} + +/** + * Implementation of certificate_t.asdf + */ +static private_x509_crl_t* get_ref(private_x509_crl_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of certificate_t.get_validity. + */ +static bool get_validity(private_x509_crl_t *this, time_t *when, + time_t *not_before, time_t *not_after) +{ + time_t t; + + if (when) + { + t = *when; + } + else + { + t = time(NULL); + } + if (not_after) + { + *not_after = this->nextUpdate; + } + if (not_before) + { + *not_before = this->thisUpdate; + } + return (t <= this->nextUpdate); +} + +/** + * Implementation of certificate_t.get_encoding. + */ +static chunk_t get_encoding(private_x509_crl_t *this) +{ + return chunk_clone(this->certificateList); +} + +/** + * Implementation of certificate_t.equals. + */ +static bool equals(private_x509_crl_t *this, certificate_t *other) +{ + if ((certificate_t*)this == other) + { + return TRUE; + } + if (other->equals == (void*)equals) + { /* same implementation */ + return chunk_equals(this->signature, + ((private_x509_crl_t*)other)->signature); + } + /* TODO: compare against other implementations */ + return FALSE; +} + +/** + * Implementation of certificate_t.destroy + */ +static void destroy(private_x509_crl_t *this) +{ + if (ref_put(&this->ref)) + { + this->revoked->destroy_function(this->revoked, free); + DESTROY_IF(this->issuer); + DESTROY_IF(this->authKeyIdentifier); + free(this->certificateList.ptr); + free(this); + } +} + +/** + * load a X509 CRL from a chunk of date (ASN1 DER) + */ +static x509_crl_t *load(chunk_t chunk) +{ + private_x509_crl_t *this = malloc_thing(private_x509_crl_t); + + this->public.crl.is_newer = (bool (*)(crl_t*,crl_t*))is_newer; + this->public.crl.get_serial = (chunk_t (*)(crl_t*))get_serial; + this->public.crl.get_authKeyIdentifier = (identification_t* (*)(crl_t*))get_authKeyIdentifier; + this->public.crl.create_enumerator = (enumerator_t* (*)(crl_t*))create_enumerator; + this->public.crl.certificate.get_type = (certificate_type_t (*)(certificate_t *this))get_type; + this->public.crl.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_subject; + this->public.crl.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; + this->public.crl.certificate.has_subject = (id_match_t (*)(certificate_t*, identification_t *subject))has_subject; + this->public.crl.certificate.has_issuer = (id_match_t (*)(certificate_t*, identification_t *issuer))has_issuer; + this->public.crl.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by; + this->public.crl.certificate.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key; + this->public.crl.certificate.get_validity = (bool (*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity; + this->public.crl.certificate.get_encoding = (chunk_t (*)(certificate_t*))get_encoding; + this->public.crl.certificate.equals = (bool (*)(certificate_t*, certificate_t *other))equals; + this->public.crl.certificate.get_ref = (certificate_t* (*)(certificate_t *this))get_ref; + this->public.crl.certificate.destroy = (void (*)(certificate_t *this))destroy; + + this->certificateList = chunk; + this->tbsCertList = chunk_empty; + this->issuer = NULL; + this->crlNumber = chunk_empty; + this->revoked = linked_list_create(); + this->authKeyIdentifier = NULL; + this->authKeySerialNumber = chunk_empty; + this->ref = 1; + + if (!parse(this)) + { + destroy(this); + return NULL; + } + + return &this->public; +} + +typedef struct private_builder_t private_builder_t; +/** + * Builder implementation for certificate loading + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** loaded CRL */ + x509_crl_t *crl; +}; + +/** + * Implementation of builder_t.build + */ +static x509_crl_t *build(private_builder_t *this) +{ + x509_crl_t *crl = this->crl; + + free(this); + return crl; +} + +/** + * Implementation of builder_t.add + */ +static void add(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + + if (this->crl) + { + DBG1("ignoring surplus build part %N", builder_part_names, part); + return; + } + + switch (part) + { + case BUILD_BLOB_ASN1_DER: + { + va_start(args, part); + this->crl = load(va_arg(args, chunk_t)); + va_end(args); + break; + } + default: + DBG1("ignoring unsupported build part %N", builder_part_names, part); + break; + } +} + +/** + * Builder construction function + */ +builder_t *x509_crl_builder(certificate_type_t type) +{ + private_builder_t *this; + + if (type != CERT_X509_CRL) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->crl = NULL; + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; + this->public.build = (void*(*)(builder_t *this))build; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/x509/x509_crl.h b/src/libstrongswan/plugins/x509/x509_crl.h new file mode 100644 index 000000000..0d9e5cca4 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_crl.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup x509_crl x509_crl + * @{ @ingroup x509_p + */ + +#ifndef X509_CRL_H_ +#define X509_CRL_H_ + +typedef struct x509_crl_t x509_crl_t; + +#include <credentials/certificates/crl.h> + +/** + * Implementation of the X509 certification revocation list. + */ +struct x509_crl_t { + + /** + * Implements the crl_t interface + */ + crl_t crl; +}; + + +/** + * Create the building facility for x509 certificate revocation lists. + * + * @param type certificate type, CERT_X509_CRL only + * @return builder instance to build certificate + */ +builder_t *x509_crl_builder(certificate_type_t type); + +#endif /* X509_CRL_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_request.c b/src/libstrongswan/plugins/x509/x509_ocsp_request.c new file mode 100644 index 000000000..7e3230412 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_ocsp_request.c @@ -0,0 +1,603 @@ +/* + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2007 Andreas Steffen + * Hochschule fuer Technik Rapperswil + * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "x509_ocsp_request.h" + +#include <library.h> +#include <asn1/oid.h> +#include <asn1/asn1.h> +#include <utils/identification.h> +#include <utils/randomizer.h> +#include <utils/linked_list.h> +#include <debug.h> +#include <credentials/certificates/x509.h> + +#define NONCE_LEN 16 + +typedef struct private_x509_ocsp_request_t private_x509_ocsp_request_t; + +/** + * private data of x509_ocsp_request + */ +struct private_x509_ocsp_request_t { + + /** + * public functions + */ + x509_ocsp_request_t public; + + /** + * CA the candidates belong to + */ + x509_t *ca; + + /** + * Requestor name, subject of cert used if not set + */ + identification_t *requestor; + + /** + * Requestor certificate, included in request + */ + certificate_t *cert; + + /** + * Requestor private key to sign request + */ + private_key_t *key; + + /** + * list of certificates to check, x509_t + */ + linked_list_t *candidates; + + /** + * nonce used in request + */ + chunk_t nonce; + + /** + * encoded OCSP request + */ + chunk_t encoding; + + /** + * reference count + */ + refcount_t ref; +}; + +static u_char ASN1_nonce_oid_str[] = { + 0x06, 0x09, + 0x2B, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02 +}; + +static u_char ASN1_response_oid_str[] = { + 0x06, 0x09, + 0x2B, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04 +}; + +static u_char ASN1_response_content_str[] = { + 0x04, 0x0D, + 0x30, 0x0B, + 0x06, 0x09, + 0x2B, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 +}; + +static const chunk_t ASN1_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str); +static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str); +static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str); + +/** + * build requestorName + */ +static chunk_t build_requestorName(private_x509_ocsp_request_t *this) +{ + if (this->requestor || this->cert) + { /* use requestor name, fallback to his cert subject */ + if (!this->requestor) + { + this->requestor = this->cert->get_subject(this->cert); + this->requestor = this->requestor->clone(this->requestor); + } + return asn1_wrap(ASN1_CONTEXT_C_1, "m", + asn1_simple_object(ASN1_CONTEXT_C_4, + this->requestor->get_encoding(this->requestor))); + + } + return chunk_empty; +} + +/** + * build Request, not using singleRequestExtensions + */ +static chunk_t build_Request(private_x509_ocsp_request_t *this, + chunk_t issuerNameHash, chunk_t issuerKeyHash, + chunk_t serialNumber) +{ + return asn1_wrap(ASN1_SEQUENCE, "m", + asn1_wrap(ASN1_SEQUENCE, "cmmm", + asn1_algorithmIdentifier(OID_SHA1), + asn1_simple_object(ASN1_OCTET_STRING, issuerNameHash), + asn1_simple_object(ASN1_OCTET_STRING, issuerKeyHash), + asn1_simple_object(ASN1_INTEGER, serialNumber))); +} + +/** + * build requestList + */ +static chunk_t build_requestList(private_x509_ocsp_request_t *this) +{ + chunk_t issuerNameHash, issuerKeyHash; + identification_t *issuer; + x509_t *x509; + certificate_t *cert; + chunk_t list = chunk_empty; + public_key_t *public; + + cert = (certificate_t*)this->ca; + public = cert->get_public_key(cert); + if (public) + { + hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (hasher) + { + identification_t *keyid = public->get_id(public, ID_PUBKEY_SHA1); + if (keyid) + { + enumerator_t *enumerator; + + issuerKeyHash = keyid->get_encoding(keyid); + + issuer = cert->get_subject(cert); + hasher->allocate_hash(hasher, issuer->get_encoding(issuer), + &issuerNameHash); + hasher->destroy(hasher); + + enumerator = this->candidates->create_enumerator(this->candidates); + while (enumerator->enumerate(enumerator, &x509)) + { + chunk_t request, serialNumber; + + serialNumber = x509->get_serial(x509); + request = build_Request(this, issuerNameHash, issuerKeyHash, + serialNumber); + list = chunk_cat("mm", list, request); + } + enumerator->destroy(enumerator); + chunk_free(&issuerNameHash); + } + } + else + { + DBG1("creating OCSP request failed, SHA1 not supported"); + } + public->destroy(public); + } + else + { + DBG1("creating OCSP request failed, CA certificate has no public key"); + } + return asn1_wrap(ASN1_SEQUENCE, "m", list); +} + +/** + * build nonce extension + */ +static chunk_t build_nonce(private_x509_ocsp_request_t *this) +{ + randomizer_t *randomizer; + + randomizer = randomizer_create(); + randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_LEN, &this->nonce); + randomizer->destroy(randomizer); + + return asn1_wrap(ASN1_SEQUENCE, "cm", ASN1_nonce_oid, + asn1_simple_object(ASN1_OCTET_STRING, this->nonce)); +} + +/** + * build acceptableResponses extension + */ +static chunk_t build_acceptableResponses(private_x509_ocsp_request_t *this) +{ + return asn1_wrap(ASN1_SEQUENCE, "cc", + ASN1_response_oid, + ASN1_response_content); +} + +/** + * build requestExtensions + */ +static chunk_t build_requestExtensions(private_x509_ocsp_request_t *this) +{ + return asn1_wrap(ASN1_CONTEXT_C_2, "m", + asn1_wrap(ASN1_SEQUENCE, "mm", + build_nonce(this), + build_acceptableResponses(this))); +} + +/** + * build tbsRequest + */ +static chunk_t build_tbsRequest(private_x509_ocsp_request_t *this) +{ + return asn1_wrap(ASN1_SEQUENCE, "mmm", + build_requestorName(this), + build_requestList(this), + build_requestExtensions(this)); +} + +/** + * Build the optionalSignature + */ +static chunk_t build_optionalSignature(private_x509_ocsp_request_t *this, + chunk_t tbsRequest) +{ + int oid; + signature_scheme_t scheme; + chunk_t certs, signature; + + switch (this->key->get_type(this->key)) + { + /* TODO: use a generic mapping function */ + case KEY_RSA: + oid = OID_SHA1_WITH_RSA; + scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + break; + default: + DBG1("unable to sign OCSP request, %N signature not supported", + key_type_names, this->key->get_type(this->key)); + return chunk_empty; + } + + if (!this->key->sign(this->key, scheme, tbsRequest, &signature)) + { + DBG1("creating OCSP signature failed, skipped"); + return chunk_empty; + } + if (this->cert) + { + certs = asn1_wrap(ASN1_CONTEXT_C_0, "m", + asn1_wrap(ASN1_SEQUENCE, "m", + this->cert->get_encoding(this->cert))); + } + return asn1_wrap(ASN1_CONTEXT_C_0, "m", + asn1_wrap(ASN1_SEQUENCE, "cmm", + asn1_algorithmIdentifier(oid), + asn1_bitstring("m", signature), + certs)); +} + +/** + * Build the OCSPRequest data + * + */ +static chunk_t build_OCSPRequest(private_x509_ocsp_request_t *this) +{ + chunk_t tbsRequest, optionalSignature = chunk_empty; + + tbsRequest = build_tbsRequest(this); + if (this->key) + { + optionalSignature = build_optionalSignature(this, tbsRequest); + } + return asn1_wrap(ASN1_SEQUENCE, "mm", tbsRequest, optionalSignature); +} + + +/** + * Implementation of certificate_t.get_type + */ +static certificate_type_t get_type(private_x509_ocsp_request_t *this) +{ + return CERT_X509_OCSP_REQUEST; +} + +/** + * Implementation of certificate_t.get_subject + */ +static identification_t* get_subject(private_x509_ocsp_request_t *this) +{ + certificate_t *ca = (certificate_t*)this->ca; + + if (this->requestor) + { + return this->requestor; + } + if (this->cert) + { + return this->cert->get_subject(this->cert); + } + return ca->get_subject(ca); +} + +/** + * Implementation of certificate_t.get_issuer + */ +static identification_t* get_issuer(private_x509_ocsp_request_t *this) +{ + certificate_t *ca = (certificate_t*)this->ca; + + return ca->get_subject(ca); +} + +/** + * Implementation of certificate_t.has_subject. + */ +static id_match_t has_subject(private_x509_ocsp_request_t *this, + identification_t *subject) +{ + certificate_t *current; + enumerator_t *enumerator; + id_match_t match, best = ID_MATCH_NONE; + + enumerator = this->candidates->create_enumerator(this->candidates); + while (enumerator->enumerate(enumerator, ¤t)) + { + match = current->has_subject(current, subject); + if (match > best) + { + best = match; + } + } + enumerator->destroy(enumerator); + return best; +} + +/** + * Implementation of certificate_t.has_subject. + */ +static id_match_t has_issuer(private_x509_ocsp_request_t *this, + identification_t *issuer) +{ + certificate_t *ca = (certificate_t*)this->ca; + + return ca->has_subject(ca, issuer); +} + +/** + * Implementation of certificate_t.issued_by + */ +static bool issued_by(private_x509_ocsp_request_t *this, certificate_t *issuer, + bool sigcheck) +{ + DBG1("OCSP request validation not implemented!"); + return FALSE; +} + +/** + * Implementation of certificate_t.get_public_key + */ +static public_key_t* get_public_key(private_x509_ocsp_request_t *this) +{ + return NULL; +} + +/** + * Implementation of x509_cert_t.get_validity. + */ +static bool get_validity(private_x509_ocsp_request_t *this, time_t *when, + time_t *not_before, time_t *not_after) +{ + certificate_t *cert; + + if (this->cert) + { + cert = this->cert; + } + else + { + cert = (certificate_t*)this->ca; + } + return cert->get_validity(cert, when, not_before, not_after); +} + +/** + * Implementation of certificate_t.get_encoding. + */ +static chunk_t get_encoding(private_x509_ocsp_request_t *this) +{ + return chunk_clone(this->encoding); +} + +/** + * Implementation of certificate_t.equals. + */ +static bool equals(private_x509_ocsp_request_t *this, certificate_t *other) +{ + if (this == (private_x509_ocsp_request_t*)other) + { + return TRUE; + } + if (other->get_type(other) != CERT_X509_OCSP_REQUEST) + { + return FALSE; + } + /* check if we have the same X509 implementation */ + if (other->equals == (void*)equals) + { + return chunk_equals(this->encoding, + ((private_x509_ocsp_request_t*)other)->encoding); + } + /* TODO: compare against other implementation */ + return FALSE; +} + +/** + * Implementation of certificate_t.asdf + */ +static private_x509_ocsp_request_t* get_ref(private_x509_ocsp_request_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of x509_ocsp_request_t.destroy + */ +static void destroy(private_x509_ocsp_request_t *this) +{ + if (ref_put(&this->ref)) + { + DESTROY_IF((certificate_t*)this->ca); + DESTROY_IF(this->requestor); + DESTROY_IF(this->cert); + DESTROY_IF(this->key); + this->candidates->destroy_offset(this->candidates, offsetof(certificate_t, destroy)); + chunk_free(&this->nonce); + chunk_free(&this->encoding); + free(this); + } +} + +/** + * create an empty but initialized OCSP request + */ +static private_x509_ocsp_request_t *create_empty() +{ + private_x509_ocsp_request_t *this = malloc_thing(private_x509_ocsp_request_t); + + this->public.interface.interface.get_type = (certificate_type_t (*)(certificate_t *this))get_type; + this->public.interface.interface.get_subject = (identification_t* (*)(certificate_t *this))get_subject; + this->public.interface.interface.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; + this->public.interface.interface.has_subject = (id_match_t(*)(certificate_t*, identification_t *subject))has_subject; + this->public.interface.interface.has_issuer = (id_match_t(*)(certificate_t*, identification_t *issuer))has_issuer; + this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by; + this->public.interface.interface.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key; + this->public.interface.interface.get_validity = (bool(*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity; + this->public.interface.interface.get_encoding = (chunk_t(*)(certificate_t*))get_encoding; + this->public.interface.interface.equals = (bool(*)(certificate_t*, certificate_t *other))equals; + this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t *this))get_ref; + this->public.interface.interface.destroy = (void (*)(certificate_t *this))destroy; + + this->ca = NULL; + this->requestor = NULL; + this->cert = NULL; + this->key = NULL; + this->nonce = chunk_empty; + this->encoding = chunk_empty; + this->candidates = linked_list_create(); + this->ref = 1; + + return this; +} + +typedef struct private_builder_t private_builder_t; +/** + * Builder implementation for certificate loading + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** OCSP request to build */ + private_x509_ocsp_request_t *req; +}; + +/** + * Implementation of builder_t.build + */ +static x509_ocsp_request_t *build(private_builder_t *this) +{ + private_x509_ocsp_request_t *req; + + req = this->req; + free(this); + if (req->ca) + { + req->encoding = build_OCSPRequest(req); + return &req->public; + } + destroy(req); + return NULL; +} + +/** + * Implementation of builder_t.add + */ +static void add(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + certificate_t *cert; + + va_start(args, part); + switch (part) + { + case BUILD_CA_CERT: + cert = va_arg(args, certificate_t*); + if (cert->get_type(cert) == CERT_X509) + { + this->req->ca = (x509_t*)cert; + } + else + { + cert->destroy(cert); + } + break; + case BUILD_CERT: + cert = va_arg(args, certificate_t*); + if (cert->get_type(cert) == CERT_X509) + { + this->req->candidates->insert_last(this->req->candidates, cert); + } + else + { + cert->destroy(cert); + } + break; + case BUILD_SIGNING_CERT: + this->req->cert = va_arg(args, certificate_t*); + break; + case BUILD_SIGNING_KEY: + this->req->key = va_arg(args, private_key_t*); + break; + case BUILD_SUBJECT: + this->req->requestor = va_arg(args, identification_t*); + break; + default: + DBG1("ignoring unsupported build part %N", builder_part_names, part); + break; + } + va_end(args); +} + +/** + * Builder construction function + */ +builder_t *x509_ocsp_request_builder(certificate_type_t type) +{ + private_builder_t *this; + + if (type != CERT_X509_OCSP_REQUEST) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->req = create_empty(); + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; + this->public.build = (void*(*)(builder_t *this))build; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_request.h b/src/libstrongswan/plugins/x509/x509_ocsp_request.h new file mode 100644 index 000000000..0a4016f65 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_ocsp_request.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup x509_ocsp_request x509_ocsp_request + * @{ @ingroup x509_p + */ + +#ifndef X509_OCSP_REQUEST_H_ +#define X509_OCSP_REQUEST_H_ + +#include <credentials/certificates/ocsp_request.h> + +typedef struct x509_ocsp_request_t x509_ocsp_request_t; + +/** + * Implementation of ocsp_request_t using own ASN1 parser. + */ +struct x509_ocsp_request_t { + + /** + * Implements the ocsp_request_t interface + */ + ocsp_request_t interface; +}; + +/** + * Create the building facility for OCSP requests. + * + * The resulting builder accepts: + * BUILD_CA_CERT: CA of the checked certificates, exactly one + * BUILD_CERT: certificates to check with the request, at least one + * BUILD_SUBJECT: subject requesting check, optional + * BUILD_SIGNING_CERT: certificate to create requestor signature, optional + * BUILD_SIGNING_KEY: private key to create requestor signature, optional + * + * @param type certificate type, CERT_X509_OCSP_REQUEST only + * @return builder instance to build OCSP requests + */ +builder_t *x509_ocsp_request_builder(certificate_type_t type); + +#endif /* X509_OCSP_REQUEST_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_response.c b/src/libstrongswan/plugins/x509/x509_ocsp_response.c new file mode 100644 index 000000000..4ea2871d2 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_ocsp_response.c @@ -0,0 +1,928 @@ +/** + * Copyright (C) 2008 Martin Willi + * Copyright (C) 2007 Andreas Steffen + * Hochschule für Technik Rapperswil + * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "x509_ocsp_response.h" + +#include <time.h> + +#include <asn1/oid.h> +#include <asn1/asn1.h> +#include <utils/identification.h> +#include <utils/linked_list.h> +#include <debug.h> + +#include <library.h> +#include <credentials/certificates/x509.h> +#include <credentials/certificates/crl.h> + +typedef struct private_x509_ocsp_response_t private_x509_ocsp_response_t; + +/** + * Private data of a ocsp_t object. + */ +struct private_x509_ocsp_response_t { + /** + * Public interface for this ocsp object. + */ + x509_ocsp_response_t public; + + /** + * complete encoded OCSP response + */ + chunk_t data; + + /** + * data for signature verficiation + */ + chunk_t tbsResponseData; + + /** + * signature algorithm (OID) + */ + int signatureAlgorithm; + + /** + * signature value + */ + chunk_t signature; + + /** + * name or keyid of the responder + */ + identification_t *responderId; + + /** + * time of response production + */ + time_t producedAt; + + /** + * list of included certificates + */ + linked_list_t *certs; + + /** + * Linked list of OCSP responses, single_response_t + */ + linked_list_t *responses; + + /** + * Nonce required for ocsp request and response + */ + chunk_t nonce; + + /** + * reference counter + */ + refcount_t ref; +}; + +/** + * single response contained in OCSP response + */ +typedef struct { + /** hash algorithm OID to for the two hashes */ + int hashAlgorithm; + /** hash of issuer DN */ + chunk_t issuerNameHash; + /** issuerKeyID */ + chunk_t issuerKeyHash; + /** serial number of certificate */ + chunk_t serialNumber; + /** OCSP certificate status */ + cert_validation_t status; + /** time of revocation, if revoked */ + time_t revocationTime; + /** revocation reason, if revoked */ + crl_reason_t revocationReason; + /** creation of associated CRL */ + time_t thisUpdate; + /** creation of next CRL */ + time_t nextUpdate; +} single_response_t; + +/* our OCSP response version implementation */ +#define OCSP_BASIC_RESPONSE_VERSION 1 + +/* some OCSP specific prefabricated ASN.1 constants */ +static u_char ASN1_nonce_oid_str[] = { + 0x06, 0x09, + 0x2B, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02 +}; + +static u_char ASN1_response_oid_str[] = { + 0x06, 0x09, + 0x2B, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04 +}; + +static u_char ASN1_response_content_str[] = { + 0x04, 0x0D, + 0x30, 0x0B, + 0x06, 0x09, + 0x2B, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 +}; + +static const chunk_t ASN1_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str); +static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str); +static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str); + +/* asn.1 definitions for parsing */ + +static const asn1Object_t ocspResponseObjects[] = { + { 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */ + { 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */ + { 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */ + { 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */ + { 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */ +}; + +#define OCSP_RESPONSE_STATUS 1 +#define OCSP_RESPONSE_TYPE 4 +#define OCSP_RESPONSE 5 +#define OCSP_RESPONSE_ROOF 7 + +static const asn1Object_t basicResponseObjects[] = { + { 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ + { 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE | + ASN1_DEF }, /* 2 */ + { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ + { 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */ + { 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ + { 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */ + { 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ + { 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */ + { 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */ + { 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */ + { 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */ + { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */ + { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */ + { 5, "critical", ASN1_BOOLEAN, ASN1_BODY | + ASN1_DEF }, /* 16 */ + { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */ + { 4, "end loop", ASN1_EOC, ASN1_END }, /* 18 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ + { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */ + { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */ + { 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */ + { 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */ + { 3, "certificate", ASN1_SEQUENCE, ASN1_RAW }, /* 24 */ + { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 26 */ +}; + +#define BASIC_RESPONSE_TBS_DATA 1 +#define BASIC_RESPONSE_VERSION 3 +#define BASIC_RESPONSE_ID_BY_NAME 5 +#define BASIC_RESPONSE_ID_BY_KEY 8 +#define BASIC_RESPONSE_PRODUCED_AT 10 +#define BASIC_RESPONSE_RESPONSES 11 +#define BASIC_RESPONSE_EXT_ID 15 +#define BASIC_RESPONSE_CRITICAL 16 +#define BASIC_RESPONSE_EXT_VALUE 17 +#define BASIC_RESPONSE_ALGORITHM 20 +#define BASIC_RESPONSE_SIGNATURE 21 +#define BASIC_RESPONSE_CERTIFICATE 24 +#define BASIC_RESPONSE_ROOF 27 + +static const asn1Object_t responsesObjects[] = { + { 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */ +}; + +#define RESPONSES_SINGLE_RESPONSE 1 +#define RESPONSES_ROOF 3 + +static const asn1Object_t singleResponseObjects[] = { + { 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */ + { 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */ + { 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */ + { 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */ + { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */ + { 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ + { 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */ + { 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */ + { 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */ + { 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */ + { 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ + { 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */ + { 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */ + { 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ + { 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */ + { 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */ + { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */ + { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */ + { 4, "critical", ASN1_BOOLEAN, ASN1_BODY | + ASN1_DEF }, /* 24 */ + { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */ + { 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 27 */ +}; + +#define SINGLE_RESPONSE_ALGORITHM 2 +#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3 +#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4 +#define SINGLE_RESPONSE_SERIAL_NUMBER 5 +#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6 +#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8 +#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9 +#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11 +#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14 +#define SINGLE_RESPONSE_THIS_UPDATE 16 +#define SINGLE_RESPONSE_NEXT_UPDATE 18 +#define SINGLE_RESPONSE_EXT_ID 23 +#define SINGLE_RESPONSE_CRITICAL 24 +#define SINGLE_RESPONSE_EXT_VALUE 25 +#define SINGLE_RESPONSE_ROOF 28 + +/** + * Implementaiton of ocsp_response_t.get_status + */ +static cert_validation_t get_status(private_x509_ocsp_response_t *this, + x509_t *subject, x509_t *issuer, + time_t *revocation_time, + crl_reason_t *revocation_reason, + time_t *this_update, time_t *next_update) +{ + enumerator_t *enumerator; + single_response_t *response; + cert_validation_t status = VALIDATION_FAILED; + certificate_t *issuercert = &issuer->interface; + + enumerator = this->responses->create_enumerator(this->responses); + while (enumerator->enumerate(enumerator, &response)) + { + hasher_t *hasher; + identification_t *id; + chunk_t hash; + + /* check serial first, is cheaper */ + if (!chunk_equals(subject->get_serial(subject), response->serialNumber)) + { + continue; + } + /* check issuerKeyHash if available */ + if (response->issuerKeyHash.ptr) + { + public_key_t *public; + + public = issuercert->get_public_key(issuercert); + if (!public) + { + continue; + } + switch (response->hashAlgorithm) + { /* TODO: generic mapper function */ + case OID_SHA1: + id = public->get_id(public, ID_PUBKEY_SHA1); + break; + default: + public->destroy(public); + continue; + } + if (!chunk_equals(response->issuerKeyHash, id->get_encoding(id))) + { + public->destroy(public); + continue; + } + public->destroy(public); + } + /* check issuerNameHash, if available */ + else if (response->issuerNameHash.ptr) + { + hasher = lib->crypto->create_hasher(lib->crypto, + hasher_algorithm_from_oid(response->hashAlgorithm)); + if (!hasher) + { + continue; + } + id = issuercert->get_subject(issuercert); + hasher->allocate_hash(hasher, id->get_encoding(id), &hash); + hasher->destroy(hasher); + if (!chunk_equals(hash, response->issuerNameHash)) + { + continue; + } + } + else + { + continue; + } + /* got a match */ + status = response->status; + *revocation_time = response->revocationTime; + *revocation_reason = response->revocationReason; + *this_update = response->thisUpdate; + *next_update = response->nextUpdate; + + break; + } + enumerator->destroy(enumerator); + return status; +} + +/** + * Implementation of ocsp_response_t.create_cert_enumerator. + */ +static enumerator_t* create_cert_enumerator(private_x509_ocsp_response_t *this) +{ + return this->certs->create_enumerator(this->certs); +} + +/** + * parse a single OCSP response + */ +static bool parse_singleResponse(private_x509_ocsp_response_t *this, + chunk_t blob, int level0) +{ + u_int level; + asn1_ctx_t ctx; + chunk_t object; + int objectID = 0; + single_response_t *response; + + response = malloc_thing(single_response_t); + response->hashAlgorithm = OID_UNKNOWN; + response->issuerNameHash = chunk_empty; + response->issuerKeyHash = chunk_empty; + response->serialNumber = chunk_empty; + response->status = VALIDATION_FAILED; + response->revocationTime = 0; + response->revocationReason = CRL_UNSPECIFIED; + response->thisUpdate = 0; + response->nextUpdate = 0; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < SINGLE_RESPONSE_ROOF) + { + if (!extract_object(singleResponseObjects, &objectID, &object, &level, &ctx)) + { + free(response); + return FALSE; + } + switch (objectID) + { + case SINGLE_RESPONSE_ALGORITHM: + response->hashAlgorithm = parse_algorithmIdentifier(object, level+1, NULL); + break; + case SINGLE_RESPONSE_ISSUER_NAME_HASH: + response->issuerNameHash = object; + break; + case SINGLE_RESPONSE_ISSUER_KEY_HASH: + response->issuerKeyHash = object; + break; + case SINGLE_RESPONSE_SERIAL_NUMBER: + response->serialNumber = object; + break; + case SINGLE_RESPONSE_CERT_STATUS_GOOD: + response->status = VALIDATION_GOOD; + break; + case SINGLE_RESPONSE_CERT_STATUS_REVOKED: + response->status = VALIDATION_REVOKED; + break; + case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME: + response->revocationTime = asn1totime(&object, ASN1_GENERALIZEDTIME); + break; + case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON: + if (object.len == 1) + { + response->revocationReason = *object.ptr; + } + break; + case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN: + response->status = VALIDATION_FAILED; + break; + case SINGLE_RESPONSE_THIS_UPDATE: + response->thisUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME); + break; + case SINGLE_RESPONSE_NEXT_UPDATE: + response->nextUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME); + break; + } + objectID++; + } + this->responses->insert_last(this->responses, response); + return TRUE; +} + +/** + * parse all contained responses + */ +static bool parse_responses(private_x509_ocsp_response_t *this, + chunk_t blob, int level0) +{ + u_int level; + asn1_ctx_t ctx; + chunk_t object; + int objectID = 0; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < RESPONSES_ROOF) + { + if (!extract_object(responsesObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + switch (objectID) + { + case RESPONSES_SINGLE_RESPONSE: + if (!parse_singleResponse(this, object, level+1)) + { + return FALSE; + } + break; + default: + break; + } + objectID++; + } + return TRUE; +} + +/** + * parse a basicOCSPResponse + */ +static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this, + chunk_t blob, int level0) +{ + u_int level, version; + asn1_ctx_t ctx; + bool critical; + chunk_t object, responses = chunk_empty; + int objectID = 0; + int extn_oid = OID_UNKNOWN; + certificate_t *cert; + + asn1_init(&ctx, blob, level0, FALSE, FALSE); + while (objectID < BASIC_RESPONSE_ROOF) + { + if (!extract_object(basicResponseObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + switch (objectID) + { + case BASIC_RESPONSE_TBS_DATA: + this->tbsResponseData = object; + break; + case BASIC_RESPONSE_VERSION: + version = (object.len)? (1 + (u_int)*object.ptr) : 1; + if (version != OCSP_BASIC_RESPONSE_VERSION) + { + DBG1("OCSP ResponseData version %d not supported", version); + return FALSE; + } + break; + case BASIC_RESPONSE_ID_BY_NAME: + this->responderId = identification_create_from_encoding( + ID_DER_ASN1_DN, object); + DBG3(" %D", this->responderId); + break; + case BASIC_RESPONSE_ID_BY_KEY: + this->responderId = identification_create_from_encoding( + ID_PUBKEY_INFO_SHA1, object); + DBG3(" %D", this->responderId); + break; + case BASIC_RESPONSE_PRODUCED_AT: + this->producedAt = asn1totime(&object, ASN1_GENERALIZEDTIME); + break; + case BASIC_RESPONSE_RESPONSES: + responses = object; + break; + case BASIC_RESPONSE_EXT_ID: + extn_oid = known_oid(object); + break; + case BASIC_RESPONSE_CRITICAL: + critical = object.len && *object.ptr; + DBG3(" %s", critical ? "TRUE" : "FALSE"); + break; + case BASIC_RESPONSE_EXT_VALUE: + if (extn_oid == OID_NONCE) + { + this->nonce = object; + } + break; + case BASIC_RESPONSE_ALGORITHM: + this->signatureAlgorithm = parse_algorithmIdentifier( + object, level+1, NULL); + break; + case BASIC_RESPONSE_SIGNATURE: + this->signature = object; + break; + case BASIC_RESPONSE_CERTIFICATE: + { + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,CERT_X509, + BUILD_BLOB_ASN1_DER, chunk_clone(object), + BUILD_END); + if (cert) + { + this->certs->insert_last(this->certs, cert); + } + break; + } + } + objectID++; + } + if (!this->responderId) + { + this->responderId = identification_create_from_encoding(ID_ANY, chunk_empty); + } + return parse_responses(this, responses, level + 1); +} + +/** + * Parse OCSPResponse object + */ +static bool parse_OCSPResponse(private_x509_ocsp_response_t *this) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + int responseType = OID_UNKNOWN; + ocsp_status_t status; + + asn1_init(&ctx, this->data, 0, FALSE, FALSE); + while (objectID < OCSP_RESPONSE_ROOF) + { + if (!extract_object(ocspResponseObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + switch (objectID) + { + case OCSP_RESPONSE_STATUS: + status = (ocsp_status_t)*object.ptr; + switch (status) + { + case OCSP_SUCCESSFUL: + break; + default: + DBG1("OCSP response status: %N", + ocsp_status_names, status); + return FALSE; + } + break; + case OCSP_RESPONSE_TYPE: + responseType = known_oid(object); + break; + case OCSP_RESPONSE: + switch (responseType) + { + case OID_BASIC: + return parse_basicOCSPResponse(this, object, level+1); + default: + DBG1("OCSP response type %#B not supported", &object); + return FALSE; + } + break; + } + objectID++; + } + return FALSE; +} + +/** + * Implementation of certificate_t.get_type + */ +static certificate_type_t get_type(private_x509_ocsp_response_t *this) +{ + return CERT_X509_OCSP_RESPONSE; +} + +/** + * Implementation of certificate_t.get_issuer + */ +static identification_t* get_issuer(private_x509_ocsp_response_t *this) +{ + return this->responderId; +} + +/** + * Implementation of certificate_t.has_subject. + */ +static id_match_t has_issuer(private_x509_ocsp_response_t *this, + identification_t *issuer) +{ + return this->responderId->matches(this->responderId, issuer); +} + +/** + * Implementation of certificate_t.issued_by + */ +static bool issued_by(private_x509_ocsp_response_t *this, certificate_t *issuer, + bool sigcheck) +{ + public_key_t *key; + signature_scheme_t scheme; + bool valid; + x509_t *x509 = (x509_t*)issuer; + + if (issuer->get_type(issuer) != CERT_X509) + { + return FALSE; + } + if (this->responderId->get_type(this->responderId) == ID_DER_ASN1_DN) + { + if (!this->responderId->equals(this->responderId, + issuer->get_subject(issuer))) + { + return FALSE; + } + } + else + { + bool equal; + public_key_t *public = issuer->get_public_key(issuer); + + if (public == NULL) + { + return FALSE; + } + equal = this->responderId->equals(this->responderId, + public->get_id(public, ID_PUBKEY_SHA1)); + public->destroy(public); + if (!equal) + { + return FALSE; + } + } + if (!(x509->get_flags(x509) & X509_OCSP_SIGNER)) + { + return FALSE; + } + if (!sigcheck) + { + return TRUE; + } + /* TODO: generic OID to scheme mapper? */ + switch (this->signatureAlgorithm) + { + case OID_MD5_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_MD5; + break; + case OID_SHA1_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + break; + case OID_SHA256_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA256; + break; + case OID_SHA384_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA384; + break; + case OID_SHA512_WITH_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA512; + break; + default: + return FALSE; + } + key = issuer->get_public_key(issuer); + if (key == NULL) + { + return FALSE; + } + valid = key->verify(key, scheme, this->tbsResponseData, this->signature); + key->destroy(key); + return valid; +} + +/** + * Implementation of certificate_t.get_public_key + */ +static public_key_t* get_public_key(private_x509_ocsp_response_t *this) +{ + return NULL; +} + +/** + * Implementation of x509_cert_t.get_validity. + */ +static bool get_validity(private_x509_ocsp_response_t *this, time_t *when, + time_t *not_before, time_t *not_after) +{ + time_t t; + + if (when == NULL) + { + t = time(NULL); + } + else + { + t = *when; + } + if (not_before) + { + *not_before = this->producedAt; + } + if (not_after) + { + *not_after = ~0; + } + /* valid from produceAt up to infinity */ + if (t >= this->producedAt) + { + return TRUE; + } + return FALSE; +} + +/** + * Implementation of certificate_t.get_encoding. + */ +static chunk_t get_encoding(private_x509_ocsp_response_t *this) +{ + return chunk_clone(this->data); +} + +/** + * Implementation of certificate_t.equals. + */ +static bool equals(private_x509_ocsp_response_t *this, certificate_t *other) +{ + if (this == (private_x509_ocsp_response_t*)other) + { + return TRUE; + } + if (other->get_type(other) != CERT_X509_OCSP_RESPONSE) + { + return FALSE; + } + /* check if we have the same X509 implementation */ + if (other->equals == (void*)equals) + { + return chunk_equals(this->data, + ((private_x509_ocsp_response_t*)other)->data); + } + /* TODO: compare against other implementation */ + return FALSE; +} + +/** + * Implementation of certificate_t.get_ref + */ +static private_x509_ocsp_response_t* get_ref(private_x509_ocsp_response_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implements ocsp_t.destroy. + */ +static void destroy(private_x509_ocsp_response_t *this) +{ + if (ref_put(&this->ref)) + { + this->certs->destroy_offset(this->certs, offsetof(certificate_t, destroy)); + this->responses->destroy_function(this->responses, free); + DESTROY_IF(this->responderId); + free(this->data.ptr); + free(this); + } +} + +/** + * load an OCSP response + */ +static x509_ocsp_response_t *load(chunk_t data) +{ + private_x509_ocsp_response_t *this; + + this = malloc_thing(private_x509_ocsp_response_t); + + this->public.interface.certificate.get_type = (certificate_type_t (*)(certificate_t *this))get_type; + this->public.interface.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_issuer; + this->public.interface.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; + this->public.interface.certificate.has_subject = (id_match_t(*)(certificate_t*, identification_t *subject))has_issuer; + this->public.interface.certificate.has_issuer = (id_match_t(*)(certificate_t*, identification_t *issuer))has_issuer; + this->public.interface.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by; + this->public.interface.certificate.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key; + this->public.interface.certificate.get_validity = (bool(*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity; + this->public.interface.certificate.get_encoding = (chunk_t(*)(certificate_t*))get_encoding; + this->public.interface.certificate.equals = (bool(*)(certificate_t*, certificate_t *other))equals; + this->public.interface.certificate.get_ref = (certificate_t* (*)(certificate_t *this))get_ref; + this->public.interface.certificate.destroy = (void (*)(certificate_t *this))destroy; + this->public.interface.get_status = (cert_validation_t(*)(ocsp_response_t*, x509_t *subject, x509_t *issuer, time_t *revocation_time,crl_reason_t *revocation_reason,time_t *this_update, time_t *next_update))get_status; + this->public.interface.create_cert_enumerator = (enumerator_t*(*)(ocsp_response_t*))create_cert_enumerator; + + this->ref = 1; + this->data = data; + this->tbsResponseData = chunk_empty; + this->responderId = NULL; + this->producedAt = UNDEFINED_TIME; + this->responses = linked_list_create(); + this->nonce = chunk_empty; + this->signatureAlgorithm = OID_UNKNOWN; + this->signature = chunk_empty; + this->certs = linked_list_create(); + + if (!parse_OCSPResponse(this)) + { + destroy(this); + return NULL; + } + return &this->public; +} + + +typedef struct private_builder_t private_builder_t; +/** + * Builder implementation for certificate loading + */ +struct private_builder_t { + /** implements the builder interface */ + builder_t public; + /** loaded response */ + x509_ocsp_response_t *res; +}; + +/** + * Implementation of builder_t.build + */ +static x509_ocsp_response_t *build(private_builder_t *this) +{ + x509_ocsp_response_t *res = this->res; + + free(this); + return res; +} + +/** + * Implementation of builder_t.add + */ +static void add(private_builder_t *this, builder_part_t part, ...) +{ + va_list args; + + if (this->res) + { + DBG1("ignoring surplus build part %N", builder_part_names, part); + return; + } + + switch (part) + { + case BUILD_BLOB_ASN1_DER: + { + va_start(args, part); + this->res = load(va_arg(args, chunk_t)); + va_end(args); + break; + } + default: + DBG1("ignoring unsupported build part %N", builder_part_names, part); + break; + } +} + +/** + * Builder construction function + */ +builder_t *x509_ocsp_response_builder(certificate_type_t type) +{ + private_builder_t *this; + + if (type != CERT_X509_OCSP_RESPONSE) + { + return NULL; + } + + this = malloc_thing(private_builder_t); + + this->res = NULL; + this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; + this->public.build = (void*(*)(builder_t *this))build; + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_response.h b/src/libstrongswan/plugins/x509/x509_ocsp_response.h new file mode 100644 index 000000000..8b4c8328d --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_ocsp_response.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup x509_ocsp_response x509_ocsp_response + * @{ @ingroup x509_p + */ + +#ifndef X509_OCSP_RESPONSE_H_ +#define X509_OCSP_RESPONSE_H_ + +#include <credentials/certificates/ocsp_response.h> + +typedef struct x509_ocsp_response_t x509_ocsp_response_t; + +/** + * Implementation of ocsp_response_t using own ASN1 parser. + */ +struct x509_ocsp_response_t { + + /** + * Implements the ocsp_response_t interface + */ + ocsp_response_t interface; +}; + +/** + * Create the building facility for OCSP responses. + * + * @param type certificate type, CERT_X509_OCSP_RESPONSE only + * @return builder instance to build OCSP responses + */ +builder_t *x509_ocsp_response_builder(certificate_type_t type); + +#endif /* X509_OCSP_RESPONSE_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_plugin.c b/src/libstrongswan/plugins/x509/x509_plugin.c new file mode 100644 index 000000000..8ddef3bcd --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_plugin.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#include "x509_plugin.h" + +#include <library.h> +#include "x509_cert.h" +#include "x509_crl.h" +#include "x509_ocsp_request.h" +#include "x509_ocsp_response.h" + +typedef struct private_x509_plugin_t private_x509_plugin_t; + +/** + * private data of x509_plugin + */ +struct private_x509_plugin_t { + + /** + * public functions + */ + x509_plugin_t public; +}; + +/** + * Implementation of x509_plugin_t.x509troy + */ +static void destroy(private_x509_plugin_t *this) +{ + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)x509_cert_builder); + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)x509_crl_builder); + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)x509_ocsp_request_builder); + lib->creds->remove_builder(lib->creds, + (builder_constructor_t)x509_ocsp_response_builder); + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_x509_plugin_t *this = malloc_thing(private_x509_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509, + (builder_constructor_t)x509_cert_builder); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL, + (builder_constructor_t)x509_crl_builder); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST, + (builder_constructor_t)x509_ocsp_request_builder); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE, + (builder_constructor_t)x509_ocsp_response_builder); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/x509/x509_plugin.h b/src/libstrongswan/plugins/x509/x509_plugin.h new file mode 100644 index 000000000..9743a2367 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_plugin.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup x509_p x509 + * @ingroup plugins + * + * @defgroup x509_plugin x509_plugin + * @{ @ingroup x509_p + */ + +#ifndef X509_PLUGIN_H_ +#define X509_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct x509_plugin_t x509_plugin_t; + +/** + * Plugin implementing x509, CRL and OCSP certificates. + */ +struct x509_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Create a x509_plugin instance. + */ +plugin_t *plugin_create(); + +#endif /* X509_PLUGIN_H_ @}*/ |