diff options
Diffstat (limited to 'src/libstrongswan')
-rw-r--r-- | src/libstrongswan/Makefile.am | 1 | ||||
-rw-r--r-- | src/libstrongswan/chunk.c | 174 | ||||
-rw-r--r-- | src/libstrongswan/chunk.h | 70 | ||||
-rw-r--r-- | src/libstrongswan/crypto/hashers/hasher.h | 16 | ||||
-rw-r--r-- | src/libstrongswan/crypto/hashers/md5_hasher.c | 14 | ||||
-rw-r--r-- | src/libstrongswan/crypto/hashers/sha1_hasher.c | 17 | ||||
-rw-r--r-- | src/libstrongswan/crypto/hashers/sha2_hasher.c | 35 | ||||
-rw-r--r-- | src/libstrongswan/crypto/prfs/fips_prf.c | 258 | ||||
-rw-r--r-- | src/libstrongswan/crypto/prfs/fips_prf.h | 80 | ||||
-rw-r--r-- | src/libstrongswan/crypto/prfs/prf.c | 16 | ||||
-rw-r--r-- | src/libstrongswan/crypto/prfs/prf.h | 16 | ||||
-rw-r--r-- | src/libstrongswan/crypto/signers/hmac_signer.c | 50 | ||||
-rw-r--r-- | src/libstrongswan/crypto/signers/hmac_signer.h | 19 | ||||
-rw-r--r-- | src/libstrongswan/crypto/signers/signer.c | 17 | ||||
-rw-r--r-- | src/libstrongswan/crypto/signers/signer.h | 12 | ||||
-rw-r--r-- | src/libstrongswan/library.c | 13 | ||||
-rw-r--r-- | src/libstrongswan/library.h | 10 | ||||
-rw-r--r-- | src/libstrongswan/utils/leak_detective.c | 1 |
18 files changed, 721 insertions, 98 deletions
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 9f1dd4fbc..7fa20e4b2 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -12,6 +12,7 @@ asn1/pem.c asn1/pem.h \ asn1/ttodata.c asn1/ttodata.h \ crypto/rsa/rsa_private_key.c crypto/rsa/rsa_private_key.h \ crypto/rsa/rsa_public_key.h crypto/rsa/rsa_public_key.c \ +crypto/prfs/fips_prf.c crypto/prfs/fips_prf.h \ crypto/prfs/hmac_prf.c crypto/prfs/hmac_prf.h \ crypto/prfs/prf.c crypto/prfs/prf.h \ crypto/signers/hmac_signer.c crypto/signers/hmac_signer.h \ diff --git a/src/libstrongswan/chunk.c b/src/libstrongswan/chunk.c index 811a9757a..f2c8a3efb 100644 --- a/src/libstrongswan/chunk.c +++ b/src/libstrongswan/chunk.c @@ -35,13 +35,22 @@ chunk_t chunk_empty = { NULL, 0 }; /** * Described in header. */ -chunk_t chunk_clone(chunk_t chunk) +chunk_t chunk_create(u_char *ptr, size_t len) +{ + chunk_t chunk = {ptr, len}; + return chunk; +} + +/** + * Described in header. + */ +chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk) { chunk_t clone = chunk_empty; if (chunk.ptr && chunk.len > 0) { - clone.ptr = malloc(chunk.len); + clone.ptr = ptr; clone.len = chunk.len; memcpy(clone.ptr, chunk.ptr, chunk.len); } @@ -52,45 +61,66 @@ chunk_t chunk_clone(chunk_t chunk) /** * Decribed in header. */ -chunk_t chunk_cat(const char* mode, ...) +size_t chunk_length(const char* mode, ...) { - chunk_t construct; va_list chunks; - u_char *pos; - int i; - int count = strlen(mode); - - /* sum up lengths of individual chunks */ + size_t length = 0; + va_start(chunks, mode); - construct.len = 0; - for (i = 0; i < count; i++) + while (TRUE) { - chunk_t ch = va_arg(chunks, chunk_t); - construct.len += ch.len; + switch (*mode++) + { + case 'm': + case 'c': + { + chunk_t ch = va_arg(chunks, chunk_t); + length += ch.len; + continue; + } + default: + break; + } + break; } va_end(chunks); + return length; +} - /* allocate needed memory for construct */ - construct.ptr = malloc(construct.len); - pos = construct.ptr; - - /* copy or move the chunks */ +/** + * Decribed in header. + */ +chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...) +{ + va_list chunks; + chunk_t construct = chunk_create(ptr, 0); + va_start(chunks, mode); - for (i = 0; i < count; i++) + while (TRUE) { - chunk_t ch = va_arg(chunks, chunk_t); + bool free_chunk = FALSE; switch (*mode++) { case 'm': - memcpy(pos, ch.ptr, ch.len); - pos += ch.len; - free(ch.ptr); - break; + { + free_chunk = TRUE; + } case 'c': + { + chunk_t ch = va_arg(chunks, chunk_t); + memcpy(ptr, ch.ptr, ch.len); + ptr += ch.len; + construct.len += ch.len; + if (free_chunk) + { + free(ch.ptr); + } + continue; + } default: - memcpy(pos, ch.ptr, ch.len); - pos += ch.len; + break; } + break; } va_end(chunks); @@ -98,6 +128,85 @@ chunk_t chunk_cat(const char* mode, ...) } /** + * Decribed in header. + */ +void chunk_split(chunk_t chunk, const char *mode, ...) +{ + va_list chunks; + size_t len; + chunk_t *ch; + + va_start(chunks, mode); + while (TRUE) + { + if (*mode == '\0') + { + break; + } + len = va_arg(chunks, size_t); + ch = va_arg(chunks, chunk_t*); + /* a null chunk means skip len bytes */ + if (ch == NULL) + { + chunk = chunk_skip(chunk, len); + continue; + } + switch (*mode++) + { + case 'm': + { + ch->len = min(chunk.len, len); + if (ch->len) + { + ch->ptr = chunk.ptr; + } + else + { + ch->ptr = NULL; + } + chunk = chunk_skip(chunk, ch->len); + continue; + } + case 'a': + { + ch->len = min(chunk.len, len); + if (ch->len) + { + ch->ptr = malloc(ch->len); + memcpy(ch->ptr, chunk.ptr, ch->len); + } + else + { + ch->ptr = NULL; + } + chunk = chunk_skip(chunk, ch->len); + continue; + } + case 'c': + { + ch->len = min(ch->len, chunk.len); + ch->len = min(ch->len, len); + if (ch->len) + { + memcpy(ch->ptr, chunk.ptr, ch->len); + } + else + { + ch->ptr = NULL; + } + chunk = chunk_skip(chunk, ch->len); + continue; + } + default: + break; + } + break; + } + va_end(chunks); +} + + +/** * Described in header. */ void chunk_free(chunk_t *chunk) @@ -110,12 +219,15 @@ void chunk_free(chunk_t *chunk) /** * Described in header. */ -chunk_t chunk_alloc(size_t bytes) +chunk_t chunk_skip(chunk_t chunk, size_t bytes) { - chunk_t new_chunk; - new_chunk.ptr = malloc(bytes); - new_chunk.len = bytes; - return new_chunk; + if (chunk.len > bytes) + { + chunk.ptr += bytes; + chunk.len -= bytes; + return chunk; + } + return chunk_empty; } /** diff --git a/src/libstrongswan/chunk.h b/src/libstrongswan/chunk.h index 93c4b512f..d3477eba8 100644 --- a/src/libstrongswan/chunk.h +++ b/src/libstrongswan/chunk.h @@ -47,21 +47,36 @@ struct chunk_t { extern chunk_t chunk_empty; /** - * Initialize a chunk to point to a static(!) buffer + * Create a new chunk pointing to "ptr" with length "len" */ -#define chunk_from_buf(str) { str, sizeof(str) } +chunk_t chunk_create(u_char *ptr, size_t len); + +/** + * Create a clone of a chunk pointing to "ptr" + */ +chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk); /** - * Clone chunk contents in a newly allocated chunk + * Calculate length of multiple chunks */ -chunk_t chunk_clone(chunk_t chunk); +size_t chunk_length(const char *mode, ...); /** - * Allocate a chunk from concatenation of other chunks. - * mode is a string 'm' and 'c, 'm' means move chunk, - * 'c' means copy chunk. + * Concatenate chunks into a chunk pointing to "ptr", + * "mode" is a string of "c" (copy) and "m" (move), which says + * how to handle to chunks in "..." */ -chunk_t chunk_cat(const char* mode, ...); +chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...); + +/** + * Split up a chunk into parts, "mode" is a string of "a" (alloc), + * "c" (copy) and "m" (move). Each letter say for the corresponding chunk if + * it should get allocated on heap, copied into existing chunk, or the chunk + * should point into "chunk". The length of each part is an argument before + * each target chunk. E.g.: + * chunk_split(chunk, "mcac", 3, &a, 7, &b, 5, &c, d.len, &d); + */ +void chunk_split(chunk_t chunk, const char *mode, ...); /** * Free contents of a chunk @@ -69,9 +84,44 @@ chunk_t chunk_cat(const char* mode, ...); void chunk_free(chunk_t *chunk); /** - * Allocate a chunk + * Initialize a chunk to point to buffer inspectable by sizeof() + */ +#define chunk_from_buf(str) { str, sizeof(str) } + +/** + * Allocate a chunk on the heap + */ +#define chunk_alloc(bytes) chunk_create(malloc(bytes), bytes) + +/** + * Allocate a chunk on the stack + */ +#define chunk_alloca(bytes) chunk_create(alloca(bytes), bytes) + +/** + * Clone a chunk on heap + */ +#define chunk_clone(chunk) chunk_create_clone(malloc(chunk.len), chunk) + +/** + * Clone a chunk on stack + */ +#define chunk_clonea(chunk) chunk_create_clone(alloca(chunk.len), chunk) + +/** + * Concatenate chunks into a chunk on heap + */ +#define chunk_cat(mode, ...) chunk_create_cat(malloc(chunk_length(mode, __VA_ARGS__)), mode, __VA_ARGS__) + +/** + * Concatenate chunks into a chunk on stack + */ +#define chunk_cata(mode, ...) chunk_create_cat(alloca(chunk_length(mode, __VA_ARGS__)), mode, __VA_ARGS__) + +/** + * Skip n bytes in chunk (forward pointer, shorten length) */ -chunk_t chunk_alloc(size_t bytes); +chunk_t chunk_skip(chunk_t chunk, size_t bytes); /** * Compare two chunks for equality, diff --git a/src/libstrongswan/crypto/hashers/hasher.h b/src/libstrongswan/crypto/hashers/hasher.h index a1b5f5805..9b226b2a1 100644 --- a/src/libstrongswan/crypto/hashers/hasher.h +++ b/src/libstrongswan/crypto/hashers/hasher.h @@ -123,9 +123,23 @@ struct hasher_t { void (*reset) (hasher_t *this); /** + * @brief Get the state of the hasher. + * + * A hasher stores internal state information. This state may be + * manipulated to include a "seed" into the hashing operation. It used by + * some exotic protocols (such as AKA). + * The data pointed by chunk may be manipulated, but not replaced nor freed. + * This is more a hack than a feature. The hasher's state may be byte + * order dependant; use with care. + * + * @param this calling object + */ + chunk_t (*get_state) (hasher_t *this); + + /** * @brief Destroys a hasher object. * - * @param this calling object + * @param this calling object */ void (*destroy) (hasher_t *this); }; diff --git a/src/libstrongswan/crypto/hashers/md5_hasher.c b/src/libstrongswan/crypto/hashers/md5_hasher.c index fa61cac5b..5330676d4 100644 --- a/src/libstrongswan/crypto/hashers/md5_hasher.c +++ b/src/libstrongswan/crypto/hashers/md5_hasher.c @@ -364,6 +364,19 @@ static void reset(private_md5_hasher_t *this) } /** + * Implementation of hasher_t.get_state + */ +static chunk_t get_state(private_md5_hasher_t *this) +{ + chunk_t chunk; + + chunk.ptr = (u_char*)&this->state[0]; + chunk.len = sizeof(this->state); + + return chunk; +} + +/** * Implementation of hasher_t.destroy. */ static void destroy(private_md5_hasher_t *this) @@ -382,6 +395,7 @@ md5_hasher_t *md5_hasher_create(void) 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.get_state = (chunk_t (*) (hasher_t*))get_state; this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy; /* initialize */ diff --git a/src/libstrongswan/crypto/hashers/sha1_hasher.c b/src/libstrongswan/crypto/hashers/sha1_hasher.c index cca336694..6a86937ae 100644 --- a/src/libstrongswan/crypto/hashers/sha1_hasher.c +++ b/src/libstrongswan/crypto/hashers/sha1_hasher.c @@ -223,7 +223,7 @@ static size_t get_hash_size(private_sha1_hasher_t *this) { return HASH_SIZE_SHA1; } - + /** * Implementation of hasher_t.reset. */ @@ -237,6 +237,20 @@ static void reset(private_sha1_hasher_t *this) this->count[0] = 0; this->count[1] = 0; } + +/** + * Implementation of hasher_t.get_state + */ +static chunk_t get_state(private_sha1_hasher_t *this) +{ + chunk_t chunk; + + chunk.ptr = (u_char*)&this->state[0]; + chunk.len = sizeof(this->state); + + return chunk; +} + /** * Implementation of hasher_t.destroy. */ @@ -256,6 +270,7 @@ sha1_hasher_t *sha1_hasher_create(void) 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.get_state = (chunk_t (*) (hasher_t*))get_state; this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy; /* initialize */ diff --git a/src/libstrongswan/crypto/hashers/sha2_hasher.c b/src/libstrongswan/crypto/hashers/sha2_hasher.c index f6fd0404e..b68972cec 100644 --- a/src/libstrongswan/crypto/hashers/sha2_hasher.c +++ b/src/libstrongswan/crypto/hashers/sha2_hasher.c @@ -587,6 +587,38 @@ static void reset512(private_sha512_hasher_t *ctx) } /** + * Implementation of hasher_t.get_state for SHA256 + */ +static chunk_t get_state256(private_sha256_hasher_t *ctx) +{ + chunk_t chunk; + chunk.ptr = (u_char*)&ctx->sha_H[0]; + chunk.len = HASH_SIZE_SHA256; + return chunk; +} + +/** + * Implementation of hasher_t.get_state for SHA384 + */ +static chunk_t get_state384(private_sha512_hasher_t *ctx) +{ + chunk_t chunk; + chunk.ptr = (u_char*)&ctx->sha_H[0]; + chunk.len = HASH_SIZE_SHA384; + return chunk; +} +/** + * Implementation of hasher_t.get_state for SHA512 + */ +static chunk_t get_state512(private_sha512_hasher_t *ctx) +{ + chunk_t chunk; + chunk.ptr = (u_char*)&ctx->sha_H[0]; + chunk.len = HASH_SIZE_SHA512; + return chunk; +} + +/** * Implementation of hasher_t.destroy. */ static void destroy(sha2_hasher_t *this) @@ -606,6 +638,7 @@ sha2_hasher_t *sha2_hasher_create(hash_algorithm_t 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_state = (chunk_t(*)(hasher_t*))get_state256; 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; @@ -614,6 +647,7 @@ sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm) /* 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_state = (chunk_t(*)(hasher_t*))get_state384; 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; @@ -621,6 +655,7 @@ sha2_hasher_t *sha2_hasher_create(hash_algorithm_t algorithm) 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_state = (chunk_t(*)(hasher_t*))get_state512; 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; diff --git a/src/libstrongswan/crypto/prfs/fips_prf.c b/src/libstrongswan/crypto/prfs/fips_prf.c new file mode 100644 index 000000000..320e56dfc --- /dev/null +++ b/src/libstrongswan/crypto/prfs/fips_prf.c @@ -0,0 +1,258 @@ +/** + * @file fips_prf.c + * + * @brief Implementation for fips_prf_t. + * + */ + +/* + * 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. + */ + +#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; + + /** + * G function, either SHA1 or DES + */ + void (*g)(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; + + for(i = length - 1; i >= 0; i--) + { + u_int32_t tmp; + int c = 0; + + 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 *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(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, one, xkey); + add_mod(this->b, xkey, &w[i * this->b], 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(u_int8_t t[], chunk_t c, u_int8_t res[]) +{ + hasher_t *hasher; + u_int8_t buf[64]; + chunk_t state_chunk; + u_int32_t *state, *iv, *hash; + + 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); + } + + /* our SHA1 hasher's state is 32-Bit integers in host order. We must + * convert them */ + hasher = hasher_create(HASH_SHA1); + state_chunk = hasher->get_state(hasher); + state = (u_int32_t*)state_chunk.ptr; + iv = (u_int32_t*)t; + hash = (u_int32_t*)res; + state[0] = htonl(iv[0]); + state[1] = htonl(iv[1]); + state[2] = htonl(iv[2]); + state[3] = htonl(iv[3]); + hasher->get_hash(hasher, c, NULL); + hash[0] = htonl(state[0]); + hash[1] = htonl(state[1]); + hash[2] = htonl(state[2]); + hash[3] = htonl(state[3]); + hash[4] = htonl(state[4]); + hasher->destroy(hasher); +} + +/** + * Implementation of prf_t.destroy. + */ +static void destroy(private_fips_prf_t *this) +{ + free(this->key); + free(this); +} + +/* + * Described in header. + */ +fips_prf_t *fips_prf_create(size_t b, void(*g)(u_int8_t[],chunk_t,u_int8_t[])) +{ + 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; + + this->g = g; + this->b = b; + this->key = malloc(b); + + return &(this->public); +} diff --git a/src/libstrongswan/crypto/prfs/fips_prf.h b/src/libstrongswan/crypto/prfs/fips_prf.h new file mode 100644 index 000000000..283ee1f61 --- /dev/null +++ b/src/libstrongswan/crypto/prfs/fips_prf.h @@ -0,0 +1,80 @@ +/** + * @file fips_prf.h + * + * @brief Interface of fips_prf_t. + * + */ + +/* + * 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. + */ + +#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> + +/** + * @brief 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. + * + * @b Constructors: + * - fips_prf_create() + * - prf_create() using one of the FIPS algorithms + * + * @ingroup prfs + */ +struct fips_prf_t { + + /** + * Generic prf_t interface for this fips_prf_t class. + */ + prf_t prf_interface; +}; + +/** + * @brief 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. + * + * @param b size of b (in bytes, not bits) + * @param g G() function to use (e.g. g_sha1) + * @return + * - fips_prf_t object + * - NULL if b invalid not supported + * + * @ingroup prfs + */ +fips_prf_t *fips_prf_create(size_t b, void(*g)(u_int8_t[],chunk_t,u_int8_t[])); + +/** + * @brief Implementation of the G() function based on SHA1. + * + * @param t initialization vector for SHA1 hasher, 20 bytes long + * @param c value to hash, not longer than 512 bit + * @param res result of G(), requries 20 bytes + */ +void g_sha1(u_int8_t t[], chunk_t c, u_int8_t res[]); + +#endif /* FIPS_PRF_H_ */ diff --git a/src/libstrongswan/crypto/prfs/prf.c b/src/libstrongswan/crypto/prfs/prf.c index aa5d1d2b7..f3b05ea00 100644 --- a/src/libstrongswan/crypto/prfs/prf.c +++ b/src/libstrongswan/crypto/prfs/prf.c @@ -26,10 +26,13 @@ #include <crypto/hashers/hasher.h> #include <crypto/prfs/hmac_prf.h> +#include <crypto/prfs/fips_prf.h> -ENUM_BEGIN(pseudo_random_function_names, PRF_UNDEFINED, PRF_UNDEFINED, - "PRF_UNDEFINED"); -ENUM_NEXT(pseudo_random_function_names, PRF_HMAC_MD5, PRF_AES128_CBC, PRF_UNDEFINED, +ENUM_BEGIN(pseudo_random_function_names, PRF_UNDEFINED, PRF_FIPS_DES, + "PRF_UNDEFINED", + "PRF_FIPS_SHA1_160", + "PRF_FIPS_DES"); +ENUM_NEXT(pseudo_random_function_names, PRF_HMAC_MD5, PRF_AES128_CBC, PRF_FIPS_DES, "PRF_HMAC_MD5", "PRF_HMAC_SHA1", "PRF_HMAC_TIGER", @@ -44,13 +47,12 @@ prf_t *prf_create(pseudo_random_function_t pseudo_random_function) switch (pseudo_random_function) { case PRF_HMAC_SHA1: - { return (prf_t*)hmac_prf_create(HASH_SHA1); - } case PRF_HMAC_MD5: - { return (prf_t*)hmac_prf_create(HASH_MD5); - } + case PRF_FIPS_SHA1_160: + return (prf_t*)fips_prf_create(20, g_sha1); + case PRF_FIPS_DES: case PRF_HMAC_TIGER: case PRF_AES128_CBC: default: diff --git a/src/libstrongswan/crypto/prfs/prf.h b/src/libstrongswan/crypto/prfs/prf.h index 897cf906b..7a4501866 100644 --- a/src/libstrongswan/crypto/prfs/prf.h +++ b/src/libstrongswan/crypto/prfs/prf.h @@ -31,11 +31,10 @@ typedef struct prf_t prf_t; /** * @brief Pseudo random function, as in IKEv2 RFC 3.3.2. - * - * Currently only the following algorithms are implemented: - * - PRF_HMAC_MD5 - * - PRF_HMAC_SHA1 - * + * + * PRF algorithms not defined in IKEv2 are allocated in "private use" + * space. + * * @ingroup prfs */ enum pseudo_random_function_t { @@ -46,6 +45,10 @@ enum pseudo_random_function_t { PRF_HMAC_SHA1 = 2, PRF_HMAC_TIGER = 3, PRF_AES128_CBC = 4, + /** Implemented via fips_prf_t, other output sizes would be possible */ + PRF_FIPS_SHA1_160 = 1025, + /** Could be implemented via fips_prf_t, uses fixed output size of 160bit */ + PRF_FIPS_DES = 1026, }; /** @@ -93,6 +96,9 @@ struct prf_t { /** * @brief Get the key size of this prf_t object. + * + * This is a suggestion only, all implemented PRFs accept variable key + * length. * * @param this calling object * @return key size in bytes diff --git a/src/libstrongswan/crypto/signers/hmac_signer.c b/src/libstrongswan/crypto/signers/hmac_signer.c index c4a6173b5..76e1ce50e 100644 --- a/src/libstrongswan/crypto/signers/hmac_signer.c +++ b/src/libstrongswan/crypto/signers/hmac_signer.c @@ -27,11 +27,6 @@ #include <crypto/prfs/hmac_prf.h> -/** - * This class represents a hmac signer with 12 byte (96 bit) output. - */ -#define BLOCK_SIZE 12 - typedef struct private_hmac_signer_t private_hmac_signer_t; /** @@ -43,10 +38,15 @@ struct private_hmac_signer_t { */ hmac_signer_t public; - /* + /** * Assigned hmac function. */ prf_t *hmac_prf; + + /** + * Block size (truncation of HMAC Hash) + */ + size_t block_size; }; /** @@ -56,10 +56,10 @@ static void get_signature (private_hmac_signer_t *this, chunk_t data, u_int8_t * { u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)]; - this->hmac_prf->get_bytes(this->hmac_prf,data,full_mac); + this->hmac_prf->get_bytes(this->hmac_prf, data, full_mac); - /* copy mac aka signature :-) */ - memcpy(buffer,full_mac,BLOCK_SIZE); + /* copy MAC depending on truncation */ + memcpy(buffer, full_mac, this->block_size); } /** @@ -72,11 +72,11 @@ static void allocate_signature (private_hmac_signer_t *this, chunk_t data, chunk this->hmac_prf->get_bytes(this->hmac_prf,data,full_mac); - signature.ptr = malloc(BLOCK_SIZE); - signature.len = BLOCK_SIZE; + signature.ptr = malloc(this->block_size); + signature.len = this->block_size; /* copy signature */ - memcpy(signature.ptr,full_mac,BLOCK_SIZE); + memcpy(signature.ptr, full_mac, this->block_size); *chunk = signature; } @@ -84,19 +84,19 @@ static void allocate_signature (private_hmac_signer_t *this, chunk_t data, chunk /** * Implementation of signer_t.verify_signature. */ -static bool verify_signature (private_hmac_signer_t *this, chunk_t data, chunk_t signature) +static bool verify_signature(private_hmac_signer_t *this, chunk_t data, chunk_t signature) { u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)]; - this->hmac_prf->get_bytes(this->hmac_prf,data,full_mac); + this->hmac_prf->get_bytes(this->hmac_prf, data, full_mac); - if (signature.len != BLOCK_SIZE) + if (signature.len != this->block_size) { return FALSE; } /* compare mac aka signature :-) */ - if (memcmp(signature.ptr,full_mac,BLOCK_SIZE) == 0) + if (memcmp(signature.ptr, full_mac, this->block_size) == 0) { return TRUE; } @@ -109,7 +109,7 @@ static bool verify_signature (private_hmac_signer_t *this, chunk_t data, chunk_t /** * Implementation of signer_t.get_key_size. */ -static size_t get_key_size (private_hmac_signer_t *this) +static size_t get_key_size(private_hmac_signer_t *this) { /* for HMAC signer, IKEv2 uses block size as key size */ return this->hmac_prf->get_block_size(this->hmac_prf); @@ -118,17 +118,17 @@ static size_t get_key_size (private_hmac_signer_t *this) /** * Implementation of signer_t.get_block_size. */ -static size_t get_block_size (private_hmac_signer_t *this) +static size_t get_block_size(private_hmac_signer_t *this) { - return BLOCK_SIZE; + return this->block_size; } /** * Implementation of signer_t.set_key. */ -static void set_key (private_hmac_signer_t *this, chunk_t key) +static void set_key(private_hmac_signer_t *this, chunk_t key) { - this->hmac_prf->set_key(this->hmac_prf,key); + this->hmac_prf->set_key(this->hmac_prf, key); } /** @@ -144,12 +144,12 @@ static status_t destroy(private_hmac_signer_t *this) /* * Described in header */ -hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm) +hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm, size_t block_size) { + size_t hmac_block_size; private_hmac_signer_t *this = malloc_thing(private_hmac_signer_t); this->hmac_prf = (prf_t *) hmac_prf_create(hash_algoritm); - if (this->hmac_prf == NULL) { /* algorithm not supported */ @@ -157,6 +157,10 @@ hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm) return NULL; } + /* prevent invalid truncation */ + hmac_block_size = this->hmac_prf->get_block_size(this->hmac_prf); + this->block_size = min(block_size, hmac_block_size); + /* 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; diff --git a/src/libstrongswan/crypto/signers/hmac_signer.h b/src/libstrongswan/crypto/signers/hmac_signer.h index 5b9549086..2449069bd 100644 --- a/src/libstrongswan/crypto/signers/hmac_signer.h +++ b/src/libstrongswan/crypto/signers/hmac_signer.h @@ -30,9 +30,11 @@ typedef struct hmac_signer_t hmac_signer_t; #include <crypto/hashers/hasher.h> /** - * @brief Implementation of signer_t interface using the - * HMAC algorithm in combination with either MD5 or SHA1. - * + * @brief Implementation of signer_t interface using HMAC. + * + * HMAC uses a standard hash function implemented in a hasher_t to build + * a MAC. + * * @ingroup signers */ struct hmac_signer_t { @@ -45,15 +47,22 @@ struct hmac_signer_t { /** * @brief 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 hash_algoritm Hash algorithm to use with signer + * @param block_size Size of resulting signature (truncated to block_size) * @return * - hmac_signer_t * - NULL if hash algorithm not supported * * @ingroup signers */ -hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm); +hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm, + size_t block_size); #endif /*HMAC_SIGNER_H_*/ diff --git a/src/libstrongswan/crypto/signers/signer.c b/src/libstrongswan/crypto/signers/signer.c index d6037c545..250d64b71 100644 --- a/src/libstrongswan/crypto/signers/signer.c +++ b/src/libstrongswan/crypto/signers/signer.c @@ -25,9 +25,10 @@ #include <crypto/signers/hmac_signer.h> -ENUM_BEGIN(integrity_algorithm_names, AUTH_UNDEFINED, AUTH_UNDEFINED, - "UNDEFINED"); -ENUM_NEXT(integrity_algorithm_names, AUTH_HMAC_MD5_96, AUTH_AES_XCBC_96, AUTH_UNDEFINED, +ENUM_BEGIN(integrity_algorithm_names, AUTH_UNDEFINED, AUTH_HMAC_SHA1_128, + "UNDEFINED", + "AUTH_HMAC_SHA1_128"); +ENUM_NEXT(integrity_algorithm_names, AUTH_HMAC_MD5_96, AUTH_AES_XCBC_96, AUTH_HMAC_SHA1_128, "HMAC_MD5_96", "HMAC_SHA1_96", "DES_MAC", @@ -43,13 +44,11 @@ signer_t *signer_create(integrity_algorithm_t integrity_algorithm) switch(integrity_algorithm) { case AUTH_HMAC_SHA1_96: - { - return ((signer_t *) hmac_signer_create(HASH_SHA1)); - } + return (signer_t *)hmac_signer_create(HASH_SHA1, 12); + case AUTH_HMAC_SHA1_128: + return (signer_t *)hmac_signer_create(HASH_SHA1, 16); case AUTH_HMAC_MD5_96: - { - return ((signer_t *) hmac_signer_create(HASH_MD5)); - } + return (signer_t *)hmac_signer_create(HASH_MD5, 12); default: return NULL; } diff --git a/src/libstrongswan/crypto/signers/signer.h b/src/libstrongswan/crypto/signers/signer.h index 57f7d8fe6..436161a66 100644 --- a/src/libstrongswan/crypto/signers/signer.h +++ b/src/libstrongswan/crypto/signers/signer.h @@ -31,11 +31,9 @@ typedef struct signer_t signer_t; /** * @brief Integrity algorithm, as in IKEv2 RFC 3.3.2. - * - * Currently only the following algorithms are implemented and therefore supported: - * - AUTH_HMAC_MD5_96 - * - AUTH_HMAC_SHA1_96 - * + * + * Algorithms not specified in IKEv2 are allocated in private use space. + * * @ingroup signers */ enum integrity_algorithm_t { @@ -46,7 +44,9 @@ enum integrity_algorithm_t { AUTH_HMAC_SHA1_96 = 2, AUTH_DES_MAC = 3, AUTH_KPDK_MD5 = 4, - AUTH_AES_XCBC_96 = 5 + AUTH_AES_XCBC_96 = 5, + /** Implemented via hmac_signer_t */ + AUTH_HMAC_SHA1_128 = 1025, }; /** diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c index ce3f827fa..3a76a5a05 100644 --- a/src/libstrongswan/library.c +++ b/src/libstrongswan/library.c @@ -43,6 +43,7 @@ ENUM(status_names, SUCCESS, DESTROY_ME, "VERIFY_ERROR", "INVALID_STATE", "DESTROY_ME", + "NEED_MORE", ); /** @@ -59,6 +60,18 @@ void *clalloc(void * pointer, size_t size) } /** + * Described in header. + */ +void memxor(u_int8_t dest[], u_int8_t src[], size_t n) +{ + size_t i; + for (i = 0; i < n; i++) + { + dest[i] ^= src[i]; + } +} + +/** * We use a single mutex for all refcount variables. This * is not optimal for performance, but the critical section * is not that long... diff --git a/src/libstrongswan/library.h b/src/libstrongswan/library.h index 12aa0cb3c..7c7f087f0 100644 --- a/src/libstrongswan/library.h +++ b/src/libstrongswan/library.h @@ -226,6 +226,11 @@ enum status_t { * Destroy object which called method belongs to. */ DESTROY_ME, + + /** + * Another call to the method is required. + */ + NEED_MORE, }; /** @@ -260,6 +265,11 @@ typedef struct sockaddr sockaddr_t; void *clalloc(void *pointer, size_t size); /** + * Same as memcpy, but XORs src into dst instead of copy + */ +void memxor(u_int8_t dest[], u_int8_t src[], size_t n); + +/** * Special type to count references */ typedef volatile u_int refcount_t; diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index 099e1170c..2c1cde707 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -186,6 +186,7 @@ whitelist_t whitelist[] = { {getservbyport, 311}, {register_printf_function, 159}, {syslog, 45}, + {dlopen, 109}, }; /** |