static void natd_hash(const struct hash_desc *hasher, unsigned char *hash, const u_int8_t *icookie, const u_int8_t *rcookie, const ip_address *ip, u_int16_t port /* host order */) { union hash_ctx ctx; if (is_zero_cookie(icookie)) DBG(DBG_NATT, DBG_log("natd_hash: Warning, icookie is zero !!")); if (is_zero_cookie(rcookie)) DBG(DBG_NATT, DBG_log("natd_hash: Warning, rcookie is zero !!")); /* * RFC 3947 * * HASH = HASH(CKY-I | CKY-R | IP | Port) * * 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; } { u_int16_t netorder_port = htons(port); hasher->hash_update(&ctx, (const u_char *)&netorder_port, sizeof(netorder_port)); } hasher->hash_final(hash, &ctx); 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; } DBG_log("natd_hash: port=%d", port); DBG_dump("natd_hash: hash=", hash, hasher->hash_digest_len); });
static void natd_hash(const struct hash_desc *hasher, unsigned char *hash, const u_int8_t *icookie, const u_int8_t *rcookie, const ip_address *ip, u_int16_t port /* host order */) { if (is_zero_cookie(icookie)) DBG(DBG_NATT, DBG_log("natd_hash: Warning, icookie is zero !!")); if (is_zero_cookie(rcookie)) DBG(DBG_NATT, DBG_log("natd_hash: Warning, rcookie is zero !!")); /* * RFC 3947 * * HASH = HASH(CKY-I | CKY-R | IP | Port) * * All values in network order */ struct crypt_hash *ctx = crypt_hash_init(hasher, "NATD", DBG_CRYPT); crypt_hash_digest_bytes(ctx, "ICOOKIE", icookie, COOKIE_SIZE); crypt_hash_digest_bytes(ctx, "RCOOKIE", rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: crypt_hash_digest_bytes(ctx, "SIN_ADDR", (const u_char *)&ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; case AF_INET6: crypt_hash_digest_bytes(ctx, "SIN6_ADDR", (const u_char *)&ip->u.v6.sin6_addr.s6_addr, sizeof(ip->u.v6.sin6_addr.s6_addr)); break; } { u_int16_t netorder_port = htons(port); crypt_hash_digest_bytes(ctx, "PORT", &netorder_port, sizeof(netorder_port)); } crypt_hash_final_bytes(&ctx, hash, hasher->hash_digest_len); 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; } DBG_log("natd_hash: port=%d", port); DBG_dump("natd_hash: hash=", hash, hasher->hash_digest_len); });
static void _natd_hash(const struct hash_desc *hasher, unsigned 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 * * HASH = HASH(CKY-I | CKY-R | IP | Port) * * 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; } DBG_log("_natd_hash: port=%d", ntohs(port)); DBG_dump("_natd_hash: hash=", hash, hasher->hash_digest_len); );
/* * Generate a cookie (aka SPI) * First argument is true if we're to create an Initiator cookie. * Length SHOULD be a multiple of sizeof(u_int32_t). * * As responder, we use a hashing method to get a pseudo random * value instead of using our own random pool. It will prevent * an attacker from gaining raw data from our random pool and * it will prevent an attacker from depleting our random pool * or entropy. */ void get_cookie(bool initiator, u_int8_t cookie[COOKIE_SIZE], const ip_address *addr) { do { if (initiator) { get_rnd_bytes(cookie, COOKIE_SIZE); } else { static u_int32_t counter = 0; /* STATIC */ unsigned char addr_buff[ sizeof(union { struct in_addr A; struct in6_addr B; })]; u_char buffer[SHA2_256_DIGEST_SIZE]; sha256_context ctx; size_t addr_length = addrbytesof(addr, addr_buff, sizeof(addr_buff)); sha256_init(&ctx); sha256_write(&ctx, addr_buff, addr_length); sha256_write(&ctx, secret_of_the_day, sizeof(secret_of_the_day)); counter++; sha256_write(&ctx, (const void *) &counter, sizeof(counter)); sha256_final(buffer, &ctx); /* cookie size is smaller than any hash output sizes */ memcpy(cookie, buffer, COOKIE_SIZE); } } while (is_zero_cookie(cookie)); /* probably never loops */ }
/* Generate a cookie. * First argument is true if we're to create an Initiator cookie. * Length SHOULD be a multiple of sizeof(u_int32_t). */ void get_cookie(bool initiator, u_int8_t *cookie, int length, const ip_address *addr) { u_char buffer[SHA1_DIGEST_SIZE]; SHA1_CTX ctx; do { if (initiator) { get_rnd_bytes(cookie, length); } else /* Responder cookie */ { /* This looks as good as any way */ size_t addr_length; static u_int32_t counter = 0; unsigned char addr_buff[ sizeof(union {struct in_addr; struct in6_addr;})]; addr_length = addrbytesof(addr, addr_buff, sizeof(addr_buff)); SHA1Init(&ctx); SHA1Update(&ctx, addr_buff, addr_length); SHA1Update(&ctx, secret_of_the_day, sizeof(secret_of_the_day)); counter++; SHA1Update(&ctx, (const void *) &counter, sizeof(counter)); SHA1Final(buffer, &ctx); memcpy(cookie, buffer, length); } } while (is_zero_cookie(cookie)); /* probably never loops */ }
bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs, struct msg_digest *md) { char hash[MAX_DIGEST_LEN]; struct state *st = md->st; if (!out_modify_previous_np(ISAKMP_NEXT_NATD, outs)) return FALSE; if (!st || !st->st_oakley.hasher) { loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d", __FILE__, __LINE__); return FALSE; } /** * First one with sender IP & port */ _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie, &(md->sender), #ifdef FORCE_NAT_TRAVERSAL 0 #else ntohs(md->sender_port) #endif ); if (!out_generic_raw(ISAKMP_NEXT_NATD, &isakmp_nat_d, outs, hash, st->st_oakley.hasher->hash_digest_len, "NAT-D")) return FALSE; /** * Second one with my IP & port */ _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie, &(md->iface->addr), #ifdef FORCE_NAT_TRAVERSAL 0 #else ntohs(st->st_connection->this.host_port) #endif ); return (out_generic_raw(np, &isakmp_nat_d, outs, hash, st->st_oakley.hasher->hash_digest_len, "NAT-D")); }
/* Generate a cookie. * First argument is true if we're to create an Initiator cookie. * Length SHOULD be a multiple of sizeof(u_int32_t). */ void get_cookie(bool initiator, u_int8_t *cookie, int length, ip_address *addr) { hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); u_char buffer[HASH_SIZE_SHA1]; do { if (initiator) { rng_t *rng; rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); rng->get_bytes(rng, length, cookie); rng->destroy(rng); } else /* Responder cookie */ { chunk_t addr_chunk, secret_chunk, counter_chunk; size_t addr_len; static u_int32_t counter = 0; unsigned char addr_buf[ sizeof(union {struct in_addr A; struct in6_addr B;})]; addr_len = addrbytesof(addr, addr_buf, sizeof(addr_buf)); addr_chunk = chunk_create(addr_buf, addr_len); secret_chunk = chunk_create(secret_of_the_day, HASH_SIZE_SHA1); counter++; counter_chunk = chunk_create((void *) &counter, sizeof(counter)); hasher->get_hash(hasher, addr_chunk, NULL); hasher->get_hash(hasher, secret_chunk, NULL); hasher->get_hash(hasher, counter_chunk, buffer); memcpy(cookie, buffer, length); } } while (is_zero_cookie(cookie)); /* probably never loops */ hasher->destroy(hasher); }