all hashes, hmacs and prfs use libstrongswan

This commit is contained in:
Andreas Steffen
2009-05-06 20:05:22 +02:00
parent e382d96f62
commit ab87051f23
4 changed files with 271 additions and 243 deletions
+25 -15
View File
@@ -21,6 +21,10 @@
#include <freeswan.h> #include <freeswan.h>
#include <ipsec_policy.h> #include <ipsec_policy.h>
#include <library.h>
#include <crypto/hashers/hasher.h>
#include <crypto/prfs/prf.h>
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "crypto.h" #include "crypto.h"
@@ -452,14 +456,16 @@ ike_hash_test(const struct hash_desc *desc)
for (i = 0; desc->hash_testvectors[i].msg_digest != NULL; i++) for (i = 0; desc->hash_testvectors[i].msg_digest != NULL; i++)
{ {
u_char digest[MAX_DIGEST_LEN]; u_char digest[MAX_DIGEST_LEN];
chunk_t msg = { desc->hash_testvectors[i].msg,
desc->hash_testvectors[i].msg_size };
hash_algorithm_t hash_alg;
hasher_t *hasher;
bool result; bool result;
union hash_ctx ctx; hash_alg = oakley_to_hash_algorithm(desc->algo_id);
hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
desc->hash_init(&ctx); hasher->get_hash(hasher, msg, digest);
desc->hash_update(&ctx, desc->hash_testvectors[i].msg hasher->destroy(hasher);
,desc->hash_testvectors[i].msg_size);
desc->hash_final(digest, &ctx);
result = memeq(digest, desc->hash_testvectors[i].msg_digest result = memeq(digest, desc->hash_testvectors[i].msg_digest
, desc->hash_digest_size); , desc->hash_digest_size);
DBG(DBG_CRYPT, DBG(DBG_CRYPT,
@@ -482,17 +488,21 @@ ike_hash_test(const struct hash_desc *desc)
for (i = 0; desc->hmac_testvectors[i].hmac != NULL; i++) for (i = 0; desc->hmac_testvectors[i].hmac != NULL; i++)
{ {
u_char digest[MAX_DIGEST_LEN]; u_char digest[MAX_DIGEST_LEN];
chunk_t key = { desc->hmac_testvectors[i].key,
desc->hmac_testvectors[i].key_size };
chunk_t msg = { desc->hmac_testvectors[i].msg,
desc->hmac_testvectors[i].msg_size };
pseudo_random_function_t prf_alg;
prf_t *prf;
bool result; bool result;
struct hmac_ctx ctx; prf_alg = oakley_to_prf(desc->algo_id);
prf = lib->crypto->create_prf(lib->crypto, prf_alg);
hmac_init(&ctx, desc, desc->hmac_testvectors[i].key prf->set_key(prf, key);
, desc->hmac_testvectors[i].key_size); prf->get_bytes(prf, msg, digest);
hmac_update(&ctx, desc->hmac_testvectors[i].msg prf->destroy(prf);
,desc->hmac_testvectors[i].msg_size); result = memeq(digest, desc->hmac_testvectors[i].hmac,
hmac_final(digest, &ctx); desc->hash_digest_size);
result = memeq(digest, desc->hmac_testvectors[i].hmac
, desc->hash_digest_size);
DBG(DBG_CRYPT, DBG(DBG_CRYPT,
DBG_log(" hmac testvector %d: %s", i, result ? "ok":"failed") DBG_log(" hmac testvector %d: %s", i, result ? "ok":"failed")
) )
+186 -186
View File
@@ -33,6 +33,7 @@
#include <asn1/asn1.h> #include <asn1/asn1.h>
#include <crypto/hashers/hasher.h> #include <crypto/hashers/hasher.h>
#include <crypto/prfs/prf.h> #include <crypto/prfs/prf.h>
#include <crypto/prf_plus.h>
#include <crypto/rngs/rng.h> #include <crypto/rngs/rng.h>
#include "constants.h" #include "constants.h"
@@ -397,16 +398,22 @@ static void send_notification(struct state *sndst, u_int16_t type,
/* calculate hash value and patch into Hash Payload */ /* calculate hash value and patch into Hash Payload */
if (encst) if (encst)
{ {
struct hmac_ctx ctx; chunk_t msgid_chunk = chunk_from_thing(msgid);
hmac_init_chunk(&ctx, encst->st_oakley.hasher, encst->st_skeyid_a); chunk_t msg_chunk = { r_hash_start, r_hdr_pbs.cur-r_hash_start };
hmac_update(&ctx, (u_char *) &msgid, sizeof(msgid_t)); pseudo_random_function_t prf_alg;
hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur-r_hash_start); prf_t *prf;
hmac_final(r_hashval, &ctx);
prf_alg = oakley_to_prf(encst->st_oakley.hasher->algo_id);
prf = lib->crypto->create_prf(lib->crypto, prf_alg);
prf->set_key(prf, encst->st_skeyid_a);
prf->get_bytes(prf, msgid_chunk, NULL);
prf->get_bytes(prf, msg_chunk, r_hashval);
DBG(DBG_CRYPT, DBG(DBG_CRYPT,
DBG_log("HASH computed:"); DBG_log("HASH computed:");
DBG_dump("", r_hashval, ctx.hmac_digest_size); DBG_dump("", r_hashval, prf->get_block_size(prf));
) )
prf->destroy(prf);
} }
/* Encrypt message (preserve st_iv and st_new_iv) */ /* Encrypt message (preserve st_iv and st_new_iv) */
@@ -648,16 +655,23 @@ void send_delete(struct state *st)
/* calculate hash value and patch into Hash Payload */ /* calculate hash value and patch into Hash Payload */
{ {
struct hmac_ctx ctx; chunk_t msgid_chunk = chunk_from_thing(msgid);
hmac_init_chunk(&ctx, p1st->st_oakley.hasher, p1st->st_skeyid_a); chunk_t msg_chunk = { r_hash_start, r_hdr_pbs.cur-r_hash_start };
hmac_update(&ctx, (u_char *) &msgid, sizeof(msgid_t)); pseudo_random_function_t prf_alg;
hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur-r_hash_start); prf_t *prf;
hmac_final(r_hashval, &ctx);
prf_alg = oakley_to_prf(p1st->st_oakley.hasher->algo_id);
prf = lib->crypto->create_prf(lib->crypto, prf_alg);
prf->set_key(prf, p1st->st_skeyid_a);
prf->get_bytes(prf, msgid_chunk, NULL);
prf->get_bytes(prf, msg_chunk, r_hashval);
DBG(DBG_CRYPT, DBG(DBG_CRYPT,
DBG_log("HASH(1) computed:"); DBG_log("HASH(1) computed:");
DBG_dump("", r_hashval, ctx.hmac_digest_size); DBG_dump("", r_hashval, prf->get_block_size(prf));
) )
prf->destroy(prf);
} }
/* Do a dance to avoid needing a new state object. /* Do a dance to avoid needing a new state object.
@@ -1172,8 +1186,8 @@ static bool skeyid_preshared(struct state *st)
prf = lib->crypto->create_prf(lib->crypto, prf_alg); prf = lib->crypto->create_prf(lib->crypto, prf_alg);
if (prf == NULL) if (prf == NULL)
{ {
loglog(RC_LOG_SERIOUS, "%N not available to compute skeyid", loglog(RC_LOG_SERIOUS, "%N not available to compute skeyid",
pseudo_random_function_names, prf_alg); pseudo_random_function_names, prf_alg);
return FALSE; return FALSE;
} }
free(st->st_skeyid.ptr); free(st->st_skeyid.ptr);
@@ -1317,32 +1331,32 @@ static bool generate_skeyids_iv(struct state *st)
* See RFC 2409 "IKE" Appendix B * See RFC 2409 "IKE" Appendix B
*/ */
{ {
/* const size_t keysize = st->st_oakley.encrypter->keydeflen/BITS_PER_BYTE; */ size_t keysize = st->st_oakley.enckeylen/BITS_PER_BYTE;
const size_t keysize = st->st_oakley.enckeylen/BITS_PER_BYTE;
u_char keytemp[MAX_OAKLEY_KEY_LEN + MAX_DIGEST_LEN]; /* free any existing key */
u_char *k = st->st_skeyid_e.ptr; free(st->st_enc_key.ptr);
if (keysize > st->st_skeyid_e.len) if (keysize > st->st_skeyid_e.len)
{ {
struct hmac_ctx ctx; char seed_buf[] = { 0x00 };
size_t i = 0; chunk_t seed = chunk_from_buf(seed_buf);
pseudo_random_function_t prf_alg;
prf_plus_t *prf_plus;
prf_t *prf;
hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_e); prf_alg = oakley_to_prf(st->st_oakley.hasher->algo_id);
hmac_update(&ctx, "\0", 1); prf = lib->crypto->create_prf(lib->crypto, prf_alg);
for (;;) prf->set_key(prf, st->st_skeyid_e);
{ prf_plus = prf_plus_create(prf, seed);
hmac_final(&keytemp[i], &ctx); prf_plus->allocate_bytes(prf_plus, keysize, &st->st_enc_key);
i += ctx.hmac_digest_size; prf_plus->destroy(prf_plus);
if (i >= keysize) prf->destroy(prf);
break; }
hmac_reinit(&ctx); else
hmac_update(&ctx, &keytemp[i - ctx.hmac_digest_size], ctx.hmac_digest_size); {
} st->st_enc_key = chunk_create(st->st_skeyid_e.ptr, keysize);
k = keytemp; st->st_enc_key = chunk_clone(st->st_enc_key);
} }
free(st->st_enc_key.ptr);
st->st_enc_key = chunk_create(k, keysize);
st->st_enc_key = chunk_clone(st->st_enc_key);
} }
DBG(DBG_CRYPT, DBG(DBG_CRYPT,
@@ -1361,96 +1375,56 @@ static bool generate_skeyids_iv(struct state *st)
* If the hashi argument is TRUE, generate HASH_I; if FALSE generate HASH_R. * If the hashi argument is TRUE, generate HASH_I; if FALSE generate HASH_R.
* If hashus argument is TRUE, we're generating a hash for our end. * If hashus argument is TRUE, we're generating a hash for our end.
* See RFC2409 IKE 5. * See RFC2409 IKE 5.
*
* Generating the SIG_I and SIG_R for DSS is an odd perversion of this:
* Most of the logic is the same, but SHA-1 is used in place of HMAC-whatever.
* The extensive common logic is embodied in main_mode_hash_body().
* See draft-ietf-ipsec-ike-01.txt 4.1 and 6.1.1.2
*/ */
static size_t main_mode_hash(struct state *st, u_char *hash_val, bool hashi,
typedef void (*hash_update_t)(union hash_ctx *, const u_char *, size_t) ; const pb_stream *idpl)
static void main_mode_hash_body(struct state *st, bool hashi,
const pb_stream *idpl, union hash_ctx *ctx,
void (*hash_update_void)(void *, const u_char *input, size_t))
{ {
#define HASH_UPDATE_T (union hash_ctx *, const u_char *input, unsigned int len) chunk_t icookie = { st->st_icookie, COOKIE_SIZE };
hash_update_t hash_update=(hash_update_t) hash_update_void; chunk_t rcookie = { st->st_rcookie, COOKIE_SIZE };
#if 0 /* if desperate to debug hashing */ chunk_t sa_body = { st->st_p1isa.ptr + sizeof(struct isakmp_generic),
# define hash_update(ctx, input, len) { \ st->st_p1isa.len - sizeof(struct isakmp_generic) };
DBG_dump("hash input", input, len); \ chunk_t id_body = { idpl->start + sizeof(struct isakmp_generic),
(hash_update)(ctx, input, len); \ pbs_offset(idpl) - sizeof(struct isakmp_generic) };
} pseudo_random_function_t prf_alg;
#endif prf_t *prf;
size_t prf_block_size;
# define hash_update_chunk(ctx, ch) hash_update((ctx), (ch).ptr, (ch).len) prf_alg = oakley_to_prf(st->st_oakley.hasher->algo_id);
prf = lib->crypto->create_prf(lib->crypto, prf_alg);
prf->set_key(prf, st->st_skeyid);
if (hashi) if (hashi)
{ {
hash_update_chunk(ctx, st->st_gi); prf->get_bytes(prf, st->st_gi, NULL);
hash_update_chunk(ctx, st->st_gr); prf->get_bytes(prf, st->st_gr, NULL);
hash_update(ctx, st->st_icookie, COOKIE_SIZE); prf->get_bytes(prf, icookie, NULL);
hash_update(ctx, st->st_rcookie, COOKIE_SIZE); prf->get_bytes(prf, rcookie, NULL);
} }
else else
{ {
hash_update_chunk(ctx, st->st_gr); prf->get_bytes(prf, st->st_gr, NULL);
hash_update_chunk(ctx, st->st_gi); prf->get_bytes(prf, st->st_gi, NULL);
hash_update(ctx, st->st_rcookie, COOKIE_SIZE); prf->get_bytes(prf, rcookie, NULL);
hash_update(ctx, st->st_icookie, COOKIE_SIZE); prf->get_bytes(prf, icookie, NULL);
} }
DBG(DBG_CRYPT, DBG_log("hashing %lu bytes of SA" DBG(DBG_CRYPT,
, (unsigned long) (st->st_p1isa.len - sizeof(struct isakmp_generic)))); DBG_log("hashing %u bytes of SA", sa_body.len)
)
/* SA_b */ prf->get_bytes(prf, sa_body, NULL);
hash_update(ctx, st->st_p1isa.ptr + sizeof(struct isakmp_generic)
, st->st_p1isa.len - sizeof(struct isakmp_generic));
/* Hash identification payload, without generic payload header. /* Hash identification payload, without generic payload header.
* We used to reconstruct ID Payload for this purpose, but now * We used to reconstruct ID Payload for this purpose, but now
* we use the bytes as they appear on the wire to avoid * we use the bytes as they appear on the wire to avoid
* "spelling problems". * "spelling problems".
*/ */
hash_update(ctx prf->get_bytes(prf, id_body, hash_val);
, idpl->start + sizeof(struct isakmp_generic) prf_block_size = prf->get_block_size(prf);
, pbs_offset(idpl) - sizeof(struct isakmp_generic)); prf->destroy(prf);
# undef hash_update_chunk return prf_block_size;
# undef hash_update
} }
static size_t /* length of hash */
main_mode_hash(struct state *st, u_char *hash_val, bool hashi,
const pb_stream *idpl)
{
struct hmac_ctx ctx;
hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid);
main_mode_hash_body(st, hashi, idpl, &ctx.hash_ctx, ctx.h->hash_update);
hmac_final(hash_val, &ctx);
return ctx.hmac_digest_size;
}
#if 0 /* only needed for DSS */
static void
main_mode_sha1(struct state *st
, u_char *hash_val /* resulting bytes */
, size_t *hash_len /* length of hash */
, bool hashi /* Initiator? */
, const pb_stream *idpl) /* ID payload, as PBS */
{
union hash_ctx ctx;
SHA1Init(&ctx.ctx_sha1);
SHA1Update(&ctx.ctx_sha1, st->st_skeyid.ptr, st->st_skeyid.len);
*hash_len = SHA1_DIGEST_SIZE;
main_mode_hash_body(st, hashi, idpl, &ctx
, (void (*)(union hash_ctx *, const u_char *, unsigned int))&SHA1Update);
SHA1Final(hash_val, &ctx.ctx_sha1);
}
#endif
/* Create an RSA signature of a hash. /* Create an RSA signature of a hash.
* Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2. * Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2.
* Use PKCS#1 version 1.5 encryption of hash (called * Use PKCS#1 version 1.5 encryption of hash (called
@@ -1911,31 +1885,33 @@ encrypt_message(pb_stream *pbs, struct state *st)
* Used by: quick_outI1, quick_inI1_outR1 (twice), quick_inR1_outI2 * Used by: quick_outI1, quick_inI1_outR1 (twice), quick_inR1_outI2
* (see RFC 2409 "IKE" 5.5, pg. 18 or draft-ietf-ipsec-ike-01.txt 6.2 pg 25) * (see RFC 2409 "IKE" 5.5, pg. 18 or draft-ietf-ipsec-ike-01.txt 6.2 pg 25)
*/ */
static size_t quick_mode_hash12(u_char *dest, const u_char *start, static size_t quick_mode_hash12(u_char *dest, u_char *start, u_char *roof,
const u_char *roof, const struct state *st, const struct state *st, const msgid_t *msgid,
const msgid_t *msgid, bool hash2) bool hash2)
{ {
struct hmac_ctx ctx; chunk_t msgid_chunk = chunk_from_thing(*msgid);
chunk_t msg_chunk = { start, roof - start };
pseudo_random_function_t prf_alg;
prf_t *prf;
size_t prf_block_size;
#if 0 /* if desperate to debug hashing */ prf_alg = oakley_to_prf(st->st_oakley.hasher->algo_id);
# define hmac_update(ctx, ptr, len) { \ prf = lib->crypto->create_prf(lib->crypto, prf_alg);
DBG_dump("hash input", (ptr), (len)); \ prf->set_key(prf, st->st_skeyid_a);
(hmac_update)((ctx), (ptr), (len)); \ prf->get_bytes(prf, msgid_chunk, NULL);
}
DBG_dump("hash key", st->st_skeyid_a.ptr, st->st_skeyid_a.len);
#endif
hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a);
hmac_update(&ctx, (const void *) msgid, sizeof(msgid_t));
if (hash2) if (hash2)
hmac_update_chunk(&ctx, st->st_ni); /* include Ni_b in the hash */ {
hmac_update(&ctx, start, roof-start); prf->get_bytes(prf, st->st_ni, NULL); /* include Ni_b in the hash */
hmac_final(dest, &ctx); }
prf->get_bytes(prf, msg_chunk, dest);
prf_block_size = prf->get_block_size(prf);
prf->destroy(prf);
DBG(DBG_CRYPT, DBG(DBG_CRYPT,
DBG_log("HASH(%d) computed:", hash2 + 1); DBG_log("HASH(%d) computed:", hash2 + 1);
DBG_dump("", dest, ctx.hmac_digest_size)); DBG_dump("", dest, prf_block_size)
return ctx.hmac_digest_size; )
# undef hmac_update return prf_block_size;
} }
/* Compute HASH(3) in Quick Mode (part of Quick I2 message). /* Compute HASH(3) in Quick Mode (part of Quick I2 message).
@@ -1946,16 +1922,25 @@ static size_t quick_mode_hash12(u_char *dest, const u_char *start,
*/ */
static size_t quick_mode_hash3(u_char *dest, struct state *st) static size_t quick_mode_hash3(u_char *dest, struct state *st)
{ {
struct hmac_ctx ctx; char seed_buf[] = { 0x00 };
chunk_t seed_chunk = chunk_from_buf(seed_buf);
chunk_t msgid_chunk = chunk_from_thing(st->st_msgid);
pseudo_random_function_t prf_alg;
prf_t *prf;
size_t prf_block_size;
hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a); prf_alg = oakley_to_prf(st->st_oakley.hasher->algo_id);
hmac_update(&ctx, "\0", 1); prf = lib->crypto->create_prf(lib->crypto, prf_alg);
hmac_update(&ctx, (u_char *) &st->st_msgid, sizeof(st->st_msgid)); prf->set_key(prf, st->st_skeyid_a);
hmac_update_chunk(&ctx, st->st_ni); prf->get_bytes(prf, seed_chunk, NULL );
hmac_update_chunk(&ctx, st->st_nr); prf->get_bytes(prf, msgid_chunk, NULL);
hmac_final(dest, &ctx); prf->get_bytes(prf, st->st_ni, NULL);
DBG_cond_dump(DBG_CRYPT, "HASH(3) computed:", dest, ctx.hmac_digest_size); prf->get_bytes(prf, st->st_nr, dest);
return ctx.hmac_digest_size; prf_block_size = prf->get_block_size(prf);
prf->destroy(prf);
DBG_cond_dump(DBG_CRYPT, "HASH(3) computed:", dest, prf_block_size);
return prf_block_size;
} }
/* Compute Phase 2 IV. /* Compute Phase 2 IV.
@@ -1963,23 +1948,26 @@ static size_t quick_mode_hash3(u_char *dest, struct state *st)
*/ */
void init_phase2_iv(struct state *st, const msgid_t *msgid) void init_phase2_iv(struct state *st, const msgid_t *msgid)
{ {
const struct hash_desc *h = st->st_oakley.hasher; chunk_t iv_chunk = { st->st_ph1_iv, st->st_ph1_iv_len };
union hash_ctx ctx; chunk_t msgid_chunk = chunk_from_thing(*msgid);
hash_algorithm_t hash_alg;
hasher_t *hasher;
DBG_cond_dump(DBG_CRYPT, "last Phase 1 IV:" hash_alg = oakley_to_hash_algorithm(st->st_oakley.hasher->algo_id);
, st->st_ph1_iv, st->st_ph1_iv_len); hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
st->st_new_iv_len = h->hash_digest_size; DBG_cond_dump(DBG_CRYPT, "last Phase 1 IV:",
st->st_ph1_iv, st->st_ph1_iv_len);
st->st_new_iv_len = hasher->get_hash_size(hasher);
passert(st->st_new_iv_len <= sizeof(st->st_new_iv)); passert(st->st_new_iv_len <= sizeof(st->st_new_iv));
h->hash_init(&ctx); hasher->get_hash(hasher, iv_chunk, NULL);
h->hash_update(&ctx, st->st_ph1_iv, st->st_ph1_iv_len); hasher->get_hash(hasher, msgid_chunk, st->st_new_iv);
passert(*msgid != 0); hasher->destroy(hasher);
h->hash_update(&ctx, (const u_char *)msgid, sizeof(*msgid));
h->hash_final(st->st_new_iv, &ctx);
DBG_cond_dump(DBG_CRYPT, "computed Phase 2 IV:" DBG_cond_dump(DBG_CRYPT, "computed Phase 2 IV:",
, st->st_new_iv, st->st_new_iv_len); st->st_new_iv, st->st_new_iv_len);
} }
/* Initiate quick mode. /* Initiate quick mode.
@@ -2872,62 +2860,68 @@ static void compute_proto_keymat(struct state *st, u_int8_t protoid,
pi->keymat_len = needed_len; pi->keymat_len = needed_len;
/* Allocate space for the keying material. /* Allocate space for the keying material. Although only needed_len bytes
* Although only needed_len bytes are desired, we * are desired, we must round up to a multiple of hash_size
* must round up to a multiple of ctx.hmac_digest_size
* so that our buffer isn't overrun. * so that our buffer isn't overrun.
*/ */
{ {
struct hmac_ctx ctx_me, ctx_peer; size_t needed_space; /* space needed for keying material (rounded up) */
size_t needed_space; /* space needed for keying material (rounded up) */ size_t i, prf_block_size;
size_t i; chunk_t protoid_chunk = chunk_from_thing(protoid);
chunk_t spi_our = chunk_from_thing(pi->our_spi);
chunk_t spi_peer = chunk_from_thing(pi->attrs.spi);
pseudo_random_function_t prf_alg;
prf_t *prf_our, *prf_peer;
hmac_init_chunk(&ctx_me, st->st_oakley.hasher, st->st_skeyid_d); prf_alg = oakley_to_prf(st->st_oakley.hasher->algo_id);
ctx_peer = ctx_me; /* duplicate initial conditions */ prf_our = lib->crypto->create_prf(lib->crypto, prf_alg);
prf_peer = lib->crypto->create_prf(lib->crypto, prf_alg);
prf_our->set_key(prf_our, st->st_skeyid_d);
prf_peer->set_key(prf_peer, st->st_skeyid_d);
prf_block_size = prf_our->get_block_size(prf_our);
needed_space = needed_len + pad_up(needed_len, ctx_me.hmac_digest_size); needed_space = needed_len + pad_up(needed_len, prf_block_size);
replace(pi->our_keymat, malloc(needed_space)); replace(pi->our_keymat, malloc(needed_space));
replace(pi->peer_keymat, malloc(needed_space)); replace(pi->peer_keymat, malloc(needed_space));
for (i = 0;; ) for (i = 0;; )
{ {
char *keymat_i_our = pi->our_keymat + i;
char *keymat_i_peer = pi->peer_keymat + i;
chunk_t keymat_our = { keymat_i_our, prf_block_size };
chunk_t keymat_peer = { keymat_i_peer, prf_block_size };
if (st->st_shared.ptr != NULL) if (st->st_shared.ptr != NULL)
{ {
/* PFS: include the g^xy */ /* PFS: include the g^xy */
hmac_update_chunk(&ctx_me, st->st_shared); prf_our->get_bytes(prf_our, st->st_shared, NULL);
hmac_update_chunk(&ctx_peer, st->st_shared); prf_peer->get_bytes(prf_peer, st->st_shared, NULL);
} }
hmac_update(&ctx_me, &protoid, sizeof(protoid)); prf_our->get_bytes(prf_our, protoid_chunk, NULL);
hmac_update(&ctx_peer, &protoid, sizeof(protoid)); prf_peer->get_bytes(prf_peer, protoid_chunk, NULL);
hmac_update(&ctx_me, (u_char *)&pi->our_spi, sizeof(pi->our_spi)); prf_our->get_bytes(prf_our, spi_our, NULL);
hmac_update(&ctx_peer, (u_char *)&pi->attrs.spi, sizeof(pi->attrs.spi)); prf_peer->get_bytes(prf_peer, spi_peer, NULL);
hmac_update_chunk(&ctx_me, st->st_ni); prf_our->get_bytes(prf_our, st->st_ni, NULL);
hmac_update_chunk(&ctx_peer, st->st_ni); prf_peer->get_bytes(prf_peer, st->st_ni, NULL);
hmac_update_chunk(&ctx_me, st->st_nr); prf_our->get_bytes(prf_our, st->st_nr, keymat_i_our);
hmac_update_chunk(&ctx_peer, st->st_nr); prf_peer->get_bytes(prf_peer, st->st_nr, keymat_i_peer);
hmac_final(pi->our_keymat + i, &ctx_me); i += prf_block_size;
hmac_final(pi->peer_keymat + i, &ctx_peer);
i += ctx_me.hmac_digest_size;
if (i >= needed_space) if (i >= needed_space)
{
break; break;
}
/* more keying material needed: prepare to go around again */ /* more keying material needed: prepare to go around again */
prf_our->get_bytes(prf_our, keymat_our, NULL);
hmac_reinit(&ctx_me); prf_peer->get_bytes(prf_peer, keymat_peer, NULL);
hmac_reinit(&ctx_peer);
hmac_update(&ctx_me, pi->our_keymat + i - ctx_me.hmac_digest_size
, ctx_me.hmac_digest_size);
hmac_update(&ctx_peer, pi->peer_keymat + i - ctx_peer.hmac_digest_size
, ctx_peer.hmac_digest_size);
} }
prf_our->destroy(prf_our);
prf_peer->destroy(prf_peer);
} }
DBG(DBG_CRYPT, DBG(DBG_CRYPT,
DBG_dump("KEYMAT computed:\n", pi->our_keymat, pi->keymat_len); DBG_dump("KEYMAT computed:\n", pi->our_keymat, pi->keymat_len);
DBG_dump("Peer KEYMAT computed:\n", pi->peer_keymat, pi->keymat_len)); DBG_dump("Peer KEYMAT computed:\n", pi->peer_keymat, pi->keymat_len));
@@ -2963,8 +2957,7 @@ static void compute_keymats(struct state *st)
/* Handle a Main Mode Oakley first packet (responder side). /* Handle a Main Mode Oakley first packet (responder side).
* HDR;SA --> HDR;SA * HDR;SA --> HDR;SA
*/ */
stf_status stf_status main_inI1_outR1(struct msg_digest *md)
main_inI1_outR1(struct msg_digest *md)
{ {
struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA];
struct state *st; struct state *st;
@@ -5268,15 +5261,22 @@ static stf_status send_isakmp_notification(struct state *st, u_int16_t type,
{ {
/* finish computing HASH */ /* finish computing HASH */
struct hmac_ctx ctx; chunk_t msgid_chunk = chunk_from_thing(msgid);
hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a); chunk_t msg_chunk = { r_hash_start, rbody.cur-r_hash_start };
hmac_update(&ctx, (const u_char *) &msgid, sizeof(msgid_t)); pseudo_random_function_t prf_alg;
hmac_update(&ctx, r_hash_start, rbody.cur-r_hash_start); prf_t *prf;
hmac_final(r_hashval, &ctx);
prf_alg = oakley_to_prf(st->st_oakley.hasher->algo_id);
prf = lib->crypto->create_prf(lib->crypto, prf_alg);
prf->set_key(prf, st->st_skeyid_a);
prf->get_bytes(prf, msgid_chunk, NULL);
prf->get_bytes(prf, msg_chunk, r_hashval);
DBG(DBG_CRYPT, DBG(DBG_CRYPT,
DBG_log("HASH computed:"); DBG_log("HASH computed:");
DBG_dump("", r_hashval, ctx.hmac_digest_size)); DBG_dump("", r_hashval, prf->get_block_size(prf));
)
prf->destroy(prf);
} }
/* Encrypt message (preserve st_iv and st_new_iv) */ /* Encrypt message (preserve st_iv and st_new_iv) */
+18 -10
View File
@@ -24,7 +24,9 @@
#include <string.h> #include <string.h>
#include <freeswan.h> #include <freeswan.h>
#include <library.h> #include <library.h>
#include <crypto/prfs/prf.h>
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
@@ -241,22 +243,28 @@ set_internal_addr(struct connection *c, internal_addr_t *ia)
/* /*
* Compute HASH of Mode Config. * Compute HASH of Mode Config.
*/ */
static size_t static size_t modecfg_hash(u_char *dest, u_char *start, u_char *roof,
modecfg_hash(u_char *dest, const u_char *start, const u_char *roof const struct state *st)
, const struct state *st)
{ {
struct hmac_ctx ctx; chunk_t msgid_chunk = chunk_from_thing(st->st_msgid);
chunk_t msg_chunk = { start, roof - start };
size_t prf_block_size;
pseudo_random_function_t prf_alg;
prf_t *prf;
hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a); prf_alg = oakley_to_prf(st->st_oakley.hasher->algo_id);
hmac_update(&ctx, (const u_char *) &st->st_msgid, sizeof(st->st_msgid)); prf = lib->crypto->create_prf(lib->crypto, prf_alg);
hmac_update(&ctx, start, roof-start); prf->set_key(prf, st->st_skeyid_a);
hmac_final(dest, &ctx); prf->get_bytes(prf, msgid_chunk, NULL);
prf->get_bytes(prf, msg_chunk, dest);
prf_block_size = prf->get_block_size(prf);
prf->destroy(prf);
DBG(DBG_CRYPT, DBG(DBG_CRYPT,
DBG_log("ModeCfg HASH computed:"); DBG_log("ModeCfg HASH computed:");
DBG_dump("", dest, ctx.hmac_digest_size) DBG_dump("", dest, prf_block_size)
) )
return ctx.hmac_digest_size; return prf_block_size;
} }
+41 -31
View File
@@ -28,6 +28,9 @@
#include <pfkeyv2.h> #include <pfkeyv2.h>
#include <pfkey.h> #include <pfkey.h>
#include <library.h>
#include <crypto/hashers/hasher.h>
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "log.h" #include "log.h"
@@ -102,16 +105,18 @@ static void disable_nat_traversal (int type)
nat_traversal_enabled = FALSE; nat_traversal_enabled = FALSE;
} }
static void _natd_hash(const struct hash_desc *hasher, char *hash, static void _natd_hash(const struct hash_desc *oakley_hasher, char *hash,
u_int8_t *icookie, u_int8_t *rcookie, u_int8_t *icookie, u_int8_t *rcookie,
const ip_address *ip, u_int16_t port) const ip_address *ip, u_int16_t port)
{ {
union hash_ctx ctx;
if (is_zero_cookie(icookie)) if (is_zero_cookie(icookie))
{
DBG_log("_natd_hash: Warning, icookie is zero !!"); DBG_log("_natd_hash: Warning, icookie is zero !!");
}
if (is_zero_cookie(rcookie)) if (is_zero_cookie(rcookie))
{
DBG_log("_natd_hash: Warning, rcookie is zero !!"); DBG_log("_natd_hash: Warning, rcookie is zero !!");
}
/** /**
* draft-ietf-ipsec-nat-t-ike-01.txt * draft-ietf-ipsec-nat-t-ike-01.txt
@@ -120,36 +125,41 @@ static void _natd_hash(const struct hash_desc *hasher, char *hash,
* *
* All values in network order * All values in network order
*/ */
hasher->hash_init(&ctx); {
hasher->hash_update(&ctx, icookie, COOKIE_SIZE); chunk_t icookie_chunk = { icookie, COOKIE_SIZE };
hasher->hash_update(&ctx, rcookie, COOKIE_SIZE); chunk_t rcookie_chunk = { rcookie, COOKIE_SIZE };
switch (addrtypeof(ip)) { chunk_t port_chunk = chunk_from_thing(port);
case AF_INET: chunk_t addr_chunk;
hasher->hash_update(&ctx, (const u_char *)&ip->u.v4.sin_addr.s_addr hash_algorithm_t hash_alg;
, sizeof(ip->u.v4.sin_addr.s_addr)); hasher_t *hasher;
break; size_t hash_size;
case AF_INET6:
hasher->hash_update(&ctx, (const u_char *)&ip->u.v6.sin6_addr.s6_addr hash_alg = oakley_to_hash_algorithm(oakley_hasher->algo_id);
, sizeof(ip->u.v6.sin6_addr.s6_addr)); hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
break; hasher->get_hash(hasher, icookie_chunk, NULL);
} hasher->get_hash(hasher, rcookie_chunk, NULL);
hasher->hash_update(&ctx, (const u_char *)&port, sizeof(u_int16_t)); switch (addrtypeof(ip))
hasher->hash_final(hash, &ctx); {
#ifdef NAT_D_DEBUG case AF_INET:
DBG(DBG_NATT, addr_chunk = chunk_from_thing(ip->u.v4.sin_addr.s_addr);
DBG_log("_natd_hash: hasher=%p(%d)", hasher, (int)hasher->hash_digest_len); break;
DBG_dump("_natd_hash: icookie=", icookie, COOKIE_SIZE); case AF_INET6:
DBG_dump("_natd_hash: rcookie=", rcookie, COOKIE_SIZE); addr_chunk = chunk_from_thing(ip->u.v6.sin6_addr.s6_addr);
switch (addrtypeof(ip)) {
case AF_INET:
DBG_dump("_natd_hash: ip=", &ip->u.v4.sin_addr.s_addr
, sizeof(ip->u.v4.sin_addr.s_addr));
break;
} }
DBG_log("_natd_hash: port=%d", port); hasher->get_hash(hasher, addr_chunk, NULL);
DBG_dump("_natd_hash: hash=", hash, hasher->hash_digest_len); hasher->get_hash(hasher, port_chunk, hash);
); hash_size = hasher->get_hash_size(hasher);
hasher->destroy(hasher);
#ifdef NAT_D_DEBUG
DBG(DBG_NATT,
DBG_dump_chunk("_natd_hash: icookie=", icookie_chunk);
DBG_dump_chunk("_natd_hash: rcookie=", rcookie_chunk);
DBG_dump_chunk("_natd_hash: ip=", addr_chunk);
DBG_log("_natd_hash: port=%d", port);
DBG_dump("_natd_hash: hash=", hash, hash_size);
)
#endif #endif
}
} }
/* Add NAT-Traversal VIDs (supported ones) /* Add NAT-Traversal VIDs (supported ones)