/** creates a new hash chain * * @param hash_func hash function to be used to generate the hash values * @param hash_length length of the hash values * @param hchain_length number of hash elements * @param hchain_hierarchy the hierarchy level this hash chain will belong to * @param link_tree the link tree, if HHL is used * @return pointer to the newly created hash chain, NULL on error */ struct hash_chain *hchain_create(const hash_function hash_func, const int hash_length, const int hchain_length, const int hchain_hierarchy, struct hash_tree *link_tree) { struct hash_chain *hchain = NULL; /* the hash function output might be longer than needed * allocate enough memory for the hash function output * * @note we also allow a concatenation with the link tree root and the jump chain element here */ unsigned char hash_value[3 * MAX_HASH_LENGTH]; int hash_data_length = 0; int i, err = 0; HIP_ASSERT(hash_func != NULL); // make sure that the hash we want to use is smaller than the max output HIP_ASSERT(hash_length > 0 && hash_length <= MAX_HASH_LENGTH); HIP_ASSERT(hchain_length > 0); HIP_ASSERT(!(hchain_hierarchy == 0 && link_tree)); // allocate memory for a new hash chain HIP_IFEL(!(hchain = calloc(1, sizeof(struct hash_chain))), -1, "failed to allocate memory\n"); // allocate memory for the hash chain elements HIP_IFEL(!(hchain->elements = calloc(1, hash_length * hchain_length)), -1, "failed to allocate memory\n"); // set the link tree if we are using different hierarchies if (link_tree) { hchain->link_tree = link_tree; hash_data_length = 2 * hash_length; } else { hchain->link_tree = NULL; hash_data_length = hash_length; } for (i = 0; i < hchain_length; i++) { if (i > 0) { // (input, input_length, output) -> output_length == 20 HIP_IFEL(!(hash_func(hash_value, hash_data_length, hash_value)), -1, "failed to calculate hash\n"); // only consider highest bytes of digest with length of actual element memcpy(&hchain->elements[i * hash_length], hash_value, hash_length); } else { // random bytes as seed -> need a copy in hash_value for further computations HIP_IFEL(RAND_bytes(hash_value, hash_length) <= 0, -1, "failed to get random bytes for source element\n"); memcpy(&hchain->elements[i * hash_length], hash_value, hash_length); } /* concatenate used part of the calculated hash with the link tree root */ if (link_tree) { memcpy(&hash_value[hash_length], link_tree->root, link_tree->node_length); } } hchain->hash_function = hash_func; hchain->hash_length = hash_length; hchain->hchain_length = hchain_length; hchain->current_index = hchain_length; hchain->hchain_hierarchy = hchain_hierarchy; HIP_DEBUG("Hash-chain with %i elements of length %i created!\n", hchain_length, hash_length); out_err: if (err) { // hchain was fully created hchain_free(hchain); hchain = NULL; } return hchain; }
/* getter function for the hash chain anchor element * * @param hash_chain hash chain from which the anchor should be returned * @return anchor element of the given hash chain */ unsigned char *hchain_get_anchor(const struct hash_chain *hash_chain) { HIP_ASSERT(hash_chain); return hchain_element_by_index(hash_chain, hash_chain->hchain_length - 1); }
/* Moved function doxy descriptor to the header file. Lauri 11.03.2008 */ int hip_read_control_msg_all(int socket, struct hip_common *hip_msg, struct in6_addr *saddr, struct in6_addr *daddr, hip_portpair_t *msg_info, int encap_hdr_size, int is_ipv4) { struct sockaddr_storage addr_from, addr_to; struct sockaddr_in *addr_from4 = ((struct sockaddr_in *) &addr_from); struct sockaddr_in6 *addr_from6 = ((struct sockaddr_in6 *) &addr_from); struct cmsghdr *cmsg; struct msghdr msg; union { struct in_pktinfo *pktinfo_in4; struct inet6_pktinfo *pktinfo_in6; } pktinfo; struct iovec iov; char cbuff[CMSG_SPACE(256)]; int err = 0, len; int cmsg_level, cmsg_type; HIP_ASSERT(saddr); HIP_ASSERT(daddr); HIP_DEBUG("hip_read_control_msg_all() invoked.\n"); HIP_IFEL(((len = hip_peek_recv_total_len(socket, encap_hdr_size, HIP_DEFAULT_MSG_TIMEOUT))<= 0), -1, "Bad packet length (%d)\n", len); memset(msg_info, 0, sizeof(hip_portpair_t)); memset(&msg, 0, sizeof(msg)); memset(cbuff, 0, sizeof(cbuff)); memset(&addr_to, 0, sizeof(addr_to)); /* setup message header with control and receive buffers */ msg.msg_name = &addr_from; msg.msg_namelen = sizeof(struct sockaddr_storage); msg.msg_iov = &iov; msg.msg_iovlen = 1; memset(cbuff, 0, sizeof(cbuff)); msg.msg_control = cbuff; msg.msg_controllen = sizeof(cbuff); msg.msg_flags = 0; iov.iov_len = len; iov.iov_base = hip_msg; pktinfo.pktinfo_in4 = NULL; len = recvmsg(socket, &msg, 0); HIP_IFEL((len < 0), -1, "ICMP%s error: errno=%d, %s\n", (is_ipv4 ? "v4" : "v6"), errno, strerror(errno)); cmsg_level = (is_ipv4) ? IPPROTO_IP : IPPROTO_IPV6; cmsg_type = (is_ipv4) ? IP_PKTINFO : IPV6_2292PKTINFO; /* destination address comes from ancillary data passed * with msg due to IPV6_PKTINFO socket option */ for (cmsg=CMSG_FIRSTHDR(&msg); cmsg; cmsg=CMSG_NXTHDR(&msg,cmsg)){ if ((cmsg->cmsg_level == cmsg_level) && (cmsg->cmsg_type == cmsg_type)) { /* The structure is a union, so this fills also the pktinfo_in6 pointer */ pktinfo.pktinfo_in4 = (struct in_pktinfo*)CMSG_DATA(cmsg); break; } } /* If this fails, change IPV6_2292PKTINFO to IPV6_PKTINFO in hip_init_raw_sock_v6 */ HIP_IFEL(!pktinfo.pktinfo_in4, -1, "Could not determine dst addr, dropping\n"); /* UDP port numbers */ if (is_ipv4 && encap_hdr_size == HIP_UDP_ZERO_BYTES_LEN) { HIP_DEBUG("hip_read_control_msg_all() source port = %d\n", ntohs(addr_from4->sin_port)); msg_info->src_port = ntohs(addr_from4->sin_port); /* Destination port is known from the bound socket. */ msg_info->dst_port = hip_get_local_nat_udp_port(); } /* IPv4 addresses */ if (is_ipv4) { struct sockaddr_in *addr_to4 = (struct sockaddr_in *) &addr_to; IPV4_TO_IPV6_MAP(&addr_from4->sin_addr, saddr); IPV4_TO_IPV6_MAP(&pktinfo.pktinfo_in4->ipi_addr, daddr); addr_to4->sin_family = AF_INET; addr_to4->sin_addr = pktinfo.pktinfo_in4->ipi_addr; addr_to4->sin_port = msg_info->dst_port; } else /* IPv6 addresses */ { struct sockaddr_in6 *addr_to6 = (struct sockaddr_in6 *) &addr_to; memcpy(saddr, &addr_from6->sin6_addr, sizeof(struct in6_addr)); memcpy(daddr, &pktinfo.pktinfo_in6->ipi6_addr, sizeof(struct in6_addr)); addr_to6->sin6_family = AF_INET6; ipv6_addr_copy(&addr_to6->sin6_addr, daddr); } //added by santtu if (hip_read_control_msg_plugin_handler(hip_msg,len, saddr,msg_info->src_port)) goto out_err; //endadd if (is_ipv4 && (encap_hdr_size == IPV4_HDR_SIZE)) {/* raw IPv4, !UDP */ /* For some reason, the IPv4 header is always included. Let's remove it here. */ memmove(hip_msg, ((char *)hip_msg) + IPV4_HDR_SIZE, HIP_MAX_PACKET - IPV4_HDR_SIZE); } else if (is_ipv4 && encap_hdr_size == HIP_UDP_ZERO_BYTES_LEN) { /* remove 32-bits of zeroes between UDP and HIP headers */ memmove(hip_msg, ((char *)hip_msg) + HIP_UDP_ZERO_BYTES_LEN, HIP_MAX_PACKET - HIP_UDP_ZERO_BYTES_LEN); } HIP_IFEL(hip_verify_network_header(hip_msg, (struct sockaddr *) &addr_from, (struct sockaddr *) &addr_to, len - encap_hdr_size), -1, "verifying network header failed\n"); if (saddr) HIP_DEBUG_IN6ADDR("src", saddr); if (daddr) HIP_DEBUG_IN6ADDR("dst", daddr); out_err: return err; }
/** * Translate and reinject an incoming packet back to the networking stack. * Supports TCP, UDP and ICMP. LSI code uses this to translate * the HITs from an incoming packet to the corresponding LSIs. Also, * the system-based opportunistic mode uses this to translate the HITs of * an incoming packet to an IPv4 or IPv6 address. * * @param src_hit source HIT of the packet * @param dst_hit destination HIT of the packet * @param msg a pointer to the transport layer header of the packet * @param len the length of the packet in bytes * @param proto the transport layer protocol of the packet * @param ttl new ttl value for the transformed packet * * @return zero on success and non-zero on error */ int hip_firewall_send_incoming_pkt(const struct in6_addr *src_hit, const struct in6_addr *dst_hit, uint8_t *msg, uint16_t len, int proto, int ttl) { int err = 0, sent, sa_size; int firewall_raw_sock = 0, is_ipv6 = 0, on = 1; struct ip *iphdr = NULL; struct udphdr *udp = NULL; struct tcphdr *tcp = NULL; struct icmphdr *icmp = NULL; struct sockaddr_storage src = { 0 }, dst = { 0 }; struct sockaddr_in6 *sock_src6 = NULL, *sock_dst6 = NULL; struct sockaddr_in *sock_src4 = NULL, *sock_dst4 = NULL; struct in6_addr any = IN6ADDR_ANY_INIT; HIP_ASSERT(src_hit != NULL && dst_hit != NULL); sock_src4 = (struct sockaddr_in *) &src; sock_dst4 = (struct sockaddr_in *) &dst; sock_src6 = (struct sockaddr_in6 *) &src; sock_dst6 = (struct sockaddr_in6 *) &dst; if (IN6_IS_ADDR_V4MAPPED(src_hit)) { sock_src4->sin_family = AF_INET; sock_dst4->sin_family = AF_INET; IPV6_TO_IPV4_MAP(src_hit, &sock_src4->sin_addr); IPV6_TO_IPV4_MAP(dst_hit, &sock_dst4->sin_addr); sa_size = sizeof(struct sockaddr_in); HIP_DEBUG_LSI("src4 addr ", &sock_src4->sin_addr); HIP_DEBUG_LSI("dst4 addr ", &sock_dst4->sin_addr); } else { sock_src6->sin6_family = AF_INET6; ipv6_addr_copy(&sock_src6->sin6_addr, src_hit); sock_dst6->sin6_family = AF_INET6; ipv6_addr_copy(&sock_dst6->sin6_addr, dst_hit); sa_size = sizeof(struct sockaddr_in6); is_ipv6 = 1; } switch (proto) { case IPPROTO_UDP: if (is_ipv6) { HIP_DEBUG(" IPPROTO_UDP v6\n"); firewall_raw_sock = firewall_raw_sock_udp_v6; ((struct udphdr *) msg)->check = ipv6_checksum(IPPROTO_UDP, &sock_src6->sin6_addr, &sock_dst6->sin6_addr, msg, len); } else { HIP_DEBUG(" IPPROTO_UDP v4\n"); firewall_raw_sock = firewall_raw_sock_udp_v4; udp = (struct udphdr *) msg; sa_size = sizeof(struct sockaddr_in); udp->check = htons(0); udp->check = ipv4_checksum(IPPROTO_UDP, (uint8_t *) &sock_src4->sin_addr, (uint8_t *) &sock_dst4->sin_addr, (uint8_t *) udp, len); memmove(msg + sizeof(struct ip), udp, len); } break; case IPPROTO_TCP: tcp = (struct tcphdr *) msg; tcp->check = htons(0); if (is_ipv6) { HIP_DEBUG(" IPPROTO_TCP v6\n"); firewall_raw_sock = firewall_raw_sock_tcp_v6; tcp->check = ipv6_checksum(IPPROTO_TCP, &sock_src6->sin6_addr, &sock_dst6->sin6_addr, msg, len); } else { HIP_DEBUG(" IPPROTO_TCP v4\n"); firewall_raw_sock = firewall_raw_sock_tcp_v4; tcp->check = ipv4_checksum(IPPROTO_TCP, (uint8_t *) &sock_src4->sin_addr, (uint8_t *) &sock_dst4->sin_addr, (uint8_t *) tcp, len); memmove(msg + sizeof(struct ip), tcp, len); } break; case IPPROTO_ICMP: firewall_raw_sock = firewall_raw_sock_icmp_v4; icmp = (struct icmphdr *) msg; icmp->checksum = htons(0); icmp->checksum = inchksum(icmp, len); memmove(msg + sizeof(struct ip), icmp, len); break; case IPPROTO_ICMPV6: goto not_sending; break; default: HIP_ERROR("No protocol family found\n"); break; } if (!is_ipv6) { iphdr = (struct ip *) msg; iphdr->ip_v = 4; iphdr->ip_hl = sizeof(struct ip) >> 2; iphdr->ip_tos = 0; iphdr->ip_len = len + iphdr->ip_hl * 4; iphdr->ip_id = htons(0); iphdr->ip_off = 0; iphdr->ip_ttl = ttl; iphdr->ip_p = proto; iphdr->ip_src = sock_src4->sin_addr; iphdr->ip_dst = sock_dst4->sin_addr; iphdr->ip_sum = htons(0); /* @todo: move the socket option to fw initialization */ if (setsockopt(firewall_raw_sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on))) { HIP_IFEL(err, -1, "setsockopt IP_HDRINCL ERROR\n"); } sent = sendto(firewall_raw_sock, iphdr, iphdr->ip_len, 0, (struct sockaddr *) &dst, sa_size); if (sent != (int) (len + sizeof(struct ip))) { HIP_ERROR("Could not send the all requested" \ " data (%d/%d)\n", sent, iphdr->ip_len); } else { HIP_DEBUG("sent=%d/%d \n", sent, (len + sizeof(struct ip))); HIP_DEBUG("Packet sent ok\n"); } }
/** * firewall_cache_db_match: * Search in the cache database the given peers of hits, lsis or ips */ int firewall_cache_db_match( struct in6_addr *hit_our, struct in6_addr *hit_peer, hip_lsi_t *lsi_our, hip_lsi_t *lsi_peer, struct in6_addr *ip_our, struct in6_addr *ip_peer, int *state){ int i, err = 0, entry_in_cache = 0; firewall_cache_hl_t *this; hip_list_t *item, *tmp; struct in6_addr all_zero_v6 = {0}; struct in_addr all_zero_v4 = {0}; struct hip_common *msg = NULL; firewall_cache_hl_t *ha_curr = NULL; firewall_cache_hl_t *ha_match = NULL; struct hip_tlv_common *current_param = NULL; HIP_ASSERT( (hit_our && hit_peer) || (lsi_our && lsi_peer) ); if(hit_peer){ ha_match = (firewall_cache_hl_t *)hip_ht_find( firewall_cache_db, (void *)hit_peer); if(ha_match){ HIP_DEBUG("Matched using hash\n"); entry_in_cache = 1; goto out_err; } } HIP_DEBUG("Check firewall cache db\n"); HIP_LOCK_HT(&firewall_cache_db); list_for_each_safe(item, tmp, firewall_cache_db, i){ this = list_entry(item); if( lsi_our && lsi_peer) { HIP_DEBUG_INADDR("this->our", &this->lsi_our.s_addr); HIP_DEBUG_INADDR("this->peer", &this->lsi_peer.s_addr); HIP_DEBUG_INADDR("our", lsi_our); HIP_DEBUG_INADDR("peer", lsi_peer); } if( hit_our && hit_peer && (ipv6_addr_cmp(hit_peer, &this->hit_peer) == 0 ) && (ipv6_addr_cmp(hit_our, &this->hit_our) == 0 ) ){ ha_match = this; break; } if( lsi_our && lsi_peer && lsi_peer->s_addr == this->lsi_peer.s_addr && lsi_our->s_addr == this->lsi_our.s_addr ){ ha_match = this; break; } if( ip_our && ip_peer && ip_peer->s6_addr == this->ip_peer.s6_addr && ip_our->s6_addr == this->ip_our.s6_addr ) { ha_match = this; break; } }
static int send_raw_from_one_src(const struct in6_addr *local_addr, const struct in6_addr *peer_addr, const in_port_t src_port, const in_port_t dst_port, struct hip_common *msg) { int err = 0, sa_size, sent, len = 0, dupl, try_again, udp = 0; struct sockaddr_storage src, dst; int src_is_ipv4 = 0, dst_is_ipv4 = 0, memmoved = 0; struct sockaddr_in6 *src6 = NULL, *dst6 = NULL; struct sockaddr_in *src4 = NULL, *dst4 = NULL; struct in6_addr my_addr; /* Points either to v4 or v6 raw sock */ int hipfw_raw_sock_output = 0; /* Verify the existence of obligatory parameters. */ HIP_ASSERT(peer_addr != NULL && msg != NULL); HIP_DEBUG("Sending %s packet\n", hip_message_type_name(hip_get_msg_type(msg))); HIP_DEBUG_IN6ADDR("hip_send_raw(): local_addr", local_addr); HIP_DEBUG_IN6ADDR("hip_send_raw(): peer_addr", peer_addr); HIP_DEBUG("Source port=%d, destination port=%d\n", src_port, dst_port); HIP_DUMP_MSG(msg); //check msg length if (!hip_check_network_msg_len(msg)) { err = -EMSGSIZE; HIP_ERROR("bad msg len %d\n", hip_get_msg_total_len(msg)); goto out_err; } dst_is_ipv4 = IN6_IS_ADDR_V4MAPPED(peer_addr); len = hip_get_msg_total_len(msg); /* Some convinient short-hands to avoid too much casting (could be * an union as well) */ src6 = (struct sockaddr_in6 *) &src; dst6 = (struct sockaddr_in6 *) &dst; src4 = (struct sockaddr_in *) &src; dst4 = (struct sockaddr_in *) &dst; memset(&src, 0, sizeof(src)); memset(&dst, 0, sizeof(dst)); if (dst_port && dst_is_ipv4) { HIP_DEBUG("Using IPv4 UDP socket\n"); hipfw_raw_sock_output = hipfw_nat_sock_output_udp; sa_size = sizeof(struct sockaddr_in); udp = 1; } else if (dst_is_ipv4) { HIP_DEBUG("Using IPv4 raw socket\n"); //hipfw_raw_sock_output = hipfw_raw_sock_output_v4; //sa_size = sizeof(struct sockaddr_in); } else { HIP_DEBUG("Using IPv6 raw socket\n"); //hipfw_raw_sock_output = hipfw_raw_sock_output_v6; //sa_size = sizeof(struct sockaddr_in6); } if (local_addr) { HIP_DEBUG("local address given\n"); memcpy(&my_addr, local_addr, sizeof(struct in6_addr)); } else { HIP_DEBUG("no local address, selecting one\n"); HIP_IFEL(select_source_address(&my_addr, peer_addr), -1, "Cannot find source address\n"); } src_is_ipv4 = IN6_IS_ADDR_V4MAPPED(&my_addr); if (src_is_ipv4) { IPV6_TO_IPV4_MAP(&my_addr, &src4->sin_addr); src4->sin_family = AF_INET; HIP_DEBUG_INADDR("src4", &src4->sin_addr); } else { memcpy(&src6->sin6_addr, &my_addr, sizeof(struct in6_addr)); src6->sin6_family = AF_INET6; HIP_DEBUG_IN6ADDR("src6", &src6->sin6_addr); } if (dst_is_ipv4) { IPV6_TO_IPV4_MAP(peer_addr, &dst4->sin_addr); dst4->sin_family = AF_INET; HIP_DEBUG_INADDR("dst4", &dst4->sin_addr); } else { memcpy(&dst6->sin6_addr, peer_addr, sizeof(struct in6_addr)); dst6->sin6_family = AF_INET6; HIP_DEBUG_IN6ADDR("dst6", &dst6->sin6_addr); } if (src6->sin6_family != dst6->sin6_family) { /* @todo: Check if this may cause any trouble. * It happens every time we send update packet that contains few locators in msg, one is * the IPv4 address of the source, another is IPv6 address of the source. But even if one of * them is ok to send raw IPvX to IPvX raw packet, another one cause the trouble, and all * updates are dropped. by Andrey "laser". * */ err = -1; HIP_ERROR("Source and destination address families differ\n"); goto out_err; } hip_zero_msg_checksum(msg); if (!udp) { msg->checksum = hip_checksum_packet((char *) msg, (struct sockaddr *) &src, (struct sockaddr *) &dst); } /* Handover may cause e.g. on-link duplicate address detection * which may cause bind to fail. */ HIP_IFEL(bind(hipfw_raw_sock_output, (struct sockaddr *) &src, sa_size), -1, "Binding to raw sock failed\n"); /* For some reason, neither sendmsg or send (with bind+connect) * do not seem to work properly. Thus, we use just sendto() */ len = hip_get_msg_total_len(msg); if (udp) { struct udphdr *uh = (struct udphdr *) msg; /* Insert 32 bits of zero bytes between UDP and HIP */ memmove(((char *) msg) + HIP_UDP_ZERO_BYTES_LEN + sizeof(struct udphdr), msg, len); memset(((char *) msg), 0, HIP_UDP_ZERO_BYTES_LEN + sizeof(struct udphdr)); len += HIP_UDP_ZERO_BYTES_LEN + sizeof(struct udphdr); uh->source = htons(src_port); uh->dest = htons(dst_port); uh->len = htons(len); uh->check = 0; memmoved = 1; } for (dupl = 0; dupl < 1; dupl++) { for (try_again = 0; try_again < 2; try_again++) { sent = sendto(hipfw_raw_sock_output, msg, len, 0, (struct sockaddr *) &dst, sa_size); if (sent != len) { HIP_ERROR("Could not send the all requested" \ " data (%d/%d)\n", sent, len); HIP_DEBUG("strerror %s\n", strerror(errno)); sleep(2); } else { HIP_DEBUG("sent=%d/%d ipv4=%d\n", sent, len, dst_is_ipv4); HIP_DEBUG("Packet sent ok\n"); break; } } } out_err: /* Reset the interface to wildcard or otherwise receiving * broadcast messages fails from the raw sockets. A better * solution would be to have separate sockets for sending * and receiving because we cannot receive a broadcast while * sending */ if (dst_is_ipv4) { src4->sin_addr.s_addr = INADDR_ANY; src4->sin_family = AF_INET; sa_size = sizeof(struct sockaddr_in); } else { struct in6_addr any = IN6ADDR_ANY_INIT; src6->sin6_family = AF_INET6; ipv6_addr_copy(&src6->sin6_addr, &any); sa_size = sizeof(struct sockaddr_in6); } bind(hipfw_raw_sock_output, (struct sockaddr *) &src, sa_size); if (udp && memmoved) { /* Remove 32 bits of zero bytes between UDP and HIP */ len -= HIP_UDP_ZERO_BYTES_LEN + sizeof(struct udphdr); memmove((char *) msg, ((char *) msg) + HIP_UDP_ZERO_BYTES_LEN + sizeof(struct udphdr), len); memset(((char *) msg) + len, 0, HIP_UDP_ZERO_BYTES_LEN + sizeof(struct udphdr)); } if (err) { HIP_ERROR("strerror: %s\n", strerror(errno)); } return err; }
/** * generate HIP keying material * @param kij Diffie-Hellman Kij (as in the HIP drafts) * @param kij_len the length of the Kij material * @param keymat pointer to a keymat structure which will be updated according * to the generated keymaterial * @param dstbuf the generated keymaterial will be written here * @param dstbuflen the length of the buffer to which to write to * @param hit1 source HIT * @param hit2 destination HIT * @param calc_index where the one byte index is stored (n of Kn) * @param I the I value * @param J the J value * */ void hip_make_keymat(char *kij, size_t kij_len, struct hip_keymat_keymat *keymat, void *dstbuf, size_t dstbuflen, struct in6_addr *hit1, struct in6_addr *hit2, uint8_t *calc_index, const uint8_t I[PUZZLE_LENGTH], const uint8_t J[PUZZLE_LENGTH]) { int bufsize; uint8_t index_nbr = 1; size_t dstoffset = 0; void *seedkey; struct in6_addr *smaller_hit, *bigger_hit; int hit1_is_bigger; uint8_t *shabuffer = NULL; HIP_DEBUG("\n"); if (dstbuflen < HIP_AH_SHA_LEN) { HIP_ERROR("dstbuf is too short (%d)\n", dstbuflen); return; } HIP_ASSERT(sizeof(index_nbr) == HIP_KEYMAT_INDEX_NBR_SIZE); hit1_is_bigger = hip_hit_is_bigger(hit1, hit2); bigger_hit = hit1_is_bigger ? hit1 : hit2; smaller_hit = hit1_is_bigger ? hit2 : hit1; shabuffer = hip_create_keymat_buffer(kij, kij_len, HIP_AH_SHA_LEN, smaller_hit, bigger_hit, I, J); if (!shabuffer) { HIP_ERROR("No memory for keymat\n"); return; } bufsize = kij_len + 2 * sizeof(struct in6_addr) + 2 * sizeof(uint64_t) + 1; // XX FIXME: is this correct hip_build_digest(HIP_DIGEST_SHA1, shabuffer, bufsize, dstbuf); dstoffset = HIP_AH_SHA_LEN; index_nbr++; /* * K2 = SHA1(Kij | K1 | 2) * K3 = SHA1(Kij | K2 | 3) * ... */ seedkey = dstbuf; hip_update_keymat_buffer(shabuffer, seedkey, HIP_AH_SHA_LEN, kij_len, index_nbr); while (dstoffset < dstbuflen) { hip_build_digest(HIP_DIGEST_SHA1, shabuffer, kij_len + HIP_AH_SHA_LEN + 1, (uint8_t *) dstbuf + dstoffset); seedkey = (uint8_t *) dstbuf + dstoffset; dstoffset += HIP_AH_SHA_LEN; index_nbr++; hip_update_keymat_buffer(shabuffer, seedkey, HIP_AH_SHA_LEN, kij_len, index_nbr); } keymat->offset = 0; keymat->keymatlen = dstoffset; keymat->keymatdst = dstbuf; if (calc_index) { *calc_index = index_nbr; } else { HIP_ERROR("NULL calc_index\n"); } free(shabuffer); }
/** * hip_make_keymat - generate HIP keying material * @param kij Diffie-Hellman Kij (as in the HIP drafts) * @param kij_len the length of the Kij material * @param keymat pointer to a keymat structure which will be updated according * to the generated keymaterial * @param dstbuf the generated keymaterial will be written here * @param hit1 source HIT * @param hit2 destination HIT * @param calc_index where the one byte index is stored (n of Kn) * */ void hip_make_keymat(char *kij, size_t kij_len, struct hip_keymat_keymat *keymat, void *dstbuf, size_t dstbuflen, struct in6_addr *hit1, struct in6_addr *hit2, u8 *calc_index, uint64_t I, uint64_t J) { int bufsize, err = 0; uint8_t index_nbr = 1; int dstoffset = 0; void *seedkey; struct in6_addr *smaller_hit, *bigger_hit; int hit1_is_bigger; u8 *shabuffer = NULL; HIP_DEBUG("\n"); if (dstbuflen < HIP_AH_SHA_LEN) { HIP_ERROR("dstbuf is too short (%d)\n", dstbuflen); return; } _HIP_ASSERT(dstbuflen % 32 == 0); HIP_ASSERT(sizeof(index_nbr) == HIP_KEYMAT_INDEX_NBR_SIZE); hit1_is_bigger = hip_hit_is_bigger(hit1, hit2); bigger_hit = hit1_is_bigger ? hit1 : hit2; smaller_hit = hit1_is_bigger ? hit2 : hit1; _HIP_HEXDUMP("kij", kij, kij_len); _HIP_DEBUG("I=0x%llx J=0x%llx\n", I, J); _HIP_HEXDUMP("bigger hit", bigger_hit, 16); _HIP_HEXDUMP("smaller hit", smaller_hit, 16); _HIP_HEXDUMP("index_nbr", (char *) &index_nbr, HIP_KEYMAT_INDEX_NBR_SIZE); shabuffer = hip_create_keymat_buffer(kij, kij_len, HIP_AH_SHA_LEN, smaller_hit, bigger_hit, I, J); if (!shabuffer) { HIP_ERROR("No memory for keymat\n"); return; } bufsize = kij_len + 2 * sizeof(struct in6_addr) + 2 * sizeof(uint64_t) + 1; //bufsize = kij_len+2*sizeof(struct in6_addr)+ 1; // XX FIXME: is this correct hip_build_digest(HIP_DIGEST_SHA1, shabuffer, bufsize, dstbuf); _HIP_HEXDUMP("keymat digest", dstbuf, HIP_AH_SHA_LEN); dstoffset = HIP_AH_SHA_LEN; index_nbr++; /* * K2 = SHA1(Kij | K1 | 2) * K3 = SHA1(Kij | K2 | 3) * ... */ seedkey = dstbuf; hip_update_keymat_buffer(shabuffer, seedkey, HIP_AH_SHA_LEN, kij_len, index_nbr); while (dstoffset < dstbuflen) { hip_build_digest(HIP_DIGEST_SHA1, shabuffer, kij_len + HIP_AH_SHA_LEN + 1, dstbuf + dstoffset); seedkey = dstbuf + dstoffset; dstoffset += HIP_AH_SHA_LEN; index_nbr++; hip_update_keymat_buffer(shabuffer, seedkey, HIP_AH_SHA_LEN, kij_len, index_nbr); } keymat->offset = 0; keymat->keymatlen = dstoffset; keymat->keymatdst = dstbuf; if (calc_index) *calc_index = index_nbr; else HIP_ERROR("NULL calc_index\n"); _HIP_DEBUG("keymat index_nbr=%u\n", index_nbr); _HIP_HEXDUMP("GENERATED KEYMAT: ", dstbuf, dstbuflen); if (shabuffer) HIP_FREE(shabuffer); return; }
/** handles a user-message sent by the firewall when the bex-store is updated * * @param msg the user-message sent by fw * @return 0 if ok, != 0 else */ int anchor_db_update(const struct hip_common *msg) { const struct hip_tlv_common *param = NULL; const unsigned char *anchor = NULL; int err = 0, i, j; uint8_t esp_transforms[MAX_NUM_TRANSFORMS]; HIP_ASSERT(msg != NULL); // if this function is called, the extension should be active if (esp_prot_active) { memset(esp_transforms, 0, MAX_NUM_TRANSFORMS * sizeof(uint8_t)); HIP_DEBUG("updating hchain anchorDB...\n"); /* XX TODO ineffcient -> only add non-existing elements instead of * uniniting and adding all elements again */ anchor_db_uninit(); /*** set up anchor_db.num_anchors and anchor_db.anchor_lengths ***/ // get first int value HIP_IFEL(!(param = hip_get_param(msg, HIP_PARAM_UINT)), -1, "parameter missing in user-message from fw\n"); // don't set up anything for UNUSED transform for (i = 0; i < esp_prot_num_transforms - 1; i++) { // needed for redirection to correct slot in anchor_db esp_transforms[i] = *(const uint8_t *) hip_get_param_contents_direct(param); HIP_DEBUG("esp_transform is %u\n", esp_transforms[i]); HIP_IFEL(!(param = hip_get_next_param(msg, param)), -1, "parameter missing in user-message from fw\n"); anchor_db.num_anchors[esp_transforms[i]] = *(const int *) hip_get_param_contents_direct(param); HIP_DEBUG("num_anchors is %i\n", anchor_db.num_anchors[esp_transforms[i]]); HIP_IFEL(!(param = hip_get_next_param(msg, param)), -1, "parameter missing in user-message from fw\n"); anchor_db.anchor_lengths[esp_transforms[i]] = *(const int *) hip_get_param_contents_direct(param); HIP_DEBUG("anchor_length is %i\n", anchor_db.anchor_lengths[esp_transforms[i]]); HIP_IFEL(!(param = hip_get_next_param(msg, param)), -1, "parameter missing in user-message from fw\n"); } for (i = 0; i < esp_prot_num_transforms - 1; i++) { HIP_DEBUG("transform %u:\n", esp_transforms[i]); for (j = 0; j < anchor_db.num_anchors[esp_transforms[i]]; j++) { HIP_IFEL(!(anchor_db.anchors[esp_transforms[i]][j] = malloc(anchor_db.anchor_lengths[esp_transforms[i]])), -1, "failed to allocate memory\n"); anchor = hip_get_param_contents_direct(param); memcpy(anchor_db.anchors[esp_transforms[i]][j], anchor, anchor_db.anchor_lengths[esp_transforms[i]]); HIP_HEXDUMP("adding anchor: ", anchor_db.anchors[esp_transforms[i]][j], anchor_db.anchor_lengths[esp_transforms[i]]); HIP_IFEL(!(param = hip_get_next_param(msg, param)), -1, "parameter missing in user-message from fw\n"); anchor_db.hash_item_length[esp_transforms[i]] = *(const int *) hip_get_param_contents_direct(param); HIP_DEBUG("adding hash_item_length: %i\n", anchor_db.hash_item_length[esp_transforms[i]]); // exclude getting the next param for the very last loop if (!(i == esp_prot_num_transforms - 2 && j == anchor_db.num_anchors[esp_transforms[i]] - 1)) { HIP_IFEL(!(param = hip_get_next_param(msg, param)), -1, "parameter missing in user-message from fw\n"); } } } HIP_DEBUG("anchor_db successfully updated\n"); } else { HIP_ERROR("received anchor_db update, but esp protection extension disabled\n"); err = -1; goto out_err; } out_err: return err; }
/** returns the hash-item-length for a given transform * * @param transform the ESP protection extension transform * @return hash-item-length, 0 for UNUSED transform */ int anchor_db_get_hash_item_length(const uint8_t transform) { HIP_ASSERT(transform > 0); return anchor_db.hash_item_length[transform]; }
/** returns the anchor-length for a given transform * * @param transform the ESP protection extension transform * @return anchor-length, 0 for UNUSED transform */ int anchor_db_get_anchor_length(const uint8_t transform) { HIP_ASSERT(transform > 0); return anchor_db.anchor_lengths[transform]; }