[hipl-dev] [Merge] lp:~hipl-core/hipl/hipv2-dh-ecdh into lp:hipl

  • From: Miika Komu <mkomu@xxxxxxxxx>
  • To: mp+131786@xxxxxxxxxxxxxxxxxx
  • Date: Sun, 28 Oct 2012 16:35:26 -0000

Miika Komu has proposed merging lp:~hipl-core/hipl/hipv2-dh-ecdh into lp:hipl.

Requested reviews:
  Diego Biurrun (diego-biurrun)
  Miika Komu (miika-iki)
  Christof Mroz (christof-mroz)

For more details, see:
https://code.launchpad.net/~hipl-core/hipl/hipv2-dh-ecdh/+merge/131786

Hi,

I haven't heard from Xin for a while. I fixed two things on this branch:
* The cookie indexing bug that Christof discovered
* The code passes now commit hooks

We need this code for HIPv2. At the moment, I don't have much time to 
restructure/modularize/rewrite the entire branch, so please no generic or high 
level comments, only specific ones! Thanks.

8 September 2012
Revise code based on Diego's review comments.
Sorry for my delay.

============================================================================
This branch includes new ECDH functions and implements the new DH negotiation
mechanism for HIPv2:

ECDH is implemented using the library of openssl. (check libcore/cypto.c), I
also added some tests for those functions (test/libcore/crypto.c)

The DH_GROUP_LIST parameter (511) is added to the protocol for DH negotiation
in HIPv2. This new parameter changes the format of I1 and R1, and new functions
for handling this parameter and DH negotiation process are added.

NOTE: Other new parameters introduced by HIPv2 is not implemented in this
branch.
-- 
https://code.launchpad.net/~hipl-core/hipl/hipv2-dh-ecdh/+merge/131786
Your team HIPL core team is subscribed to branch lp:hipl.
=== modified file 'libcore/builder.c'
--- libcore/builder.c   2012-07-13 13:16:17 +0000
+++ libcore/builder.c   2012-10-28 16:34:23 +0000
@@ -119,7 +119,8 @@
  * @param content   the buffer to hold all the items
  * @param count     the number of items in the buffer
  * @param item_size the size of each item in bytes. The function only supports
- *                  items in 2 bytes or 4 bytes.
+ *                  byte conversion for items in 2 bytes or 4 bytes. For items
+ *                  with other size, no conversion will be applied.
  * @param flag      the flag to decide the byte conversion order
  */
 static void convert_byte_order(void *content, unsigned count,
@@ -128,14 +129,12 @@
     uint32_t (*f32)(uint32_t) = (flag == CBO_HTON) ? htonl : ntohl;
     uint16_t (*f16)(uint16_t) = (flag == CBO_HTON) ? htons : ntohs;
 
-    HIP_ASSERT(item_size == sizeof(uint16_t) || item_size == sizeof(uint32_t));
-
     if (item_size == sizeof(uint16_t)) {
         uint16_t *p = content;
         for (unsigned i = 0; i < count; i++) {
             p[i] = f16(p[i]);
         }
-    } else {
+    } else if (item_size == sizeof(uint32_t)) {
         uint32_t *p = content;
         for (unsigned i = 0; i < count; i++) {
             p[i] = f32(p[i]);
@@ -730,7 +729,8 @@
         HIP_PARAM_ESP_PROT_ANCHOR,
         HIP_PARAM_ESP_PROT_BRANCH,
         HIP_PARAM_ESP_PROT_SECRET,
-        HIP_PARAM_ESP_PROT_ROOT
+        HIP_PARAM_ESP_PROT_ROOT,
+        HIP_PARAM_DH_GROUP_LIST
     };
     hip_tlv type = hip_get_param_type(param);
 
@@ -1200,6 +1200,7 @@
     case HIP_PARAM_CERT:            return "HIP_PARAM_CERT";
     case HIP_PARAM_CERT_X509_REQ:   return "HIP_PARAM_CERT_X509_REQ";
     case HIP_PARAM_CERT_X509_RESP:  return "HIP_PARAM_CERT_X509_RESP";
+    case HIP_PARAM_DH_GROUP_LIST:   return "HIP_PARAM_DH_GROUP_LIST";
     case HIP_PARAM_DH_SHARED_KEY:   return "HIP_PARAM_DH_SHARED_KEY";
     case HIP_PARAM_DIFFIE_HELLMAN:  return "HIP_PARAM_DIFFIE_HELLMAN";
     case HIP_PARAM_DSA_SIGN_DATA:   return "HIP_PARAM_DSA_SIGN_DATA";

=== modified file 'libcore/crypto.c'
--- libcore/crypto.c    2012-05-12 06:54:33 +0000
+++ libcore/crypto.c    2012-10-28 16:34:23 +0000
@@ -46,6 +46,7 @@
  */
 
 #include <errno.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -68,6 +69,11 @@
 #include "crypto.h"
 
 
+const uint8_t HIP_DH_GROUP_LIST[HIP_DH_GROUP_LIST_SIZE] = {
+    HIP_DH_NIST_P_384,
+    HIP_DH_OAKLEY_15,
+    HIP_DH_OAKLEY_5
+};
 /*
  * Diffie-Hellman primes
  */
@@ -325,6 +331,10 @@
     sizeof(dhprime_modp_3072),
     sizeof(dhprime_modp_6144),
     sizeof(dhprime_modp_8192),
+    64,                       /* NIST P-256 */
+    96,                       /* NIST P-384 */
+    132,                      /* NIST P-512 */
+    0,                        /* SECP 160R1, unsupported */
 };
 
 static unsigned char dhgen[HIP_MAX_DH_GROUP_ID] = { 0,
@@ -701,6 +711,172 @@
     return dh;
 }
 
+#ifdef HAVE_EC_CRYPTO
+
+/**
+ * Test if the current DH group ID belongs to an ECDH group.
+ *
+ * @param group_id the Diffie-Hellman group ID
+ * @return         True if the given group is an ECDH group, False otherwise.
+ */
+bool hip_is_ecdh_group(const int group_id)
+{
+    return group_id == HIP_DH_NIST_P_256 ||
+           group_id == HIP_DH_NIST_P_384 ||
+           group_id == HIP_DH_NIST_P_521;
+}
+
+/**
+ * Generate a new Elliptic Curve Diffie-Hellman key.
+ *
+ * @param group_id the group ID of the DH_GROUP defined in HIPv2
+ * @return         a new ECDH key (caller deallocates), or NULL on error.
+ */
+EC_KEY *hip_generate_ecdh_key(const int group_id)
+{
+    char           rnd_seed[20];
+    struct timeval tv;
+    EC_KEY        *key;
+    int            nid;
+
+    if (group_id == HIP_DH_NIST_P_256) {
+        nid = NID_X9_62_prime256v1;
+    } else if (group_id == HIP_DH_NIST_P_384) {
+        nid = NID_secp384r1;
+    } else if (group_id == HIP_DH_NIST_P_521) {
+        nid = NID_secp521r1;
+    } else {
+        HIP_ERROR("Unsupported ECDH group: %d\n", group_id);
+        return NULL;
+    }
+
+    gettimeofday(&tv, NULL);
+    sprintf(rnd_seed, "%x%x", (unsigned int) tv.tv_usec,
+            (unsigned int) tv.tv_sec);
+    RAND_seed(rnd_seed, sizeof(rnd_seed));
+
+    if ((key = EC_KEY_new_by_curve_name(nid)) == NULL) {
+        HIP_ERROR("Failed to create a new EC_KEY from nid: %d\n", nid);
+        return NULL;
+    }
+
+    if (EC_KEY_generate_key(key) == 0) {
+        HIP_ERROR("Failed to generate parameters for the new EC_KEY.\n");
+        EC_KEY_free(key);
+        return NULL;
+    }
+
+    return key;
+}
+
+/**
+ * Generate a shared key using Elliptic Curve Diffie-Hellman.
+ * This method only supports keys using Prime Curve.
+ *
+ * @param key           the Elliptic Curve Diffie-Hellman key
+ * @param peer_pub_x    the x coordinator of the peer's public key
+ * @param peer_pub_y    the y coordinator of the peer's public key
+ * @param peer_len      length of the @c peer_pub_x or @c peer_pub_y (these two
+ *                      length values are identical)
+ * @param shared_key    shared key to generate
+ * @param outlen        the length of the @c shared_key
+ * @return              the length of the shared key on success, 0 otherwise
+ */
+int hip_gen_ecdh_shared_key(EC_KEY *const key,
+                            const uint8_t *const peer_pub_x,
+                            const uint8_t *const peer_pub_y,
+                            const size_t peer_len,
+                            uint8_t *const shared_key,
+                            const size_t outlen)
+{
+    const EC_GROUP *group;
+    BIGNUM         *peer_pubx = NULL;
+    BIGNUM         *peer_puby = NULL;
+    EC_POINT       *peer_pub  = NULL;
+    int             err       = 1;
+    unsigned int    out;
+
+    if (EC_KEY_check_key(key) == 0) {
+        HIP_ERROR("Invalid input EC_KEY\n");
+        return 0;
+    }
+
+    group = EC_KEY_get0_group(key);
+
+    if (EC_METHOD_get_field_type(EC_GROUP_method_of(group))
+        != NID_X9_62_prime_field) {
+        HIP_ERROR("Invalid group method, only prime curve is supported.\n");
+        return 0;
+    }
+
+    peer_pub  = EC_POINT_new(group);
+    peer_pubx = BN_bin2bn(peer_pub_x, peer_len, NULL);
+    peer_puby = BN_bin2bn(peer_pub_y, peer_len, NULL);
+
+    HIP_IFEL(EC_POINT_set_affine_coordinates_GFp(group, peer_pub, peer_pubx,
+                                                 peer_puby, NULL) == 0,
+             0, "Failed to create peer's public key.\n");
+
+    out = ECDH_compute_key(shared_key, outlen, peer_pub, key, NULL);
+    HIP_IFEL(out == 0 || out != peer_len, 0,
+             "Failed to compute the ECDH shared key\n");
+    err = out;
+
+out_err:
+    BN_free(peer_pubx);
+    BN_free(peer_puby);
+    EC_POINT_free(peer_pub);
+    return err;
+}
+
+/**
+ * Encode an ECDH public key into a character array.
+ *
+ * @param key      the ECDH key
+ * @param[out] out the character array
+ * @param outlen   the length of @c out in bytes
+ * @return         the number of bytes written
+ */
+int hip_encode_ecdh_publickey(EC_KEY *key, uint8_t *out, int outlen)
+{
+    BIGNUM *pubx = NULL;
+    BIGNUM *puby = NULL;
+    int     len;
+    int     err = 0;
+
+    if (key == NULL || out == NULL || outlen < 0 ||
+        EC_KEY_check_key(key) == 0) {
+        HIP_ERROR("Invalid input\n");
+        return -1;
+    }
+
+    pubx = BN_new();
+    puby = BN_new();
+    HIP_IFEL(pubx == NULL || puby == NULL, -1, "Failed to initialize Big 
Number\n");
+
+    if (EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(key),
+                                            EC_KEY_get0_public_key(key),
+                                            pubx, puby, NULL) == 0) {
+        HIP_ERROR("Failed to get x,y coordinates from the ECDH key\n");
+        return -1;
+    }
+
+    len = BN_num_bytes(pubx);
+    HIP_IFEL(outlen < len * 2, -1, "Output buffer too small\n");
+
+    bn2bin_safe(pubx, out, outlen / 2);
+    bn2bin_safe(puby, out + outlen / 2, outlen / 2);
+
+    return outlen;
+
+out_err:
+    BN_free(pubx);
+    BN_free(puby);
+    return err;
+}
+
+#endif /* HAVE_EC_CRYPTO */
+
 /**
  * Determine the size for required to store DH shared secret.
  * @param hip_dh_group_type the group type from DIFFIE_HELLMAN parameter
@@ -714,7 +890,7 @@
     if (hip_dh_group_type == 0) {
         HIP_ERROR("Trying to use reserved DH group type 0\n");
     } else if (hip_dh_group_type > ARRAY_SIZE(dhprime_len)) {
-        HIP_ERROR("Unknown/unsupported MODP group %d\n", hip_dh_group_type);
+        HIP_ERROR("Unknown/unsupported DH or ECDH group %d\n", 
hip_dh_group_type);
     } else {
         ret = dhprime_len[hip_dh_group_type];
     }

=== modified file 'libcore/crypto.h'
--- libcore/crypto.h    2012-05-12 10:21:32 +0000
+++ libcore/crypto.h    2012-10-28 16:34:23 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 Aalto University and RWTH Aachen University.
+ * Copyright (c) 2010-2012 Aalto University and RWTH Aachen University.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -28,6 +28,7 @@
 
 #include "config.h"
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <netinet/in.h>
 #include <sys/types.h>
@@ -51,15 +52,25 @@
 
 /* These should be consistent with the table length in crypto.c and
  * crypto/dh.c */
-#define HIP_DH_384                    1 /* 384-bit group */
-#define HIP_DH_OAKLEY_1               2 /* 768-bit OAKLEY well known group 1 */
+/* 384-bit group, DEPRECATED from HIPv2 */
+#define HIP_DH_384                    1
+/* 768-bit OAKLEY well known group 1, DEPRECATED from HIPv2 */
+#define HIP_DH_OAKLEY_1               2
 #define HIP_DH_OAKLEY_5               3 /* 1536-bit MODP group */
 #define HIP_DH_OAKLEY_15              4 /* 3072-bit MODP group */
-#define HIP_DH_OAKLEY_17              5 /* 6144-bit MODP group */
-#define HIP_DH_OAKLEY_18              6 /* 8192-bit MODP group */
+/* 6144-bit MODP group, DEPRECATED from HIPv2 */
+#define HIP_DH_OAKLEY_17              5
+/* 8192-bit MODP group, DEPRECATED from HIPv2 */
+#define HIP_DH_OAKLEY_18              6
+/* Group 7 to 10 are new groups defined in HIPv2, among which group 7,8 and 9
+ * are Ellipse Curve groups. */
+#define HIP_DH_NIST_P_256             7
+#define HIP_DH_NIST_P_384             8
+#define HIP_DH_NIST_P_521             9
+#define HIP_DH_SECP_160_R1            10
 #define HIP_FIRST_DH_GROUP_ID         HIP_DH_OAKLEY_5
 #define HIP_SECOND_DH_GROUP_ID        HIP_DH_384
-#define HIP_MAX_DH_GROUP_ID           7
+#define HIP_MAX_DH_GROUP_ID           11
 
 #define DSA_KEY_DEFAULT_BITS       1024
 #define RSA_KEY_DEFAULT_BITS       1024
@@ -86,6 +97,13 @@
 #define HIP_SHA(buffer, total_len, hash)   SHA((buffer), (total_len), (hash))
 #endif
 
+/* HIPv2: default value for DH_GROUP_LIST parameter */
+#define HIP_DH_GROUP_LIST_SIZE        3
+const uint8_t HIP_DH_GROUP_LIST[HIP_DH_GROUP_LIST_SIZE];
+
+/* HIPv2: max acceptable size of DH group list, longer part will be ignored */
+#define HIP_DH_GROUP_MAX_RECV_SIZE    6
+
 int ssl_rsa_verify(uint8_t *digest, uint8_t *public_key, uint8_t *signature, 
int pub_klen);
 int ssl_dsa_verify(uint8_t *digest, uint8_t *public_key, uint8_t *signature);
 /* In kernel these come from crypto/dh.h, included above */
@@ -121,6 +139,15 @@
 int impl_ecdsa_verify(const unsigned char *const digest,
                       EC_KEY *const ecdsa,
                       const unsigned char *const signature);
+bool hip_is_ecdh_group(const int group_id);
+EC_KEY *hip_generate_ecdh_key(const int group_id);
+int hip_encode_ecdh_publickey(EC_KEY *key, uint8_t *out, int outlen);
+int hip_gen_ecdh_shared_key(EC_KEY *const key,
+                            const uint8_t *const peer_pub_x,
+                            const uint8_t *const peer_pub_y,
+                            const size_t peer_len,
+                            uint8_t *const shared_key,
+                            const size_t outlen);
 #endif /* HAVE_EC_CRYPTO */
 
 #endif /* HIPL_LIBCORE_CRYPTO_H */

=== modified file 'libcore/protodefs.h'
--- libcore/protodefs.h 2012-07-12 11:32:14 +0000
+++ libcore/protodefs.h 2012-10-28 16:34:23 +0000
@@ -143,6 +143,7 @@
 #define HIP_PARAM_SOLUTION             321
 #define HIP_PARAM_SEQ                  385
 #define HIP_PARAM_ACK                  449
+#define HIP_PARAM_DH_GROUP_LIST        511
 #define HIP_PARAM_DIFFIE_HELLMAN       513
 #define HIP_PARAM_HIP_TRANSFORM        577
 #define HIP_PARAM_ENCRYPTED            641

=== modified file 'libhipl/cookie.c'
--- libhipl/cookie.c    2012-06-03 10:26:55 +0000
+++ libhipl/cookie.c    2012-10-28 16:34:23 +0000
@@ -182,14 +182,13 @@
  * @param ip_i        Initiator's IPv6
  * @param ip_r        Responder's IPv6
  * @param our_hit     Our HIT
- * @param hip_version HIP message version
  *
  * @note Comments for the if 0 code are inlined below.
  *
  * Returns NULL if error.
  */
 struct hip_common *hip_get_r1(struct in6_addr *ip_i, struct in6_addr *ip_r,
-                              struct in6_addr *our_hit, uint8_t hip_version)
+                              struct in6_addr *our_hit)
 {
     struct hip_common    *err         = NULL, *r1 = NULL;
     struct hip_r1entry   *hip_r1table = NULL;
@@ -200,7 +199,7 @@
     HIP_IFEL(!(hid = hip_get_hostid_entry_by_lhi_and_algo(our_hit, 
HIP_ANY_ALGO, -1)),
              NULL, "Unknown HIT\n");
 
-    hip_r1table = hid->r1[hip_version];
+    hip_r1table = hid->r1;
     idx         = calc_cookie_idx(ip_i, ip_r);
     HIP_DEBUG("Calculated index: %d\n", idx);
 
@@ -219,41 +218,93 @@
 }
 
 /**
- * precreate an R1 packet
- *
- * @param r1table     a pointer to R1 table structure
+ * HIPv2: get a copy of R1entry structure.
+ *
+ * @param ip_i        Initiator's IPv6
+ * @param ip_r        Responder's IPv6
+ * @param our_hit     Our HIT
+ * @param dh_group_id Diffie Hellman group ID
+ * @return            A R1 packet copy on success, NULL on error
+ */
+struct hip_common *hip_get_r1_v2(struct in6_addr *ip_i, struct in6_addr *ip_r,
+                                 struct in6_addr *our_hit, const int 
dh_group_id)
+{
+    struct hip_common    *r1  = NULL;
+    struct local_host_id *hid = NULL;
+    int                   idx, len;
+
+    /* Find the proper R1 table and copy the R1 message from the table */
+    hid = hip_get_hostid_entry_by_lhi_and_algo(our_hit, HIP_ANY_ALGO, -1);
+    if (hid == NULL) {
+        HIP_ERROR("Unknown HIT\n");
+        return NULL;
+    }
+
+    idx = calc_cookie_idx(ip_i, ip_r);
+    HIP_DEBUG("Calculated index: %d\n", idx);
+
+    /* Create a copy of the found entry */
+    len = hip_get_msg_total_len(&hid->r1_v2[dh_group_id][idx].buf.msg);
+    if (len <= 0) {
+        HIP_ERROR("Invalid r1_v2 entry at %d, %d\n", dh_group_id, idx);
+        return NULL;
+    }
+
+    if ((r1 = hip_msg_alloc()) == NULL) {
+        return NULL;
+    }
+
+    memcpy(r1, &hid->r1_v2[dh_group_id][idx].buf.msg, len);
+
+    return r1;
+}
+
+/**
+ * HIPv1 & HIPv2: precreate R1 entries
+ *
+ * @param id_entry    a pointer to host ID entry
  * @param hit         the local HIT
  * @param sign        a signing callback function
  * @param privkey     the private key to use for signing
  * @param pubkey      the host id (public key)
- * @param hip_version HIP message version
  * @return            zero on success and non-zero on error
  */
-int hip_precreate_r1(struct hip_r1entry *const r1table,
-                     const struct in6_addr *const hit,
+int hip_precreate_r1(struct local_host_id *id_entry,
+                     const hip_hit_t *const hit,
                      int (*sign)(void *const key, struct hip_common *const m),
                      void *const privkey,
-                     const struct hip_host_id *const pubkey,
-                     const uint8_t hip_version)
+                     const struct hip_host_id *const pubkey)
 {
-    int i = 0;
+    int i, j, group_id, cookie_k;
+
     for (i = 0; i < HIP_R1TABLESIZE; i++) {
-        int cookie_k;
-
         cookie_k = get_cookie_difficulty();
-
-        hip_msg_init(&r1table[i].buf.msg);
-
-        if (hip_create_r1(&r1table[i].buf.msg, hit, sign, privkey, pubkey,
-                          cookie_k, hip_version)) {
+        hip_msg_init(&id_entry->r1[i].buf.msg);
+
+        if (hip_create_r1(&id_entry->r1[i].buf.msg, hit, sign, privkey,
+                          pubkey, cookie_k)) {
             HIP_ERROR("Unable to precreate R1s\n");
-            return 0;
-        }
-
-        HIP_DEBUG("Packet %d created\n", i);
-    }
-
-    return 1;
+            return -1;
+        }
+        HIP_DEBUG("R1 Packet %d created\n", i);
+    }
+
+    for (j = 0; j < HIP_DH_GROUP_LIST_SIZE; j++) {
+        group_id = HIP_DH_GROUP_LIST[j];
+        for (i = 0; i < HIP_R1TABLESIZE; i++) {
+            cookie_k = get_cookie_difficulty();
+            hip_msg_init(&id_entry->r1_v2[j][i].buf.msg);
+
+            if (hip_create_r1_v2(&id_entry->r1_v2[j][i].buf.msg, hit, sign,
+                                 privkey, pubkey, cookie_k, group_id)) {
+                HIP_ERROR("Unable to precreate R1_v2\n");
+                return -1;
+            }
+            HIP_DEBUG("R1_v2 Packets %d created for group: %d\n", i, group_id);
+        }
+    }
+
+    return 0;
 }
 
 /**
@@ -266,13 +317,17 @@
  * @param hdr         a pointer to HIP packet common header
  * @param solution    a pointer to a solution structure
  * @param hip_version HIP message version
+ * @param dh_group_id the Diffie-Hellman group ID of the R1 entry. This
+ *                    parameter is required for a HIPv2 cookie verification.
+ *                    For v1, this parameter will be ignored.
  * @return            Zero if the cookie was verified successfully, negative
  *                    otherwise.
  */
 int hip_verify_cookie(struct in6_addr *ip_i, struct in6_addr *ip_r,
                       struct hip_common *hdr,
                       const struct hip_solution *solution,
-                      const uint8_t hip_version)
+                      const uint8_t hip_version,
+                      const int dh_group_id)
 {
     /* In a effort to conform the HIPL coding convention, the return value
      * of this function was inverted. I.e. This function now returns
@@ -289,7 +344,12 @@
                                                           HIP_ANY_ALGO,
                                                           -1)),
              -1, "Requested source HIT not (any more) available.\n");
-    result = &hid->r1[hip_version][calc_cookie_idx(ip_i, ip_r)];
+
+    if (hip_version == HIP_V1) {
+        result = &hid->r1[calc_cookie_idx(ip_i, ip_r)];
+    } else {
+        result = &hid->r1_v2[dh_group_id][calc_cookie_idx(ip_i, ip_r)];
+    }
 
     puzzle = hip_get_param(&result->buf.msg, HIP_PARAM_PUZZLE);
     HIP_IFEL(!puzzle, -1, "Internal error: could not find the cookie\n");
@@ -344,7 +404,6 @@
 static int recreate_r1s_for_entry_move(struct local_host_id *entry,
                                        UNUSED void *opaque)
 {
-    int i;
     int (*signature_func)(void *const key, struct hip_common *const m);
 
     switch (hip_get_host_id_algo(&entry->host_id)) {
@@ -364,11 +423,10 @@
         return -1;
     }
 
-    for (i = 1; i < HIP_MAX_VERSION; i++) {
-        if (!hip_precreate_r1(entry->r1[i], &entry->hit, signature_func,
-                              entry->private_key, &entry->host_id, i)) {
-            return -1;
-        }
+    if (hip_precreate_r1(entry, &entry->hit, signature_func,
+                         entry->private_key, &entry->host_id) < 0) {
+        HIP_ERROR("Precreate r1 failed\n");
+        return -1;
     }
 
     return 0;

=== modified file 'libhipl/cookie.h'
--- libhipl/cookie.h    2012-06-03 10:26:55 +0000
+++ libhipl/cookie.h    2012-10-28 16:34:23 +0000
@@ -30,32 +30,26 @@
 #include <netinet/in.h>
 
 #include "libcore/protodefs.h"
-
-#define HIP_R1TABLESIZE 3 /* precreate only this many R1s */
-
-struct hip_r1entry {
-    union hip_msg_bfr buf;
-    uint32_t          generation;
-    uint8_t           Ci[PUZZLE_LENGTH];
-    uint8_t           Ck;
-    uint8_t           Copaque[HIP_PUZZLE_OPAQUE_LEN];
-};
+#include "libhipl/hidb.h"
 
 struct hip_common *hip_get_r1(struct in6_addr *ip_i,
                               struct in6_addr *ip_r,
-                              struct in6_addr *peer_hit,
-                              uint8_t hip_version);
+                              struct in6_addr *peer_hit);
+struct hip_common *hip_get_r1_v2(struct in6_addr *ip_i,
+                                 struct in6_addr *ip_r,
+                                 struct in6_addr *our_hit,
+                                 const int dh_group_id);
 int hip_recreate_all_precreated_r1_packets(void);
-int hip_precreate_r1(struct hip_r1entry *const r1table,
-                     const struct in6_addr *const hit,
+int hip_precreate_r1(struct local_host_id *id_entry,
+                     const hip_hit_t *const hit,
                      int (*sign)(void *const key, struct hip_common *const m),
                      void *const privkey,
-                     const struct hip_host_id *const pubkey,
-                     const uint8_t hip_version);
+                     const struct hip_host_id *const pubkey);
 int hip_verify_cookie(struct in6_addr *ip_i, struct in6_addr *ip_r,
                       struct hip_common *hdr,
                       const struct hip_solution *cookie,
-                      const uint8_t hip_version);
+                      const uint8_t hip_version,
+                      const int dh_group_id);
 int hip_inc_cookie_difficulty(void);
 int hip_dec_cookie_difficulty(void);
 int hip_get_puzzle_difficulty_msg(struct hip_common *msg);

=== modified file 'libhipl/dh.c'
--- libhipl/dh.c        2012-05-12 10:21:32 +0000
+++ libhipl/dh.c        2012-10-28 16:34:23 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Aalto University and RWTH Aachen University.
+ * Copyright (c) 2010, 2012 Aalto University and RWTH Aachen University.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -47,6 +47,8 @@
  */
 static DH *dh_table[HIP_MAX_DH_GROUP_ID] = { 0 };
 
+static EC_KEY *ecdh_table[HIP_MAX_DH_GROUP_ID] = { 0 };
+
 /**
  * insert the current DH-key into the buffer
  *
@@ -95,66 +97,288 @@
 }
 
 /**
- * create a shared secret based on the public key of the peer
+ * Store the bytes of the current ECDH public key in the given buffer.
+ *
+ * A new ECDH key will be created if it doesn't exist,
+ *
+ * @param buffer   buffer to store the public part of the ECDH key
+ * @param bufsize  size of the @c buffer
+ * @param group_id group ID of the ECDH key
+ * @return         the number of bytes written to the buffer, -1 on error.
+ */
+int hip_insert_ecdh(uint8_t *buffer, int bufsize, int group_id)
+{
+    EC_KEY *key;
+    int     ret;
+
+    if (!hip_is_ecdh_group(group_id)) {
+        HIP_ERROR("Invalid group id for ECDH: %d\n", group_id);
+        return -1;
+    }
+
+    if (ecdh_table[group_id] == NULL) {
+        key = hip_generate_ecdh_key(group_id);
+        if (key == NULL) {
+            HIP_ERROR("Failed to generate an ECDH key for group: %d\n",
+                      group_id);
+            return -1;
+        }
+        ecdh_table[group_id] = key;
+    }
+
+    key = ecdh_table[group_id];
+    if ((ret = hip_encode_ecdh_publickey(key, buffer, bufsize)) < 0) {
+        HIP_ERROR("Failed to encode the ECDH public key\n");
+        return -1;
+    }
+
+    return ret;
+}
+
+/**
+ * HIPv2: Store the bytes of the current ECDH/DH public key to the given 
buffer.
+ *
+ * An ECDH/DH key will be created if it does not exist.
+ *
+ * @param buffer   the buffer to store the ECDH/DH public key
+ * @param bufsize  the size of the @c buffer
+ * @param group_id the group ID of the ECDH/DH key
+ * @return         the number of bytes written to the buffer
+ */
+int hip_insert_dh_v2(uint8_t *buffer, int bufsize, int group_id)
+{
+    if (group_id <= 0 || group_id >= HIP_MAX_DH_GROUP_ID) {
+        HIP_ERROR("Invalid DH_GROUP_ID: %d\n", group_id);
+        return -1;
+    }
+
+    if (hip_is_ecdh_group(group_id)) {
+        return hip_insert_ecdh(buffer, bufsize, group_id);
+    } else {
+        return hip_insert_dh(buffer, bufsize, group_id);
+    }
+}
+
+/**
+ * Match the first identical DH group ID in local and peer's list.
+ *
+ * @param dh_group_list  the DH_GROUP_LIST parameter sent from the peer
+ * @param our_dh_group   the local DH list
+ * @param our_group_size the size of the @c our_dh_group
+ * @return               ID of the matched group on success, -1 otherwise.
+ */
+int hip_match_dh_group_list(const struct hip_tlv_common *const dh_group_list,
+                            const uint8_t *const our_dh_group,
+                            const int our_group_size)
+{
+    int     list_size = HIP_DH_GROUP_MAX_RECV_SIZE;
+    uint8_t list[list_size];
+    int     i, j;
+
+    list_size = hip_get_list_from_param(dh_group_list, list, list_size,
+                                        sizeof(uint8_t));
+    for (i = 0; i < list_size; i++) {
+        for (j = 0; j < our_group_size; j++) {
+            if (our_dh_group[j] == list[i]) {
+                return our_dh_group[j];
+            }
+        }
+    }
+
+    return -1;
+}
+
+/**
+ * Calculate a Diffie-Hellman shared secret based on the public key of the peer
  * (passed as an argument) and own DH private key (created beforehand).
  *
- * @param public_value Peer's Diffie-Hellman public key
+ * @param group_id     the Diffie-Hellman group ID
+ * @param public_value the Diffie-Hellman public key of the peer
+ * @param len          the length of the @c public_value
+ * @param buffer       the buffer that holds enough space for the shared secret
+ * @param bufsize      the size of the @c buffer
+ *
+ * @return             the length of the shared secret in octets if successful,
+ *                     or -1 if an error occurred.
+ */
+static int hip_calculate_dh_shared_secret(const uint16_t group_id,
+                                          const uint8_t *const public_value,
+                                          const int len,
+                                          unsigned char *const buffer,
+                                          const int bufsize)
+{
+    DH *key;
+    int secret_len;
+
+    if (group_id <= 0 || group_id >= HIP_MAX_DH_GROUP_ID) {
+        HIP_ERROR("Invalid Group ID: %d.\n", group_id);
+        return -1;
+    }
+
+    if (dh_table[group_id] == NULL) {
+        if (NULL == (key = hip_generate_dh_key(group_id))) {
+            HIP_ERROR("Failed to generate a DH key for group: %d\n", group_id);
+            return -1;
+        }
+        dh_table[group_id] = key;
+    }
+    key = dh_table[group_id];
+
+    secret_len = hip_gen_dh_shared_key(dh_table[group_id], public_value, len,
+                                       buffer, bufsize);
+    if (secret_len < 0) {
+        HIP_ERROR("failed to create a DH shared secret\n");
+        return -1;
+    }
+
+    return secret_len;
+}
+
+/**
+ * Calculate an Elliptic Curve Diffie-Hellman shared secret.
+ *
+ * The length of the public value should match the corresponding ECDH group; 
The
+ * buffer to hold the shared secret should be at least larger than the length 
of
+ * the public value divided by 2.
+ *
+ * @param group_id     the ECDH group ID
+ * @param public_value Peer's ECDH public key
+ * @param pubkey_len   the length of the @c public_value
+ * @param buffer       Buffer that holds enough space for the shared secret
+ * @param bufsize      size of the @c buffer
+ *
+ * @return             the length of the shared secret in octets if successful,
+ *                     or -1 if an error occurred.
+ */
+static int hip_calculate_ecdh_shared_secret(const uint16_t group_id,
+                                            const uint8_t *const public_value,
+                                            const int pubkey_len,
+                                            unsigned char *const buffer,
+                                            const int bufsize)
+{
+    EC_KEY *key;
+    int     key_len;
+
+    if (ecdh_table[group_id] == NULL) {
+        if (NULL == (key = hip_generate_ecdh_key(group_id))) {
+            HIP_ERROR("Failed to generate an ECDH key for group: %d\n",
+                      group_id);
+            return -1;
+        }
+        ecdh_table[group_id] = key;
+    }
+    key = ecdh_table[group_id];
+
+    key_len = hip_get_dh_size(group_id);
+    if (key_len != pubkey_len || key_len / 2 > bufsize) {
+        HIP_ERROR("Invalid public key length (%d) or buffer size (%d)\n",
+                  pubkey_len, bufsize);
+        return -1;
+    }
+    int out = hip_gen_ecdh_shared_key(key, public_value,
+                                      public_value + key_len / 2,
+                                      key_len / 2,
+                                      buffer,
+                                      bufsize);
+    if (out <= 0) {
+        HIP_ERROR("Failed to generate a shared secret\n");
+        return -1;
+    }
+
+    return out;
+}
+
+/**
+ * Calculate a shared secret for Diffie-Hellman exchange.
+ *
+ * This function supports both normal DH and ECDH groups. The DH private key
+ * is created beforehand.
+ *
+ * @param group_id     the Diffie-Hellman group ID
+ * @param public_value the Diffie-Hellman public key of the peer
+ * @param len          the length of the @c public_value
+ * @param buffer       Buffer that holds the shared secret
+ * @param bufsize      size of the @c buffer
+ *
+ * @return             the length of the shared secret in octets if successful,
+ *                     or -1 if an error occurred.
+ */
+int hip_calculate_shared_secret(const uint16_t group_id,
+                                const uint8_t *const public_value,
+                                const int len,
+                                unsigned char *const buffer,
+                                const int bufsize)
+{
+    if (group_id <= 0 || group_id >= HIP_MAX_DH_GROUP_ID) {
+        HIP_ERROR("Invalid Diffie-Hellman group ID: %d\n", group_id);
+        return -1;
+    }
+
+    if (hip_is_ecdh_group(group_id)) {
+        return hip_calculate_ecdh_shared_secret(group_id, public_value, len,
+                                                buffer, bufsize);
+    } else {
+        return hip_calculate_dh_shared_secret(group_id, public_value, len,
+                                              buffer, bufsize);
+    }
+}
+
+/**
+ * Re-generate a DH key for a given group ID.
+ *
  * @param group_id the Diffie-Hellman group ID
- * @param len the length of the public value
- * @param buffer Buffer that holds enough space for the shared secret.
- * @param bufsize size of the buffer
- *
- * @return the length of the shared secret in octets if successful,
- * or -1 if an error occured.
- */
-int hip_calculate_shared_secret(const uint8_t *public_value,
-                                uint8_t group_id,
-                                signed int len,
-                                unsigned char *buffer,
-                                int bufsize)
-{
-    int err = 0;
-    DH *tmp;
-
-    if (group_id <= 0 || group_id >= HIP_MAX_DH_GROUP_ID) {
-        HIP_ERROR("The Group ID %d is invalid\n", group_id);
-        return -1;
-    }
-
-    /*
-     * First check that we have the key available.
-     * Then encode it into the buffer
-     */
-
-    if (dh_table[group_id] == NULL) {
-        tmp                = hip_generate_dh_key(group_id);
-        dh_table[group_id] = tmp;
-
-        if (dh_table[group_id] == NULL) {
-            HIP_ERROR("Unsupported DH group: %d\n", group_id);
-            return -1;
-        }
-    }
-
-    err = hip_gen_dh_shared_key(dh_table[group_id], public_value,
-                                len, buffer, bufsize);
-    if (err < 0) {
-        HIP_ERROR("Could not create shared secret\n");
-        return -1;
-    }
-
-    return err;
-}
-
-/**
- * regenerate Diffie-Hellman keys for HIP
- * @param bitmask Mask of groups to generate.
- *
- * @note Use only this function to generate DH keys.
- */
-static void regen_dh_keys(uint32_t bitmask)
+ * @return         0 on success, -1 otherwise
+ */
+static int regen_dh_key(const int group_id)
 {
     DH *tmp, *okey;
+
+    tmp = hip_generate_dh_key(group_id);
+    if (!tmp) {
+        HIP_INFO("Failed to generate a DH key for group: %d\n", group_id);
+        return -1;
+    }
+
+    okey               = dh_table[group_id];
+    dh_table[group_id] = tmp;
+
+    DH_free(okey);
+    return 0;
+}
+
+#ifdef HAVE_EC_CRYPTO
+/**
+ * Re-generate DH key for a given ECDH group ID.
+ *
+ * @param group_id the ECDH group ID
+ * @return         0 on success, -1 otherwise
+ */
+static int regen_ecdh_key(const int group_id)
+{
+    EC_KEY *tmp, *okey;
+
+    tmp = hip_generate_ecdh_key(group_id);
+    if (!tmp) {
+        HIP_INFO("Failed to generate an ECDH key for group: %d\n", group_id);
+        return -1;
+    }
+
+    okey                 = ecdh_table[group_id];
+    ecdh_table[group_id] = tmp;
+
+    EC_KEY_free(okey);
+    return 0;
+}
+
+#endif /* HAVE_EC_CRYPTO */
+
+/**
+ * HIPv2: regenerate Diffie-Hellman keys.
+ *
+ * @param bitmask the mask of groups to generate
+ */
+static void regen_dh_keys_v2(uint32_t bitmask)
+{
     int maxmask, i;
     int cnt = 0;
 
@@ -164,19 +388,13 @@
 
     for (i = 1; i < HIP_MAX_DH_GROUP_ID; i++) {
         if (bitmask & (1 << i)) {
-            tmp = hip_generate_dh_key(i);
-            if (!tmp) {
-                HIP_INFO("Error while generating group: %d\n", i);
-                continue;
+            if (hip_is_ecdh_group(i)) {
+                regen_ecdh_key(i);
+            } else {
+                regen_dh_key(i);
             }
 
-            okey        = dh_table[i];
-            dh_table[i] = tmp;
-
-            DH_free(okey);
-
             cnt++;
-
             HIP_DEBUG("DH key for group %d generated\n", i);
         }
     }
@@ -193,6 +411,14 @@
         DH_free(dh_table[i]);
         dh_table[i] = NULL;
     }
+
+#ifdef HAVE_EC_CRYPTO
+    for (i = 1; i < HIP_MAX_DH_GROUP_ID; i++) {
+        EC_KEY_free(ecdh_table[i]);
+        ecdh_table[i] = NULL;
+    }
+#endif /* HAVE_EC_CRYPTO */
+
     CRYPTO_cleanup_all_ex_data();
 }
 
@@ -205,10 +431,13 @@
 
     supported_groups = (1 << HIP_DH_OAKLEY_1 |
                         1 << HIP_DH_OAKLEY_5 |
-                        1 << HIP_DH_384);
+                        1 << HIP_DH_384 |
+                        1 << HIP_DH_NIST_P_256 |
+                        1 << HIP_DH_NIST_P_384 |
+                        1 << HIP_DH_NIST_P_521);
 
     HIP_DEBUG("Generating DH keys\n");
-    regen_dh_keys(supported_groups);
+    regen_dh_keys_v2(supported_groups);
 
     return 1;
 }

=== modified file 'libhipl/dh.h'
--- libhipl/dh.h        2012-05-12 10:21:32 +0000
+++ libhipl/dh.h        2012-10-28 16:34:23 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Aalto University and RWTH Aachen University.
+ * Copyright (c) 2010, 2012 Aalto University and RWTH Aachen University.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -28,13 +28,21 @@
 
 #include <stdint.h>
 
+#include "libcore/protodefs.h"
+
+
 int hip_insert_dh(uint8_t *buffer, int bufsize, int group_id);
 void hip_dh_uninit(void);
-int hip_calculate_shared_secret(const uint8_t *public_value,
-                                uint8_t group_id,
-                                signed int len,
-                                unsigned char *buffer,
-                                int bufsize);
+int hip_calculate_shared_secret(const uint16_t group_id,
+                                const uint8_t *const pulic_value,
+                                const int len,
+                                unsigned char *const buffer,
+                                const int bufsize);
 int hip_init_cipher(void);
 
+int hip_insert_dh_v2(uint8_t *buffer, int bufsize, int group_id);
+int hip_insert_ecdh(uint8_t *buffer, int bufsize, int group_id);
+int hip_match_dh_group_list(const struct hip_tlv_common *const dh_group_list,
+                            const uint8_t *our_dh_group, const int 
our_group_size);
+
 #endif /* HIPL_LIBHIPL_DH_H */

=== modified file 'libhipl/hidb.c'
--- libhipl/hidb.c      2012-06-03 10:26:55 +0000
+++ libhipl/hidb.c      2012-10-28 16:34:23 +0000
@@ -429,7 +429,6 @@
                        hip_lsi_t *lsi,
                        const struct hip_host_id_priv *host_id)
 {
-    int                   i;
     int                   err      = 0;
     struct local_host_id *id_entry = NULL;
     struct local_host_id *old_entry;
@@ -493,16 +492,12 @@
         err = -1;
         goto out_err;
     }
-    for (i = 1; i < HIP_MAX_VERSION; i++) {
-        HIP_IFEL(!hip_precreate_r1(id_entry->r1[i],
-                                   &hit,
-                                   signature_func,
-                                   id_entry->private_key,
-                                   &id_entry->host_id,
-                                   i),
-                 -ENOENT,
-                 "Unable to precreate R1s.\n");
-    }
+
+    HIP_IFEL(hip_precreate_r1(id_entry, &hit, signature_func,
+                              id_entry->private_key,
+                              &id_entry->host_id) < 0,
+             -ENOENT,
+             "Unable to precreate R1s.\n");
 
 out_err:
     if (err && id_entry) {

=== modified file 'libhipl/hidb.h'
--- libhipl/hidb.h      2012-06-03 10:26:55 +0000
+++ libhipl/hidb.h      2012-10-28 16:34:23 +0000
@@ -35,9 +35,19 @@
 #include <stdbool.h>
 #include <netinet/in.h>
 
+#include "libcore/crypto.h"
 #include "libcore/protodefs.h"
-#include "cookie.h"
-
+
+
+#define HIP_R1TABLESIZE 3 /* precreate only this many R1s */
+
+struct hip_r1entry {
+    union hip_msg_bfr buf;
+    uint32_t          generation;
+    uint8_t           Ci[PUZZLE_LENGTH];
+    uint8_t           Ck;
+    uint8_t           Copaque[HIP_PUZZLE_OPAQUE_LEN];
+};
 
 struct local_host_id {
     hip_hit_t          hit;
@@ -45,7 +55,13 @@
     hip_lsi_t          lsi;
     struct hip_host_id host_id;
     void              *private_key;       /* RSA or DSA */
-    struct hip_r1entry r1[HIP_MAX_VERSION][HIP_R1TABLESIZE];    /* precreated 
R1s */
+
+    /* precreated R1 entries.
+     * Due to the introduction of DH_GROUP_LIST in HIPv2,  R1's DIFFIE_HELLMAN
+     * parameter must match one of the group ID of initiator's I1. Therefore we
+     * precreate R1 for all DH groups we support. */
+    struct hip_r1entry r1[HIP_R1TABLESIZE];
+    struct hip_r1entry r1_v2[HIP_MAX_DH_GROUP_ID][HIP_R1TABLESIZE];
 };
 
 struct local_host_id *hip_get_hostid_entry_by_lhi_and_algo(const struct 
in6_addr *const hit,

=== modified file 'libhipl/input.c'
--- libhipl/input.c     2012-07-13 13:16:17 +0000
+++ libhipl/input.c     2012-10-28 16:34:23 +0000
@@ -110,6 +110,43 @@
 }
 
 /**
+ * HIPv2: Check potential downgrade possibility for DH group selection by
+ * matching our DH list with the peer's DH list. If the peer doesn't select
+ * the strongest group, DH downgrade occurs.
+ *
+ * @param peer_group the DH group peer has selected
+ * @param peer_param the peer's DH group list parameter
+ * @return           0 if no downgrade detected, -1 otherwise.
+ */
+static int check_dh_downgrade_v2(const uint8_t peer_group,
+                                 const struct hip_tlv_common *const peer_param)
+{
+    int     i, j;
+    int     list_size = HIP_DH_GROUP_MAX_RECV_SIZE;
+    uint8_t list[list_size];
+
+    list_size = hip_get_list_from_param(peer_param, list, list_size,
+                                        sizeof(list[0]));
+    for (i = 0; i < HIP_DH_GROUP_LIST_SIZE; i++) {
+        for (j = 0; j < list_size; j++) {
+            if (HIP_DH_GROUP_LIST[i] == list[j]) {
+                if (list[j] == peer_group) {
+                    return 0;
+                } else {
+                    HIP_ERROR("Detect DH group downgrade. "
+                              "Expect group: %d, Got: %d\n",
+                              list[j], peer_group);
+                    return -1;
+                }
+            }
+        }
+    }
+
+    HIP_ERROR("No identical group in the DH group lists\n");
+    return -1;
+}
+
+/**
  * Verifies gerenal HMAC in HIP msg
  *
  * @param msg HIP packet
@@ -325,11 +362,14 @@
     HIP_DEBUG("Start PERF_DH_CREATE\n");
     hip_perf_start_benchmark(perf_set, PERF_DH_CREATE);
 #endif
-    HIP_IFEL((dh_shared_len = hip_calculate_shared_secret(dhpv->public_value, 
dhpv->group_id,
-                                                          ntohs(dhpv->pub_len),
-                                                          (unsigned char *) 
dh_shared_key,
-                                                          dh_shared_len)) < 0,
-             -EINVAL, "Calculation of shared secret failed.\n");
+
+    dh_shared_len = hip_calculate_shared_secret(dhpv->group_id, 
dhpv->public_value,
+                                                ntohs(dhpv->pub_len),
+                                                (unsigned char *) 
dh_shared_key,
+                                                dh_shared_len);
+    HIP_IFEL(dh_shared_len <= 0, -EINVAL, "Calculation of shared secret 
failed.\n");
+    HIP_DEBUG("DH group %d, shared secret length is %d\n",
+              dhpv->group_id, dh_shared_len);
 
     hip_make_keymat(dh_shared_key,
                     dh_shared_len,
@@ -763,6 +803,24 @@
     HIP_IFE(hip_init_peer(ctx->hadb_entry, &peer_host_id),
             -EINVAL);
 
+    /* HIPv2: check possible DH group downgrade */
+    if (ctx->hadb_entry->hip_version == HIP_V2) {
+        const struct hip_tlv_common     *dh_list_param;
+        const struct hip_diffie_hellman *dh_param;
+
+        dh_list_param = hip_get_param(ctx->input_msg, HIP_PARAM_DH_GROUP_LIST);
+        HIP_IFEL(dh_list_param == NULL, -ENOENT,
+                 "No DH_GROUP_LIST parameter found in R1\n");
+
+        dh_param = hip_get_param(ctx->input_msg, HIP_PARAM_DIFFIE_HELLMAN);
+        HIP_IFEL(dh_param == NULL, -ENOENT,
+                 "No DIFFIE_HELLMAN parameter found in R1\n");
+
+        HIP_IFEL(check_dh_downgrade_v2(dh_param->pub_val.group_id,
+                                       dh_list_param) < 0,
+                 -EINVAL, "DH group downgrade check failed.\n");
+    }
+
 #ifdef CONFIG_HIP_PERFORMANCE
     HIP_DEBUG("Start PERF_VERIFY\n");
     hip_perf_start_benchmark(perf_set, PERF_VERIFY);
@@ -945,7 +1003,8 @@
         HIP_ERROR("Failed to allocate memory for public value\n");
         return -ENOMEM;
     }
-    if ((pub_len = hip_insert_dh(public_value, pub_len, dhpv->group_id)) < 0) {
+
+    if ((pub_len = hip_insert_dh_v2(public_value, pub_len, dhpv->group_id)) < 
0) {
         HIP_ERROR("Could not extract the DH public key\n");
         return -1;
     }
@@ -1363,19 +1422,22 @@
                  UNUSED const enum hip_state ha_state,
                  struct hip_packet_context *ctx)
 {
-    int                             hip_version       = 0;
-    int                             err               = 0, is_loopback = 0;
-    bool                            skip_key_creation = false;
-    uint16_t                        mask              = HIP_PACKET_CTRL_ANON;
-    uint16_t                        crypto_len        = 0;
-    char                           *tmp_enc           = NULL;
-    const char                     *enc               = NULL;
-    unsigned char                  *iv                = NULL;
-    const struct hip_solution      *solution          = NULL;
-    const struct hip_r1_counter    *r1cntr            = NULL;
-    const struct hip_hip_transform *hip_transform     = NULL;
-    struct hip_host_id             *host_id_in_enc    = NULL;
-    struct hip_host_id              host_id;
+    int                              hip_version       = 0;
+    int                              err               = 0, is_loopback = 0;
+    bool                             skip_key_creation = false;
+    uint16_t                         mask              = HIP_PACKET_CTRL_ANON;
+    uint16_t                         crypto_len        = 0;
+    char                            *tmp_enc           = NULL;
+    const char                      *enc               = NULL;
+    unsigned char                   *iv                = NULL;
+    const struct hip_solution       *solution          = NULL;
+    const struct hip_diffie_hellman *dh_param          = NULL;
+    const struct hip_r1_counter     *r1cntr            = NULL;
+    const struct hip_hip_transform  *hip_transform     = NULL;
+    struct hip_host_id              *host_id_in_enc    = NULL;
+    struct hip_host_id               host_id;
+    int                              dh_group_id, i;
+
 #ifdef CONFIG_HIP_PERFORMANCE
     HIP_DEBUG("Start PERF_I2\n");
     hip_perf_start_benchmark(perf_set, PERF_I2);
@@ -1464,13 +1526,47 @@
              -ENODATA,
              "SOLUTION parameter missing from I2 packet. Dropping\n");
 
-    HIP_IFEL(hip_verify_cookie(&ctx->src_addr,
-                               &ctx->dst_addr,
-                               ctx->input_msg,
-                               solution,
-                               ctx->hadb_entry->hip_version),
-             -EPROTO,
-             "Cookie solution rejected. Dropping the I2 packet.\n");
+    /* Validate DIFFIE_HELLMAN parameter */
+    if (NULL == (dh_param = hip_get_param(ctx->input_msg,
+                                          HIP_PARAM_DIFFIE_HELLMAN))) {
+        HIP_ERROR("DIFFIE_HELLMAN parameter missing from I2 packet\n");
+        ctx->error = -ENODATA;
+        return ctx->error;
+    }
+    dh_group_id = dh_param->pub_val.group_id;
+    for (i = 0; i < HIP_DH_GROUP_LIST_SIZE; i++) {
+        if (dh_group_id == HIP_DH_GROUP_LIST[i]) {
+            break;
+        }
+    }
+    if (i == HIP_DH_GROUP_LIST_SIZE) {
+        HIP_ERROR("Invalid group %d for DIFFIE_HELLMAN parameter.\n",
+                  dh_group_id);
+        ctx->error = -EINVAL;
+        return ctx->error;
+    }
+    if (hip_get_dh_size(dh_group_id) != ntohs(dh_param->pub_val.pub_len)) {
+        HIP_ERROR("Invalid public key length for DIFFIE_HELLMAN parameter. "
+                  "Expect: %d, Got: %d\n", hip_get_dh_size(dh_group_id),
+                  ntohs(dh_param->pub_val.pub_len));
+        ctx->error = -EINVAL;
+        return ctx->error;
+    }
+
+    /* Verify cookie */
+    if (hip_version == HIP_V1) {
+        HIP_IFEL(hip_verify_cookie(&ctx->src_addr, &ctx->dst_addr,
+                                   ctx->input_msg, solution,
+                                   hip_version, 0),
+                 -EPROTO,
+                 "Cookie solution rejected. Dropping the I2 packet.\n");
+    } else {
+        HIP_IFEL(hip_verify_cookie(&ctx->src_addr, &ctx->dst_addr,
+                                   ctx->input_msg, solution,
+                                   hip_version, dh_group_id),
+                 -EPROTO,
+                 "Cookie solution rejected. Dropping the I2 packet.\n");
+    }
 
     /* Shared secrets are reused when the received I2 is a retransmission. */
     if (skip_key_creation) {

=== modified file 'libhipl/netdev.c'
--- libhipl/netdev.c    2012-06-03 10:26:55 +0000
+++ libhipl/netdev.c    2012-10-28 16:34:23 +0000
@@ -987,8 +987,25 @@
 
     HIP_DEBUG("Using ifindex %d\n", if_index);
 
-    HIP_IFEL(hip_send_i1(&entry->hit_our, &entry->hit_peer, entry), -1,
-             "Sending of I1 failed\n");
+    switch (entry->hip_version) {
+    case HIP_V1:
+        if (hip_send_i1(&entry->hit_our, &entry->hit_peer, entry) < 0) {
+            HIP_ERROR("Failed to send the I1(v1) message.\n");
+            return -1;
+        }
+        break;
+
+    case HIP_V2:
+        if (hip_send_i1_v2(&entry->hit_our, &entry->hit_peer, entry) < 0) {
+            HIP_ERROR("Failed to send the I1(v2) message.\n");
+            return -1;
+        }
+        break;
+
+    default:
+        HIP_ERROR("Unknown HIP version: %d\n", entry->hip_version);
+        return -1;
+    }
 
 out_err:
 

=== modified file 'libhipl/output.c'
--- libhipl/output.c    2012-06-07 12:45:16 +0000
+++ libhipl/output.c    2012-10-28 16:34:23 +0000
@@ -161,7 +161,111 @@
 }
 
 /**
- * Send an I1 packet to the Responder
+ * Send an I1 packet to the responder.
+ *
+ * This method checks the shotgun status and decides whether to use shotgun
+ * mode or not for I1 sending.
+ *
+ * @param i1    the I1 packet to be sent
+ * @param entry a pointer to the current host association database state.
+ * @return      zero on success, or negative error value on error.
+ */
+static int send_i1_internal(struct hip_common *const i1,
+                            struct hip_hadb_state *const entry)
+{
+    struct in6_addr                *local_addr = NULL;
+    struct in6_addr                 peer_addr;
+    LHASH_NODE                     *item = NULL, *tmp = NULL;
+    struct hip_peer_addr_list_item *addr;
+    int                             err = 0, i = 0;
+
+    HIP_DEBUG("Sending I1 to the following addresses:\n");
+    print_peer_addresses_to_be_added(entry);
+
+    if (hip_shotgun_status == HIP_MSG_SHOTGUN_OFF ||
+        (entry->peer_addr_list_to_be_added == NULL)) {
+        if (hip_hadb_get_peer_addr(entry, &peer_addr)) {
+            HIP_ERROR("No preferred IP address for the peer.\n");
+            return -1;
+        }
+
+        local_addr = &entry->our_addr;
+        return send_i1_pkt(i1, local_addr, &peer_addr, entry->local_udp_port,
+                           entry->peer_udp_port, entry);
+    } else {
+        HIP_DEBUG("Number of items in the peer addr list: %d ",
+                  ((struct lhash_st *) 
entry->peer_addr_list_to_be_added)->num_items);
+        list_for_each_safe(item, tmp, entry->peer_addr_list_to_be_added, i)
+        {
+            addr = list_entry(item);
+            ipv6_addr_copy(&peer_addr, &addr->address);
+
+            err = send_i1_pkt(i1, NULL, &peer_addr, entry->local_udp_port,
+                              entry->peer_udp_port, entry);
+        }
+        return err;
+    }
+}
+
+/**
+ * HIPv2: send an I1 packet to the responder.
+ *
+ * @param src_hit a pointer to the source host identity tag.
+ * @param dst_hit a pointer to the destination host identity tag.
+ * @param entry   a pointer to the host association database state reserved for
+ *                the peer.
+ * @return        zero on success, or negative value on error.
+ */
+int hip_send_i1_v2(hip_hit_t *const src_hit, const hip_hit_t *const dst_hit,
+                   struct hip_hadb_state *const entry)
+{
+    struct hip_common *i1  = NULL;
+    int                err = 0;
+
+    int     group_size = HIP_DH_GROUP_LIST_SIZE;
+    uint8_t dh_group[group_size];
+
+    memcpy(dh_group, HIP_DH_GROUP_LIST, group_size);
+
+    if (entry->state == HIP_STATE_ESTABLISHED) {
+        HIP_DEBUG("HIP association established, not triggering bex\n");
+        return 0;
+    }
+
+    /* Assign a local private key, public key and HIT to HA */
+    HIP_DEBUG_HIT("src_hit", src_hit);
+    HIP_DEBUG_HIT("entry->src_hit", &entry->hit_our);
+    HIP_IFEL(hip_init_us(entry, src_hit), -EINVAL,
+             "Could not assign a local host id\n");
+    HIP_DEBUG_HIT("entry->src_hit", &entry->hit_our);
+
+    if ((i1 = hip_msg_alloc()) == NULL) {
+        return -1;
+    }
+
+    hip_build_network_hdr(i1, HIP_I1, 0, &entry->hit_our,
+                          dst_hit, entry->hip_version);
+
+    /* Calculate the HIP header length */
+    hip_calc_hdr_len(i1);
+
+    /* Build DH_GROUP_LIST */
+    HIP_IFEL(hip_build_param_list(i1, HIP_PARAM_DH_GROUP_LIST, dh_group,
+                                  group_size, sizeof(uint8_t)),
+             -1, "Failed to build param: DH_GROUP_LIST\n");
+
+    HIP_DEBUG_HIT("HIT source", &i1->hit_sender);
+    HIP_DEBUG_HIT("HIT dest", &i1->hit_receiver);
+
+    HIP_IFEL(send_i1_internal(i1, entry), -1, "send_i1_internal() failed\n");
+
+out_err:
+    free(i1);
+    return err;
+}
+
+/**
+ * HIPv1: send an I1 packet to the responder.
  *
  * @param src_hit a pointer to source host identity tag.
  * @param dst_hit a pointer to destination host identity tag.
@@ -172,13 +276,8 @@
 int hip_send_i1(hip_hit_t *src_hit, const hip_hit_t *dst_hit,
                 struct hip_hadb_state *entry)
 {
-    struct hip_common              *i1   = 0;
-    uint16_t                        mask = 0;
-    int                             err  = 0,       i = 0;
-    LHASH_NODE                     *item = NULL, *tmp = NULL;
-    struct hip_peer_addr_list_item *addr;
-    struct in6_addr                *local_addr = NULL;
-    struct in6_addr                 peer_addr;
+    struct hip_common *i1  = 0;
+    int                err = 0;
 
 #ifdef CONFIG_HIP_PERFORMANCE
     HIP_DEBUG("Start PERF_I1_SEND, PERF_BASE\n");
@@ -209,7 +308,7 @@
 
     i1 = hip_msg_alloc();
 
-    hip_build_network_hdr(i1, HIP_I1, mask, &entry->hit_our,
+    hip_build_network_hdr(i1, HIP_I1, 0, &entry->hit_our,
                           dst_hit, entry->hip_version);
 
     /* Calculate the HIP header length */
@@ -218,30 +317,8 @@
     HIP_DEBUG_HIT("HIT source", &i1->hit_sender);
     HIP_DEBUG_HIT("HIT dest", &i1->hit_receiver);
 
-    HIP_DEBUG("Sending I1 to the following addresses:\n");
-    print_peer_addresses_to_be_added(entry);
-
-    if (hip_shotgun_status == HIP_MSG_SHOTGUN_OFF ||
-        (entry->peer_addr_list_to_be_added == NULL)) {
-        HIP_IFEL(hip_hadb_get_peer_addr(entry, &peer_addr), -1,
-                 "No preferred IP address for the peer.\n");
-
-        local_addr = &entry->our_addr;
-        err        = send_i1_pkt(i1, local_addr, &peer_addr,
-                                 entry->local_udp_port,
-                                 entry->peer_udp_port, entry);
-    } else {
-        HIP_DEBUG("Number of items in the peer addr list: %d ",
-                  ((struct lhash_st *) 
entry->peer_addr_list_to_be_added)->num_items);
-        list_for_each_safe(item, tmp, entry->peer_addr_list_to_be_added, i)
-        {
-            addr = list_entry(item);
-            ipv6_addr_copy(&peer_addr, &addr->address);
-
-            err = send_i1_pkt(i1, NULL, &peer_addr, entry->local_udp_port,
-                              entry->peer_udp_port, entry);
-        }
-    }
+    HIP_IFEL(send_i1_internal(i1, entry), -1, "send_i1_internal() failed\n");
+
 #ifdef CONFIG_HIP_PERFORMANCE
     HIP_DEBUG("Stop and write PERF_I1_SEND\n");
     hip_perf_stop_benchmark(perf_set, PERF_I1_SEND);
@@ -263,8 +340,8 @@
  */
 static int add_echo_response(struct hip_packet_context *ctx, int sign)
 {
-    int param_type = sign ? HIP_PARAM_ECHO_REQUEST_SIGN
-                          : HIP_PARAM_ECHO_REQUEST;
+    int param_type =
+        sign ? HIP_PARAM_ECHO_REQUEST_SIGN : HIP_PARAM_ECHO_REQUEST;
 
     const struct hip_echo_msg *ping = hip_get_param(ctx->input_msg, 
param_type);
 
@@ -597,15 +674,14 @@
 /**
  * Construct a new R1 packet payload
  *
- * @param msg          points to a message object backed by HIP_MAX_PACKET 
bytes
- *                     of memory to which the R1 message is written.
+ * @param msg          pointer to a message backed by HIP_MAX_PACKET bytes of
+ *                     memory to which the R1 message is written.
  * @param src_hit      a pointer to the source host identity tag used in the
  *                     packet.
  * @param sign         a funtion pointer to a signature funtion.
  * @param private_key  a pointer to the local host private key
  * @param host_id_pub  a pointer to the public host id of the local host
  * @param cookie_k     the difficulty value for the puzzle
- * @param hip_version  HIP message version
  * @return             0 on success, a non-zero value on error.
  */
 int hip_create_r1(struct hip_common *const msg,
@@ -613,8 +689,7 @@
                   int (*sign)(void *const key, struct hip_common *const m),
                   void *const private_key,
                   const struct hip_host_id *const host_id_pub,
-                  const int cookie_k,
-                  const uint8_t hip_version)
+                  const int cookie_k)
 {
     int            err = 0;
     struct hip_srv service_list[HIP_TOTAL_EXISTING_SERVICES];
@@ -682,7 +757,7 @@
     /** @todo TH: hip_build_network_hdr has to be replaced with an
      *  appropriate function pointer */
     HIP_DEBUG_HIT("src_hit used to build r1 network header", src_hit);
-    hip_build_network_hdr(msg, HIP_R1, mask, src_hit, NULL, hip_version);
+    hip_build_network_hdr(msg, HIP_R1, mask, src_hit, NULL, HIP_V1);
 
     /********** R1_COUNTER (OPTIONAL) *********/
 
@@ -776,6 +851,172 @@
 }
 
 /**
+ * Construct a new R1 packet payload.
+ *
+ * @param msg          pointer to a message backed by HIP_MAX_PACKET bytes
+ *                     of memory to which the R1 message is written
+ * @param src_hit      a pointer to the source HIT used in the packet
+ * @param sign         a function pointer to a signature function
+ * @param private_key  a pointer to the local host private key
+ * @param host_id_pub  a pointer to the public host id of the local host
+ * @param cookie_k     the difficulty value for the puzzle
+ * @param dh_group_id  the Diffie-Hellman group ID which will be used by this
+ *                     new R1 entry
+ * @return             0 on success, a non-zero value on error
+ */
+int hip_create_r1_v2(struct hip_common *const msg,
+                     const struct in6_addr *const src_hit,
+                     int (*sign)(void *const key, struct hip_common *const m),
+                     void *const private_key,
+                     const struct hip_host_id *const host_id_pub,
+                     const int cookie_k,
+                     const int dh_group_id)
+{
+    int            err = 0;
+    struct hip_srv service_list[HIP_TOTAL_EXISTING_SERVICES];
+    uint8_t       *dh_data       = NULL;
+    char           order[]       = "000";
+    int            dh_size       = 0;
+    int            mask          = 0, i = 0, written = 0;
+    unsigned int   service_count = 0;
+
+    /* Supported HIP and ESP transforms. */
+    hip_transform_suite transform_hip_suite[] = {
+        HIP_HIP_AES_SHA1,
+        HIP_HIP_3DES_SHA1,
+        HIP_HIP_NULL_SHA1
+    };
+    hip_transform_suite transform_esp_suite[] = {
+        HIP_ESP_AES_SHA1,
+        HIP_ESP_3DES_SHA1,
+        HIP_ESP_NULL_SHA1
+    };
+
+    /* change order if necessary */
+    sprintf(order, "%d", hip_transform_order);
+    for (i = 0; i < 3; i++) {
+        switch (order[i]) {
+        case '1':
+            transform_hip_suite[i] = HIP_HIP_AES_SHA1;
+            transform_esp_suite[i] = HIP_ESP_AES_SHA1;
+            HIP_DEBUG("Transform order index %d is AES\n", i);
+            break;
+        case '2':
+            transform_hip_suite[i] = HIP_HIP_3DES_SHA1;
+            transform_esp_suite[i] = HIP_ESP_3DES_SHA1;
+            HIP_DEBUG("Transform order index %d is 3DES\n", i);
+            break;
+        case '3':
+            transform_hip_suite[i] = HIP_HIP_NULL_SHA1;
+            transform_esp_suite[i] = HIP_ESP_NULL_SHA1;
+            HIP_DEBUG("Transform order index %d is NULL_SHA1\n", i);
+            break;
+        }
+    }
+
+    /* Initialize the message buffer as the message builder depends on it. */
+    hip_msg_init(msg);
+
+    /* Allocate memory for writing the Diffie-Hellman public value */
+    if ((dh_size = hip_get_dh_size(dh_group_id)) == 0) {
+        HIP_ERROR("Could not get dh_size\n");
+        return -1;
+    }
+    if ((dh_data = calloc(1, dh_size)) == NULL) {
+        HIP_ERROR("Failed to allocate memory for dh_data\n");
+        return -1;
+    }
+
+    /* Ready to begin building of the R1 packet */
+    HIP_DEBUG_HIT("src_hit used to build r1 network header", src_hit);
+    hip_build_network_hdr(msg, HIP_R1, mask, src_hit, NULL, HIP_V2);
+
+    /********** R1_COUNTER (OPTIONAL) *********/
+
+    /********** Parameter PUZZLE ************/
+    const uint8_t zero_i[PUZZLE_LENGTH] = { 0 };
+    //2^(42-32) sec lifetime
+    err = hip_build_param_puzzle(msg, cookie_k, 42, 0, zero_i);
+    HIP_IFEL(err, err, "Cookies were burned. Bummer!\n");
+
+    /* Parameter DH_GROUP_LIST */
+    uint8_t dh_group[HIP_DH_GROUP_LIST_SIZE];
+    memcpy(dh_group, HIP_DH_GROUP_LIST, HIP_DH_GROUP_LIST_SIZE);
+    HIP_IFEL(hip_build_param_list(msg, HIP_PARAM_DH_GROUP_LIST, dh_group,
+                                  HIP_DH_GROUP_LIST_SIZE, sizeof(uint8_t)),
+             -1, "Failed to build param DH_GROUP_LIST.\n");
+
+    /******** Parameter DIFFIE_HELLMAN ********/
+    HIP_IFEL((written = hip_insert_dh_v2(dh_data, dh_size, dh_group_id)) < 0,
+             written, "Could not extract DH public key\n");
+
+    HIP_IFEL((err = hip_build_param_diffie_hellman_contents(msg, dh_group_id,
+                                                            dh_data, written,
+                                                            
HIP_MAX_DH_GROUP_ID,
+                                                            NULL, 0)),
+             err, "Building of DH failed.\n");
+
+    /* Parameter HIP transform. */
+    HIP_IFEL((err = hip_build_param_hip_transform(msg,
+                                                  transform_hip_suite,
+                                                  sizeof(transform_hip_suite) /
+                                                  
sizeof(hip_transform_suite))),
+             err, "Building of HIP transform failed\n");
+
+    /* Parameter HOST_ID */
+    HIP_IFEL((err = hip_build_param_host_id(msg, host_id_pub)),
+             err, "Building of host id failed\n");
+
+    /* Parameter REG_INFO */
+    hip_get_active_services(service_list, &service_count);
+    HIP_DEBUG("Found %d active service(s) \n", service_count);
+    hip_build_param_reg_info(msg, service_list, service_count);
+
+    /* Parameter ESP-ENC transform. */
+    HIP_IFEL((err = hip_build_param_esp_transform(msg,
+                                                  transform_esp_suite,
+                                                  sizeof(transform_esp_suite) /
+                                                  
sizeof(hip_transform_suite))),
+             err, "Building of ESP transform failed\n");
+
+    /********** ESP-PROT transform (OPTIONAL) **********/
+
+    HIP_IFEL((err = esp_prot_r1_add_transforms(msg)), err,
+             "failed to add optional esp transform parameter\n");
+
+    /********** ECHO_REQUEST_SIGN (OPTIONAL) *********/
+
+    //HIP_HEXDUMP("Pubkey:", host_id_pub, 
hip_get_param_total_len(host_id_pub));
+
+    /* Parameter Signature 2 */
+
+    HIP_IFEL((err = sign(private_key, msg)), err, "Signing of R1 failed.\n");
+
+    /* Parameter ECHO_REQUEST (OPTIONAL) */
+
+    /* Fill puzzle parameters */
+    {
+        struct hip_puzzle *pz;
+
+        HIP_IFEL(!(pz = hip_get_param_readwrite(msg, HIP_PARAM_PUZZLE)), -1,
+                 "Internal error\n");
+
+        /* hardcode kludge */
+        pz->opaque[0] = 'H';
+        pz->opaque[1] = 'I';
+
+        get_random_bytes(pz->I, PUZZLE_LENGTH);
+    }
+
+    /* Packet ready */
+
+out_err:
+    free(dh_data);
+
+    return err;
+}
+
+/**
  * Transmit an R1 packet to the network.
  *
  * Send an R1 packet to the peer and store the cookie information that was
@@ -866,10 +1107,29 @@
         }
     }
 
-    HIP_IFEL(!(r1pkt = hip_get_r1(r1_dst_addr, &ctx->dst_addr,
-                                  &ctx->input_msg->hit_receiver,
-                                  hip_get_msg_version(ctx->input_msg))),
-             -ENOENT, "No precreated R1\n");
+    if (hip_get_msg_version(ctx->input_msg) == HIP_V1) {
+        HIP_IFEL(!(r1pkt = hip_get_r1(r1_dst_addr, &ctx->dst_addr,
+                                      &ctx->input_msg->hit_receiver)),
+                 -ENOENT, "No precreated R1\n");
+    } else {
+        const struct hip_tlv_common *dh_group_list;
+        int                          selected_group;
+
+        dh_group_list = hip_get_param(ctx->input_msg, HIP_PARAM_DH_GROUP_LIST);
+        HIP_IFEL(dh_group_list == NULL, -1, "No DH_GROUP_LIST parameter in 
r1\n");
+
+        selected_group = hip_match_dh_group_list(dh_group_list,
+                                                 HIP_DH_GROUP_LIST,
+                                                 HIP_DH_GROUP_LIST_SIZE);
+        HIP_IFEL(selected_group == -1, -1,
+                 "Cannot find a matchness for DH_GROUP_LIST\n");
+        HIP_DEBUG("Selected DH group: %d\n", selected_group);
+
+        r1pkt = hip_get_r1_v2(r1_dst_addr, &ctx->dst_addr,
+                              &ctx->input_msg->hit_receiver, selected_group);
+        HIP_IFEL(r1pkt == NULL, -ENOENT, "No precreated R1_v2 for group: %d\n",
+                 selected_group);
+    }
 
     if (&ctx->input_msg->hit_sender) {
         ipv6_addr_copy(&r1pkt->hit_receiver, &ctx->input_msg->hit_sender);

=== modified file 'libhipl/output.h'
--- libhipl/output.h    2012-06-03 10:26:55 +0000
+++ libhipl/output.h    2012-10-28 16:34:23 +0000
@@ -52,8 +52,15 @@
                   int (*sign)(void *const key, struct hip_common *const m),
                   void *const private_key,
                   const struct hip_host_id *const host_id_pub,
-                  const int cookie_k,
-                  const uint8_t hip_version);
+                  const int cookie_k);
+
+int hip_create_r1_v2(struct hip_common *const msg,
+                     const struct in6_addr *const src_hit,
+                     int (*sign)(void *const key, struct hip_common *const m),
+                     void *const private_key,
+                     const struct hip_host_id *const host_id_pub,
+                     const int cookie_k,
+                     const int dh_group_id);
 
 int hip_send_r1(const uint8_t packet_type,
                 const enum hip_state ha_state,
@@ -81,6 +88,9 @@
 
 int hip_send_i1(hip_hit_t *, const hip_hit_t *, struct hip_hadb_state *);
 
+int hip_send_i1_v2(hip_hit_t *const src_hit, const hip_hit_t *const dst_hit,
+                   struct hip_hadb_state *const entry);
+
 int hip_add_signed_echo_response(const uint8_t packet_type,
                                  const enum hip_state ha_state,
                                  struct hip_packet_context *ctx);

=== modified file 'test/libcore/crypto.c'
--- test/libcore/crypto.c       2012-05-12 06:54:33 +0000
+++ test/libcore/crypto.c       2012-10-28 16:34:23 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Aalto University and RWTH Aachen University.
+ * Copyright (c) 2011-2012 Aalto University and RWTH Aachen University.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -28,12 +28,235 @@
 #include <string.h>
 #include <stdio.h>
 #include <unistd.h>
+#ifdef HAVE_EC_CRYPTO
+#include <openssl/ecdh.h>
+#endif
 
 #include "libcore/crypto.h"
 #include "config.h"
 #include "test_suites.h"
 
+
 #ifdef HAVE_EC_CRYPTO
+
+static const int TEST_ECDH_PRIV_A = 0;
+static const int TEST_ECDH_PUBX_A = 1;
+static const int TEST_ECDH_PUBY_A = 2;
+static const int TEST_ECDH_PRIV_B = 3;
+static const int TEST_ECDH_PUBX_B = 4;
+static const int TEST_ECDH_PUBY_B = 5;
+static const int TEST_ECDH_SHARED = 6;
+
+/* An example for testing from RFC5903, section 8.1 */
+static unsigned char TEST_ECDH_NIST_P_256[] = {
+    0xC8, 0x8F, 0x01, 0xF5, 0x10, 0xD9, 0xAC, 0x3F, 0x70, 0xA2,
+    0x92, 0xDA, 0xA2, 0x31, 0x6D, 0xE5, 0x44, 0xE9, 0xAA, 0xB8,
+    0xAF, 0xE8, 0x40, 0x49, 0xC6, 0x2A, 0x9C, 0x57, 0x86, 0x2D,
+    0x14, 0x33,
+
+    0xDA, 0xD0, 0xB6, 0x53, 0x94, 0x22, 0x1C, 0xF9, 0xB0, 0x51,
+    0xE1, 0xFE, 0xCA, 0x57, 0x87, 0xD0, 0x98, 0xDF, 0xE6, 0x37,
+    0xFC, 0x90, 0xB9, 0xEF, 0x94, 0x5D, 0x0C, 0x37, 0x72, 0x58,
+    0x11, 0x80,
+
+    0x52, 0x71, 0xA0, 0x46, 0x1C, 0xDB, 0x82, 0x52, 0xD6, 0x1F,
+    0x1C, 0x45, 0x6F, 0xA3, 0xE5, 0x9A, 0xB1, 0xF4, 0x5B, 0x33,
+    0xAC, 0xCF, 0x5F, 0x58, 0x38, 0x9E, 0x05, 0x77, 0xB8, 0x99,
+    0x0B, 0xB3,
+
+    0xC6, 0xEF, 0x9C, 0x5D, 0x78, 0xAE, 0x01, 0x2A, 0x01, 0x11,
+    0x64, 0xAC, 0xB3, 0x97, 0xCE, 0x20, 0x88, 0x68, 0x5D, 0x8F,
+    0x06, 0xBF, 0x9B, 0xE0, 0xB2, 0x83, 0xAB, 0x46, 0x47, 0x6B,
+    0xEE, 0x53,
+
+    0xD1, 0x2D, 0xFB, 0x52, 0x89, 0xC8, 0xD4, 0xF8, 0x12, 0x08,
+    0xB7, 0x02, 0x70, 0x39, 0x8C, 0x34, 0x22, 0x96, 0x97, 0x0A,
+    0x0B, 0xCC, 0xB7, 0x4C, 0x73, 0x6F, 0xC7, 0x55, 0x44, 0x94,
+    0xBF, 0x63,
+
+    0x56, 0xFB, 0xF3, 0xCA, 0x36, 0x6C, 0xC2, 0x3E, 0x81, 0x57,
+    0x85, 0x4C, 0x13, 0xC5, 0x8D, 0x6A, 0xAC, 0x23, 0xF0, 0x46,
+    0xAD, 0xA3, 0x0F, 0x83, 0x53, 0xE7, 0x4F, 0x33, 0x03, 0x98,
+    0x72, 0xAB,
+
+    0xD6, 0x84, 0x0F, 0x6B, 0x42, 0xF6, 0xED, 0xAF, 0xD1, 0x31,
+    0x16, 0xE0, 0xE1, 0x25, 0x65, 0x20, 0x2F, 0xEF, 0x8E, 0x9E,
+    0xCE, 0x7D, 0xCE, 0x03, 0x81, 0x24, 0x64, 0xD0, 0x4B, 0x94,
+    0x42, 0xDE,
+};
+
+/* An example for testing from RFC5903, section 8.2 */
+static unsigned char TEST_ECDH_NIST_P_384[] = {
+    0x09, 0x9F, 0x3C, 0x70, 0x34, 0xD4, 0xA2, 0xC6, 0x99, 0x88,
+    0x4D, 0x73, 0xA3, 0x75, 0xA6, 0x7F, 0x76, 0x24, 0xEF, 0x7C,
+    0x6B, 0x3C, 0x0F, 0x16, 0x06, 0x47, 0xB6, 0x74, 0x14, 0xDC,
+    0xE6, 0x55, 0xE3, 0x5B, 0x53, 0x80, 0x41, 0xE6, 0x49, 0xEE,
+    0x3F, 0xAE, 0xF8, 0x96, 0x78, 0x3A, 0xB1, 0x94,
+
+    0x66, 0x78, 0x42, 0xD7, 0xD1, 0x80, 0xAC, 0x2C, 0xDE, 0x6F,
+    0x74, 0xF3, 0x75, 0x51, 0xF5, 0x57, 0x55, 0xC7, 0x64, 0x5C,
+    0x20, 0xEF, 0x73, 0xE3, 0x16, 0x34, 0xFE, 0x72, 0xB4, 0xC5,
+    0x5E, 0xE6, 0xDE, 0x3A, 0xC8, 0x08, 0xAC, 0xB4, 0xBD, 0xB4,
+    0xC8, 0x87, 0x32, 0xAE, 0xE9, 0x5F, 0x41, 0xAA,
+
+    0x94, 0x82, 0xED, 0x1F, 0xC0, 0xEE, 0xB9, 0xCA, 0xFC, 0x49,
+    0x84, 0x62, 0x5C, 0xCF, 0xC2, 0x3F, 0x65, 0x03, 0x21, 0x49,
+    0xE0, 0xE1, 0x44, 0xAD, 0xA0, 0x24, 0x18, 0x15, 0x35, 0xA0,
+    0xF3, 0x8E, 0xEB, 0x9F, 0xCF, 0xF3, 0xC2, 0xC9, 0x47, 0xDA,
+    0xE6, 0x9B, 0x4C, 0x63, 0x45, 0x73, 0xA8, 0x1C,
+
+    0x41, 0xCB, 0x07, 0x79, 0xB4, 0xBD, 0xB8, 0x5D, 0x47, 0x84,
+    0x67, 0x25, 0xFB, 0xEC, 0x3C, 0x94, 0x30, 0xFA, 0xB4, 0x6C,
+    0xC8, 0xDC, 0x50, 0x60, 0x85, 0x5C, 0xC9, 0xBD, 0xA0, 0xAA,
+    0x29, 0x42, 0xE0, 0x30, 0x83, 0x12, 0x91, 0x6B, 0x8E, 0xD2,
+    0x96, 0x0E, 0x4B, 0xD5, 0x5A, 0x74, 0x48, 0xFC,
+
+    0xE5, 0x58, 0xDB, 0xEF, 0x53, 0xEE, 0xCD, 0xE3, 0xD3, 0xFC,
+    0xCF, 0xC1, 0xAE, 0xA0, 0x8A, 0x89, 0xA9, 0x87, 0x47, 0x5D,
+    0x12, 0xFD, 0x95, 0x0D, 0x83, 0xCF, 0xA4, 0x17, 0x32, 0xBC,
+    0x50, 0x9D, 0x0D, 0x1A, 0xC4, 0x3A, 0x03, 0x36, 0xDE, 0xF9,
+    0x6F, 0xDA, 0x41, 0xD0, 0x77, 0x4A, 0x35, 0x71,
+
+    0xDC, 0xFB, 0xEC, 0x7A, 0xAC, 0xF3, 0x19, 0x64, 0x72, 0x16,
+    0x9E, 0x83, 0x84, 0x30, 0x36, 0x7F, 0x66, 0xEE, 0xBE, 0x3C,
+    0x6E, 0x70, 0xC4, 0x16, 0xDD, 0x5F, 0x0C, 0x68, 0x75, 0x9D,
+    0xD1, 0xFF, 0xF8, 0x3F, 0xA4, 0x01, 0x42, 0x20, 0x9D, 0xFF,
+    0x5E, 0xAA, 0xD9, 0x6D, 0xB9, 0xE6, 0x38, 0x6C,
+
+    0x11, 0x18, 0x73, 0x31, 0xC2, 0x79, 0x96, 0x2D, 0x93, 0xD6,
+    0x04, 0x24, 0x3F, 0xD5, 0x92, 0xCB, 0x9D, 0x0A, 0x92, 0x6F,
+    0x42, 0x2E, 0x47, 0x18, 0x75, 0x21, 0x28, 0x7E, 0x71, 0x56,
+    0xC5, 0xC4, 0xD6, 0x03, 0x13, 0x55, 0x69, 0xB9, 0xE9, 0xD0,
+    0x9C, 0xF5, 0xD4, 0xA2, 0x70, 0xF5, 0x97, 0x46
+};
+
+/* An example for testing from RFC5903, section 8.3 */
+static unsigned char TEST_ECDH_NIST_P_521[] = {
+    0x00, 0x37, 0xAD, 0xE9, 0x31, 0x9A, 0x89, 0xF4, 0xDA, 0xBD,
+    0xB3, 0xEF, 0x41, 0x1A, 0xAC, 0xCC, 0xA5, 0x12, 0x3C, 0x61,
+    0xAC, 0xAB, 0x57, 0xB5, 0x39, 0x3D, 0xCE, 0x47, 0x60, 0x81,
+    0x72, 0xA0, 0x95, 0xAA, 0x85, 0xA3, 0x0F, 0xE1, 0xC2, 0x95,
+    0x2C, 0x67, 0x71, 0xD9, 0x37, 0xBA, 0x97, 0x77, 0xF5, 0x95,
+    0x7B, 0x26, 0x39, 0xBA, 0xB0, 0x72, 0x46, 0x2F, 0x68, 0xC2,
+    0x7A, 0x57, 0x38, 0x2D, 0x4A, 0x52,
+
+    0x00, 0x15, 0x41, 0x7E, 0x84, 0xDB, 0xF2, 0x8C, 0x0A, 0xD3,
+    0xC2, 0x78, 0x71, 0x33, 0x49, 0xDC, 0x7D, 0xF1, 0x53, 0xC8,
+    0x97, 0xA1, 0x89, 0x1B, 0xD9, 0x8B, 0xAB, 0x43, 0x57, 0xC9,
+    0xEC, 0xBE, 0xE1, 0xE3, 0xBF, 0x42, 0xE0, 0x0B, 0x8E, 0x38,
+    0x0A, 0xEA, 0xE5, 0x7C, 0x2D, 0x10, 0x75, 0x64, 0x94, 0x18,
+    0x85, 0x94, 0x2A, 0xF5, 0xA7, 0xF4, 0x60, 0x17, 0x23, 0xC4,
+    0x19, 0x5D, 0x17, 0x6C, 0xED, 0x3E,
+
+    0x01, 0x7C, 0xAE, 0x20, 0xB6, 0x64, 0x1D, 0x2E, 0xEB, 0x69,
+    0x57, 0x86, 0xD8, 0xC9, 0x46, 0x14, 0x62, 0x39, 0xD0, 0x99,
+    0xE1, 0x8E, 0x1D, 0x5A, 0x51, 0x4C, 0x73, 0x9D, 0x7C, 0xB4,
+    0xA1, 0x0A, 0xD8, 0xA7, 0x88, 0x01, 0x5A, 0xC4, 0x05, 0xD7,
+    0x79, 0x9D, 0xC7, 0x5E, 0x7B, 0x7D, 0x5B, 0x6C, 0xF2, 0x26,
+    0x1A, 0x6A, 0x7F, 0x15, 0x07, 0x43, 0x8B, 0xF0, 0x1B, 0xEB,
+    0x6C, 0xA3, 0x92, 0x6F, 0x95, 0x82,
+
+    0x01, 0x45, 0xBA, 0x99, 0xA8, 0x47, 0xAF, 0x43, 0x79, 0x3F,
+    0xDD, 0x0E, 0x87, 0x2E, 0x7C, 0xDF, 0xA1, 0x6B, 0xE3, 0x0F,
+    0xDC, 0x78, 0x0F, 0x97, 0xBC, 0xCC, 0x3F, 0x07, 0x83, 0x80,
+    0x20, 0x1E, 0x9C, 0x67, 0x7D, 0x60, 0x0B, 0x34, 0x37, 0x57,
+    0xA3, 0xBD, 0xBF, 0x2A, 0x31, 0x63, 0xE4, 0xC2, 0xF8, 0x69,
+    0xCC, 0xA7, 0x45, 0x8A, 0xA4, 0xA4, 0xEF, 0xFC, 0x31, 0x1F,
+    0x5C, 0xB1, 0x51, 0x68, 0x5E, 0xB9,
+
+    0x00, 0xD0, 0xB3, 0x97, 0x5A, 0xC4, 0xB7, 0x99, 0xF5, 0xBE,
+    0xA1, 0x6D, 0x5E, 0x13, 0xE9, 0xAF, 0x97, 0x1D, 0x5E, 0x9B,
+    0x98, 0x4C, 0x9F, 0x39, 0x72, 0x8B, 0x5E, 0x57, 0x39, 0x73,
+    0x5A, 0x21, 0x9B, 0x97, 0xC3, 0x56, 0x43, 0x6A, 0xDC, 0x6E,
+    0x95, 0xBB, 0x03, 0x52, 0xF6, 0xBE, 0x64, 0xA6, 0xC2, 0x91,
+    0x2D, 0x4E, 0xF2, 0xD0, 0x43, 0x3C, 0xED, 0x2B, 0x61, 0x71,
+    0x64, 0x00, 0x12, 0xD9, 0x46, 0x0F,
+
+    0x01, 0x5C, 0x68, 0x22, 0x63, 0x83, 0x95, 0x6E, 0x3B, 0xD0,
+    0x66, 0xE7, 0x97, 0xB6, 0x23, 0xC2, 0x7C, 0xE0, 0xEA, 0xC2,
+    0xF5, 0x51, 0xA1, 0x0C, 0x2C, 0x72, 0x4D, 0x98, 0x52, 0x07,
+    0x7B, 0x87, 0x22, 0x0B, 0x65, 0x36, 0xC5, 0xC4, 0x08, 0xA1,
+    0xD2, 0xAE, 0xBB, 0x8E, 0x86, 0xD6, 0x78, 0xAE, 0x49, 0xCB,
+    0x57, 0x09, 0x1F, 0x47, 0x32, 0x29, 0x65, 0x79, 0xAB, 0x44,
+    0xFC, 0xD1, 0x7F, 0x0F, 0xC5, 0x6A,
+
+    0x01, 0x14, 0x4C, 0x7D, 0x79, 0xAE, 0x69, 0x56, 0xBC, 0x8E,
+    0xDB, 0x8E, 0x7C, 0x78, 0x7C, 0x45, 0x21, 0xCB, 0x08, 0x6F,
+    0xA6, 0x44, 0x07, 0xF9, 0x78, 0x94, 0xE5, 0xE6, 0xB2, 0xD7,
+    0x9B, 0x04, 0xD1, 0x42, 0x7E, 0x73, 0xCA, 0x4B, 0xAA, 0x24,
+    0x0A, 0x34, 0x78, 0x68, 0x59, 0x81, 0x0C, 0x06, 0xB3, 0xC7,
+    0x15, 0xA3, 0xA8, 0xCC, 0x31, 0x51, 0xF2, 0xBE, 0xE4, 0x17,
+    0x99, 0x6D, 0x19, 0xF3, 0xDD, 0xEA,
+};
+
+enum ecdh_data { SIDE_A_KEY, SIDE_B_KEY, SHARED_SECRET };
+static void *generate_test_ecdh_data(const int group_id,
+                                     enum ecdh_data request_data)
+{
+    uint8_t        *data_set;
+    int             size;
+    EC_KEY         *key;
+    const EC_GROUP *group;
+    const BIGNUM   *k_priv = NULL;
+    const BIGNUM   *k_pubx = NULL;
+    const BIGNUM   *k_puby = NULL;
+    EC_POINT       *k_pub  = NULL;
+
+    switch (group_id) {
+    case HIP_DH_NIST_P_256:
+        data_set = TEST_ECDH_NIST_P_256;
+        break;
+
+    case HIP_DH_NIST_P_384:
+        data_set = TEST_ECDH_NIST_P_384;
+        break;
+
+    case HIP_DH_NIST_P_521:
+        data_set = TEST_ECDH_NIST_P_521;
+        break;
+
+    default:
+        return NULL;
+    }
+
+    size = hip_get_dh_size(group_id) / 2;
+
+    switch (request_data) {
+    case SIDE_A_KEY:
+        key    = hip_generate_ecdh_key(group_id);
+        group  = EC_KEY_get0_group(key);
+        k_priv = BN_bin2bn(data_set + size * TEST_ECDH_PRIV_A, size, NULL);
+        k_pubx = BN_bin2bn(data_set + size * TEST_ECDH_PUBX_A, size, NULL);
+        k_puby = BN_bin2bn(data_set + size * TEST_ECDH_PUBY_A, size, NULL);
+        k_pub  = EC_POINT_new(group);
+
+        EC_POINT_set_affine_coordinates_GFp(group, k_pub, k_pubx, k_puby, 
NULL);
+        EC_KEY_set_public_key(key, k_pub);
+        EC_KEY_set_private_key(key, k_priv);
+
+        return key;
+
+    case SIDE_B_KEY:
+        key    = hip_generate_ecdh_key(group_id);
+        group  = EC_KEY_get0_group(key);
+        k_priv = BN_bin2bn(data_set + size * TEST_ECDH_PRIV_B, size, NULL);
+        k_pubx = BN_bin2bn(data_set + size * TEST_ECDH_PUBX_B, size, NULL);
+        k_puby = BN_bin2bn(data_set + size * TEST_ECDH_PUBY_B, size, NULL);
+        k_pub  = EC_POINT_new(group);
+
+        EC_POINT_set_affine_coordinates_GFp(group, k_pub, k_pubx, k_puby, 
NULL);
+        EC_KEY_set_public_key(key, k_pub);
+        EC_KEY_set_private_key(key, k_priv);
+
+        return key;
+
+    case SHARED_SECRET:
+        return data_set + size * TEST_ECDH_SHARED;
+    }
+
+    return NULL;
+}
+
 START_TEST(test_create_ecdsa_key_invalid_id)
 {
     HIP_DEBUG("Trying to create some invalid ECDSA keys.\n");
@@ -244,6 +467,108 @@
 }
 END_TEST
 
+#define TEST_ECDH_GROUP_SIZE 3
+static int TEST_ECDH_GROUPS[TEST_ECDH_GROUP_SIZE] = { HIP_DH_NIST_P_256,
+                                                      HIP_DH_NIST_P_384,
+                                                      HIP_DH_NIST_P_521 };
+
+START_TEST(test_generate_ecdh_key_invalid_group_id)
+{
+    fail_unless(hip_generate_ecdh_key(0) == NULL);
+    fail_unless(hip_generate_ecdh_key(-1) == NULL);
+    fail_unless(hip_generate_ecdh_key(HIP_MAX_DH_GROUP_ID) == NULL);
+}
+END_TEST
+
+START_TEST(test_generate_ecdh_key_valid_group_id)
+{
+    EC_KEY *key;
+    int     i;
+
+    for (i = 0; i < TEST_ECDH_GROUP_SIZE; i++) {
+        key = hip_generate_ecdh_key(TEST_ECDH_GROUPS[i]);
+        fail_if(key == NULL || EC_KEY_check_key(key) == 0);
+    }
+}
+END_TEST
+
+START_TEST(test_ecdh_generate_2_keys_and_share_secret)
+{
+    EC_KEY *key1;
+    EC_KEY *key2;
+    int     out1, out2;
+    int     len1, len2;
+    int     i;
+    int     group_id;
+    int     pubkey_size;
+
+    for (i = 0; i < TEST_ECDH_GROUP_SIZE; i++) {
+        group_id    = TEST_ECDH_GROUPS[i];
+        pubkey_size = hip_get_dh_size(group_id);
+        fail_if(pubkey_size <= 0);
+
+        key1 = hip_generate_ecdh_key(group_id);
+        key2 = hip_generate_ecdh_key(group_id);
+        fail_if(key1 == NULL || key2 == NULL);
+
+        const EC_POINT *k1pub = EC_KEY_get0_public_key(key1);
+        const EC_POINT *k2pub = EC_KEY_get0_public_key(key2);
+
+        len1 = len2 = pubkey_size / 2;
+        unsigned char share1[len1];
+        unsigned char share2[len2];
+
+        out1 = ECDH_compute_key(share1, len1, k2pub, key1, NULL);
+        out2 = ECDH_compute_key(share2, len2, k1pub, key2, NULL);
+        fail_if(out1 <= 0 || out2 <= 0);
+        fail_if(out1 != len1 && out2 != len2);
+        fail_if(memcmp(share1, share2, len1) != 0);
+    }
+}
+END_TEST
+
+START_TEST(test_ecdh_encode_publickey)
+{
+    int i, group_id, key_size;
+
+    for (i = 0; i < TEST_ECDH_GROUP_SIZE; i++) {
+        group_id = TEST_ECDH_GROUPS[i];
+        key_size = hip_get_dh_size(group_id);
+        uint8_t out[key_size];
+        EC_KEY *key = hip_generate_ecdh_key(group_id);
+        fail_if(hip_encode_ecdh_publickey(key, out, key_size) != key_size);
+    }
+}
+END_TEST
+
+START_TEST(test_ecdh_gen_shared_key)
+{
+    int i, group_id, size, res;
+
+    for (i = 0; i < TEST_ECDH_GROUP_SIZE; i++) {
+        group_id = TEST_ECDH_GROUPS[i];
+        size     = hip_get_dh_size(group_id) / 2;
+        uint8_t pub[size * 2];
+        uint8_t out[size];
+        EC_KEY *a      = generate_test_ecdh_data(group_id, SIDE_A_KEY);
+        EC_KEY *b      = generate_test_ecdh_data(group_id, SIDE_B_KEY);
+        void   *secret = generate_test_ecdh_data(group_id, SHARED_SECRET);
+        fail_if(a == NULL || b == NULL || secret == NULL);
+        fail_if(EC_KEY_check_key(a) == 0 || EC_KEY_check_key(b) == 0);
+
+        hip_encode_ecdh_publickey(b, pub, size * 2);
+        res = hip_gen_ecdh_shared_key(a, pub, pub + size, size, out, size);
+        fail_if(res != size);
+        fail_if(memcmp(secret, out, size) != 0);
+
+        hip_encode_ecdh_publickey(a, pub, size * 2);
+        res = hip_gen_ecdh_shared_key(b, pub, pub + size, size, out, size);
+        fail_if(res != size);
+        fail_if(memcmp(secret, out, size) != 0);
+    }
+}
+END_TEST
+
 Suite *libcore_crypto(void)
 {
     Suite *s = suite_create("libcore/crypto");
@@ -257,6 +582,11 @@
     tcase_add_test(tc_core, test_load_invalid_ecdsa_key);
     tcase_add_test(tc_core, test_impl_ecdsa_sign_verify);
     tcase_add_test(tc_core, test_invalid_impl_ecdsa_sign_verify);
+    tcase_add_test(tc_core, test_generate_ecdh_key_invalid_group_id);
+    tcase_add_test(tc_core, test_generate_ecdh_key_valid_group_id);
+    tcase_add_test(tc_core, test_ecdh_generate_2_keys_and_share_secret);
+    tcase_add_test(tc_core, test_ecdh_encode_publickey);
+    tcase_add_test(tc_core, test_ecdh_gen_shared_key);
 
     suite_add_tcase(s, tc_core);
 

Other related posts: