all hashes, hmacs and prfs use libstrongswan

This commit is contained in:
Andreas Steffen 2009-05-06 20:05:06 +02:00
parent e382d96f62
commit ab87051f23
4 changed files with 271 additions and 243 deletions

View File

@ -21,6 +21,10 @@
#include <freeswan.h>
#include <ipsec_policy.h>
#include <library.h>
#include <crypto/hashers/hasher.h>
#include <crypto/prfs/prf.h>
#include "constants.h"
#include "defs.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++)
{
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;
union hash_ctx ctx;
desc->hash_init(&ctx);
desc->hash_update(&ctx, desc->hash_testvectors[i].msg
,desc->hash_testvectors[i].msg_size);
desc->hash_final(digest, &ctx);
hash_alg = oakley_to_hash_algorithm(desc->algo_id);
hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
hasher->get_hash(hasher, msg, digest);
hasher->destroy(hasher);
result = memeq(digest, desc->hash_testvectors[i].msg_digest
, desc->hash_digest_size);
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++)
{
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;
struct hmac_ctx ctx;
hmac_init(&ctx, desc, desc->hmac_testvectors[i].key
, desc->hmac_testvectors[i].key_size);
hmac_update(&ctx, desc->hmac_testvectors[i].msg
,desc->hmac_testvectors[i].msg_size);
hmac_final(digest, &ctx);
result = memeq(digest, desc->hmac_testvectors[i].hmac
, desc->hash_digest_size);
prf_alg = oakley_to_prf(desc->algo_id);
prf = lib->crypto->create_prf(lib->crypto, prf_alg);
prf->set_key(prf, key);
prf->get_bytes(prf, msg, digest);
prf->destroy(prf);
result = memeq(digest, desc->hmac_testvectors[i].hmac,
desc->hash_digest_size);
DBG(DBG_CRYPT,
DBG_log(" hmac testvector %d: %s", i, result ? "ok":"failed")
)

View File

@ -33,6 +33,7 @@
#include <asn1/asn1.h>
#include <crypto/hashers/hasher.h>
#include <crypto/prfs/prf.h>
#include <crypto/prf_plus.h>
#include <crypto/rngs/rng.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 */
if (encst)
{
struct hmac_ctx ctx;
hmac_init_chunk(&ctx, encst->st_oakley.hasher, encst->st_skeyid_a);
hmac_update(&ctx, (u_char *) &msgid, sizeof(msgid_t));
hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur-r_hash_start);
hmac_final(r_hashval, &ctx);
chunk_t msgid_chunk = chunk_from_thing(msgid);
chunk_t msg_chunk = { r_hash_start, r_hdr_pbs.cur-r_hash_start };
pseudo_random_function_t prf_alg;
prf_t *prf;
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_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) */
@ -648,16 +655,23 @@ void send_delete(struct state *st)
/* calculate hash value and patch into Hash Payload */
{
struct hmac_ctx ctx;
hmac_init_chunk(&ctx, p1st->st_oakley.hasher, p1st->st_skeyid_a);
hmac_update(&ctx, (u_char *) &msgid, sizeof(msgid_t));
hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur-r_hash_start);
hmac_final(r_hashval, &ctx);
chunk_t msgid_chunk = chunk_from_thing(msgid);
chunk_t msg_chunk = { r_hash_start, r_hdr_pbs.cur-r_hash_start };
pseudo_random_function_t prf_alg;
prf_t *prf;
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_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.
@ -1172,8 +1186,8 @@ static bool skeyid_preshared(struct state *st)
prf = lib->crypto->create_prf(lib->crypto, prf_alg);
if (prf == NULL)
{
loglog(RC_LOG_SERIOUS, "%N not available to compute skeyid",
pseudo_random_function_names, prf_alg);
loglog(RC_LOG_SERIOUS, "%N not available to compute skeyid",
pseudo_random_function_names, prf_alg);
return FALSE;
}
free(st->st_skeyid.ptr);
@ -1317,32 +1331,32 @@ static bool generate_skeyids_iv(struct state *st)
* See RFC 2409 "IKE" Appendix B
*/
{
/* const size_t keysize = st->st_oakley.encrypter->keydeflen/BITS_PER_BYTE; */
const size_t keysize = st->st_oakley.enckeylen/BITS_PER_BYTE;
u_char keytemp[MAX_OAKLEY_KEY_LEN + MAX_DIGEST_LEN];
u_char *k = st->st_skeyid_e.ptr;
size_t keysize = st->st_oakley.enckeylen/BITS_PER_BYTE;
/* free any existing key */
free(st->st_enc_key.ptr);
if (keysize > st->st_skeyid_e.len)
{
struct hmac_ctx ctx;
size_t i = 0;
char seed_buf[] = { 0x00 };
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);
hmac_update(&ctx, "\0", 1);
for (;;)
{
hmac_final(&keytemp[i], &ctx);
i += ctx.hmac_digest_size;
if (i >= keysize)
break;
hmac_reinit(&ctx);
hmac_update(&ctx, &keytemp[i - ctx.hmac_digest_size], ctx.hmac_digest_size);
}
k = keytemp;
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_e);
prf_plus = prf_plus_create(prf, seed);
prf_plus->allocate_bytes(prf_plus, keysize, &st->st_enc_key);
prf_plus->destroy(prf_plus);
prf->destroy(prf);
}
free(st->st_enc_key.ptr);
st->st_enc_key = chunk_create(k, keysize);
st->st_enc_key = chunk_clone(st->st_enc_key);
else
{
st->st_enc_key = chunk_create(st->st_skeyid_e.ptr, keysize);
st->st_enc_key = chunk_clone(st->st_enc_key);
}
}
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 hashus argument is TRUE, we're generating a hash for our end.
* 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
*/
typedef void (*hash_update_t)(union hash_ctx *, const u_char *, size_t) ;
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))
static size_t main_mode_hash(struct state *st, u_char *hash_val, bool hashi,
const pb_stream *idpl)
{
#define HASH_UPDATE_T (union hash_ctx *, const u_char *input, unsigned int len)
hash_update_t hash_update=(hash_update_t) hash_update_void;
#if 0 /* if desperate to debug hashing */
# define hash_update(ctx, input, len) { \
DBG_dump("hash input", input, len); \
(hash_update)(ctx, input, len); \
}
#endif
chunk_t icookie = { st->st_icookie, COOKIE_SIZE };
chunk_t rcookie = { st->st_rcookie, COOKIE_SIZE };
chunk_t sa_body = { st->st_p1isa.ptr + sizeof(struct isakmp_generic),
st->st_p1isa.len - sizeof(struct isakmp_generic) };
chunk_t id_body = { idpl->start + sizeof(struct isakmp_generic),
pbs_offset(idpl) - sizeof(struct isakmp_generic) };
pseudo_random_function_t prf_alg;
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)
{
hash_update_chunk(ctx, st->st_gi);
hash_update_chunk(ctx, st->st_gr);
hash_update(ctx, st->st_icookie, COOKIE_SIZE);
hash_update(ctx, st->st_rcookie, COOKIE_SIZE);
prf->get_bytes(prf, st->st_gi, NULL);
prf->get_bytes(prf, st->st_gr, NULL);
prf->get_bytes(prf, icookie, NULL);
prf->get_bytes(prf, rcookie, NULL);
}
else
{
hash_update_chunk(ctx, st->st_gr);
hash_update_chunk(ctx, st->st_gi);
hash_update(ctx, st->st_rcookie, COOKIE_SIZE);
hash_update(ctx, st->st_icookie, COOKIE_SIZE);
prf->get_bytes(prf, st->st_gr, NULL);
prf->get_bytes(prf, st->st_gi, NULL);
prf->get_bytes(prf, rcookie, NULL);
prf->get_bytes(prf, icookie, NULL);
}
DBG(DBG_CRYPT, DBG_log("hashing %lu bytes of SA"
, (unsigned long) (st->st_p1isa.len - sizeof(struct isakmp_generic))));
/* SA_b */
hash_update(ctx, st->st_p1isa.ptr + sizeof(struct isakmp_generic)
, st->st_p1isa.len - sizeof(struct isakmp_generic));
DBG(DBG_CRYPT,
DBG_log("hashing %u bytes of SA", sa_body.len)
)
prf->get_bytes(prf, sa_body, NULL);
/* Hash identification payload, without generic payload header.
* We used to reconstruct ID Payload for this purpose, but now
* we use the bytes as they appear on the wire to avoid
* "spelling problems".
*/
hash_update(ctx
, idpl->start + sizeof(struct isakmp_generic)
, pbs_offset(idpl) - sizeof(struct isakmp_generic));
prf->get_bytes(prf, id_body, hash_val);
prf_block_size = prf->get_block_size(prf);
prf->destroy(prf);
# undef hash_update_chunk
# undef hash_update
return prf_block_size;
}
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.
* Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2.
* 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
* (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,
const u_char *roof, const struct state *st,
const msgid_t *msgid, bool hash2)
static size_t quick_mode_hash12(u_char *dest, u_char *start, u_char *roof,
const struct state *st, const msgid_t *msgid,
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 */
# define hmac_update(ctx, ptr, len) { \
DBG_dump("hash input", (ptr), (len)); \
(hmac_update)((ctx), (ptr), (len)); \
}
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));
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);
if (hash2)
hmac_update_chunk(&ctx, st->st_ni); /* include Ni_b in the hash */
hmac_update(&ctx, start, roof-start);
hmac_final(dest, &ctx);
{
prf->get_bytes(prf, st->st_ni, NULL); /* include Ni_b in the hash */
}
prf->get_bytes(prf, msg_chunk, dest);
prf_block_size = prf->get_block_size(prf);
prf->destroy(prf);
DBG(DBG_CRYPT,
DBG_log("HASH(%d) computed:", hash2 + 1);
DBG_dump("", dest, ctx.hmac_digest_size));
return ctx.hmac_digest_size;
# undef hmac_update
DBG_dump("", dest, prf_block_size)
)
return prf_block_size;
}
/* 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)
{
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;
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, seed_chunk, NULL );
prf->get_bytes(prf, msgid_chunk, NULL);
prf->get_bytes(prf, st->st_ni, NULL);
prf->get_bytes(prf, st->st_nr, dest);
prf_block_size = prf->get_block_size(prf);
prf->destroy(prf);
hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a);
hmac_update(&ctx, "\0", 1);
hmac_update(&ctx, (u_char *) &st->st_msgid, sizeof(st->st_msgid));
hmac_update_chunk(&ctx, st->st_ni);
hmac_update_chunk(&ctx, st->st_nr);
hmac_final(dest, &ctx);
DBG_cond_dump(DBG_CRYPT, "HASH(3) computed:", dest, ctx.hmac_digest_size);
return ctx.hmac_digest_size;
DBG_cond_dump(DBG_CRYPT, "HASH(3) computed:", dest, prf_block_size);
return prf_block_size;
}
/* 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)
{
const struct hash_desc *h = st->st_oakley.hasher;
union hash_ctx ctx;
chunk_t iv_chunk = { st->st_ph1_iv, st->st_ph1_iv_len };
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:"
, st->st_ph1_iv, st->st_ph1_iv_len);
hash_alg = oakley_to_hash_algorithm(st->st_oakley.hasher->algo_id);
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));
hasher->get_hash(hasher, iv_chunk, NULL);
hasher->get_hash(hasher, msgid_chunk, st->st_new_iv);
hasher->destroy(hasher);
h->hash_init(&ctx);
h->hash_update(&ctx, st->st_ph1_iv, st->st_ph1_iv_len);
passert(*msgid != 0);
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:"
, st->st_new_iv, st->st_new_iv_len);
DBG_cond_dump(DBG_CRYPT, "computed Phase 2 IV:",
st->st_new_iv, st->st_new_iv_len);
}
/* Initiate quick mode.
@ -2872,62 +2860,68 @@ static void compute_proto_keymat(struct state *st, u_int8_t protoid,
pi->keymat_len = needed_len;
/* Allocate space for the keying material.
* Although only needed_len bytes are desired, we
* must round up to a multiple of ctx.hmac_digest_size
/* Allocate space for the keying material. Although only needed_len bytes
* are desired, we must round up to a multiple of hash_size
* 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 i;
size_t needed_space; /* space needed for keying material (rounded up) */
size_t i, prf_block_size;
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);
ctx_peer = ctx_me; /* duplicate initial conditions */
prf_alg = oakley_to_prf(st->st_oakley.hasher->algo_id);
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->peer_keymat, malloc(needed_space));
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)
{
/* PFS: include the g^xy */
hmac_update_chunk(&ctx_me, st->st_shared);
hmac_update_chunk(&ctx_peer, st->st_shared);
prf_our->get_bytes(prf_our, st->st_shared, NULL);
prf_peer->get_bytes(prf_peer, st->st_shared, NULL);
}
hmac_update(&ctx_me, &protoid, sizeof(protoid));
hmac_update(&ctx_peer, &protoid, sizeof(protoid));
prf_our->get_bytes(prf_our, protoid_chunk, NULL);
prf_peer->get_bytes(prf_peer, protoid_chunk, NULL);
hmac_update(&ctx_me, (u_char *)&pi->our_spi, sizeof(pi->our_spi));
hmac_update(&ctx_peer, (u_char *)&pi->attrs.spi, sizeof(pi->attrs.spi));
prf_our->get_bytes(prf_our, spi_our, NULL);
prf_peer->get_bytes(prf_peer, spi_peer, NULL);
hmac_update_chunk(&ctx_me, st->st_ni);
hmac_update_chunk(&ctx_peer, st->st_ni);
prf_our->get_bytes(prf_our, st->st_ni, NULL);
prf_peer->get_bytes(prf_peer, st->st_ni, NULL);
hmac_update_chunk(&ctx_me, st->st_nr);
hmac_update_chunk(&ctx_peer, st->st_nr);
prf_our->get_bytes(prf_our, st->st_nr, keymat_i_our);
prf_peer->get_bytes(prf_peer, st->st_nr, keymat_i_peer);
hmac_final(pi->our_keymat + i, &ctx_me);
hmac_final(pi->peer_keymat + i, &ctx_peer);
i += ctx_me.hmac_digest_size;
i += prf_block_size;
if (i >= needed_space)
{
break;
}
/* more keying material needed: prepare to go around again */
hmac_reinit(&ctx_me);
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->get_bytes(prf_our, keymat_our, NULL);
prf_peer->get_bytes(prf_peer, keymat_peer, NULL);
}
prf_our->destroy(prf_our);
prf_peer->destroy(prf_peer);
}
DBG(DBG_CRYPT,
DBG_dump("KEYMAT computed:\n", pi->our_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).
* HDR;SA --> HDR;SA
*/
stf_status
main_inI1_outR1(struct msg_digest *md)
stf_status main_inI1_outR1(struct msg_digest *md)
{
struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA];
struct state *st;
@ -5268,15 +5261,22 @@ static stf_status send_isakmp_notification(struct state *st, u_int16_t type,
{
/* finish computing HASH */
struct hmac_ctx ctx;
hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a);
hmac_update(&ctx, (const u_char *) &msgid, sizeof(msgid_t));
hmac_update(&ctx, r_hash_start, rbody.cur-r_hash_start);
hmac_final(r_hashval, &ctx);
chunk_t msgid_chunk = chunk_from_thing(msgid);
chunk_t msg_chunk = { r_hash_start, rbody.cur-r_hash_start };
pseudo_random_function_t prf_alg;
prf_t *prf;
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_log("HASH computed:");
DBG_dump("", r_hashval, ctx.hmac_digest_size));
DBG_log("HASH computed:");
DBG_dump("", r_hashval, prf->get_block_size(prf));
)
prf->destroy(prf);
}
/* Encrypt message (preserve st_iv and st_new_iv) */

View File

@ -24,7 +24,9 @@
#include <string.h>
#include <freeswan.h>
#include <library.h>
#include <crypto/prfs/prf.h>
#include "constants.h"
#include "defs.h"
@ -241,22 +243,28 @@ set_internal_addr(struct connection *c, internal_addr_t *ia)
/*
* Compute HASH of Mode Config.
*/
static size_t
modecfg_hash(u_char *dest, const u_char *start, const u_char *roof
, const struct state *st)
static size_t modecfg_hash(u_char *dest, u_char *start, u_char *roof,
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);
hmac_update(&ctx, (const u_char *) &st->st_msgid, sizeof(st->st_msgid));
hmac_update(&ctx, start, roof-start);
hmac_final(dest, &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, dest);
prf_block_size = prf->get_block_size(prf);
prf->destroy(prf);
DBG(DBG_CRYPT,
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;
}

View File

@ -28,6 +28,9 @@
#include <pfkeyv2.h>
#include <pfkey.h>
#include <library.h>
#include <crypto/hashers/hasher.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
@ -102,16 +105,18 @@ static void disable_nat_traversal (int type)
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,
const ip_address *ip, u_int16_t port)
{
union hash_ctx ctx;
if (is_zero_cookie(icookie))
{
DBG_log("_natd_hash: Warning, icookie is zero !!");
}
if (is_zero_cookie(rcookie))
{
DBG_log("_natd_hash: Warning, rcookie is zero !!");
}
/**
* 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
*/
hasher->hash_init(&ctx);
hasher->hash_update(&ctx, icookie, COOKIE_SIZE);
hasher->hash_update(&ctx, rcookie, COOKIE_SIZE);
switch (addrtypeof(ip)) {
case AF_INET:
hasher->hash_update(&ctx, (const u_char *)&ip->u.v4.sin_addr.s_addr
, sizeof(ip->u.v4.sin_addr.s_addr));
break;
case AF_INET6:
hasher->hash_update(&ctx, (const u_char *)&ip->u.v6.sin6_addr.s6_addr
, sizeof(ip->u.v6.sin6_addr.s6_addr));
break;
}
hasher->hash_update(&ctx, (const u_char *)&port, sizeof(u_int16_t));
hasher->hash_final(hash, &ctx);
#ifdef NAT_D_DEBUG
DBG(DBG_NATT,
DBG_log("_natd_hash: hasher=%p(%d)", hasher, (int)hasher->hash_digest_len);
DBG_dump("_natd_hash: icookie=", icookie, COOKIE_SIZE);
DBG_dump("_natd_hash: rcookie=", rcookie, COOKIE_SIZE);
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;
{
chunk_t icookie_chunk = { icookie, COOKIE_SIZE };
chunk_t rcookie_chunk = { rcookie, COOKIE_SIZE };
chunk_t port_chunk = chunk_from_thing(port);
chunk_t addr_chunk;
hash_algorithm_t hash_alg;
hasher_t *hasher;
size_t hash_size;
hash_alg = oakley_to_hash_algorithm(oakley_hasher->algo_id);
hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
hasher->get_hash(hasher, icookie_chunk, NULL);
hasher->get_hash(hasher, rcookie_chunk, NULL);
switch (addrtypeof(ip))
{
case AF_INET:
addr_chunk = chunk_from_thing(ip->u.v4.sin_addr.s_addr);
break;
case AF_INET6:
addr_chunk = chunk_from_thing(ip->u.v6.sin6_addr.s6_addr);
}
DBG_log("_natd_hash: port=%d", port);
DBG_dump("_natd_hash: hash=", hash, hasher->hash_digest_len);
);
hasher->get_hash(hasher, addr_chunk, NULL);
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
}
}
/* Add NAT-Traversal VIDs (supported ones)