[hipl-dev] [Branch ~hipl-core/hipl/trunk] Rev 6437: Merged lp:~hipl-core/hipl/hipv2-dh-ecdh

  • From: noreply@xxxxxxxxxxxxx
  • To: HIPL core team <hipl-dev@xxxxxxxxxxxxx>
  • Date: Tue, 22 Oct 2013 13:51:27 -0000

Merge authors:
  Miika Komu (miika-iki)
  Xin (eric-nevup)
Related merge proposals:
  https://code.launchpad.net/~hipl-core/hipl/hipv2-dh-ecdh/+merge/131786
  proposed by: Miika Komu (miika-iki)
  review: Needs Information - Diego Biurrun (diego-biurrun)
  review: Approve - Christof Mroz (christof-mroz)
------------------------------------------------------------
revno: 6437 [merge]
committer: Miika Komu <miika@xxxxxx>
branch nick: hipl
timestamp: Tue 2013-10-22 16:50:32 +0300
message:
  Merged lp:~hipl-core/hipl/hipv2-dh-ecdh
modified:
  libcore/builder.c
  libcore/crypto.c
  libcore/crypto.h
  libcore/protodefs.h
  libhipl/cookie.c
  libhipl/cookie.h
  libhipl/dh.c
  libhipl/dh.h
  libhipl/hidb.c
  libhipl/hidb.h
  libhipl/input.c
  libhipl/netdev.c
  libhipl/output.c
  libhipl/output.h
  test/libcore/crypto.c


--
lp:hipl
https://code.launchpad.net/~hipl-core/hipl/trunk

Your team HIPL core team is subscribed to branch lp:hipl.
To unsubscribe from this branch go to 
https://code.launchpad.net/~hipl-core/hipl/trunk/+edit-subscription
=== modified file 'libcore/builder.c'
--- libcore/builder.c   2013-08-19 18:30:29 +0000
+++ libcore/builder.c   2013-10-22 12:34:28 +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    2013-09-20 06:29:24 +0000
+++ libcore/crypto.c    2013-10-22 12:34:28 +0000
@@ -46,6 +46,7 @@
  */
 
 #include <errno.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -68,6 +69,12 @@
 #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 +332,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 +712,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;
+
+    switch (group_id) {
+    case HIP_DH_NIST_P_256:
+        nid = NID_X9_62_prime256v1;
+        break;
+    case HIP_DH_NIST_P_384:
+        nid = NID_secp384r1;
+        break;
+    case HIP_DH_NIST_P_521:
+        nid = NID_secp521r1;
+        break;
+    default:
+        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;
+    unsigned int    err       = 1;
+
+    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");
+
+    err = ECDH_compute_key(shared_key, outlen, peer_pub, key, NULL);
+    HIP_IFEL(err == 0 || err != peer_len, 0,
+             "Failed to compute the ECDH shared key\n");
+
+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");
+
+    err = EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(key),
+                                              EC_KEY_get0_public_key(key),
+                                              pubx, puby, NULL);
+    HIP_IFEL(err == 0, -1,
+             "Failed to get x,y coordinates from the ECDH key\n");
+
+    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);
+    err = 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 +891,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-07-28 21:18:08 +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-07-20 07:52:59 +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-11-01 15:06:33 +0000
@@ -177,83 +177,99 @@
 }
 
 /**
- * get a copy of R1entry structure
+ * Get a copy of R1entry structure.
  *
  * @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.
+ * @param dh_group_id Diffie Hellman group ID. -1 for HIPv1, otherwise return
+                      R1 for HIPv2
+ * @return            A R1 packet copy on success, NULL on 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, const int dh_group_id)
 {
-    struct hip_common    *err         = NULL, *r1 = NULL;
-    struct hip_r1entry   *hip_r1table = NULL;
-    struct local_host_id *hid         = NULL;
+    struct hip_common    *r1         = NULL;
+    struct hip_common    *r1_matched = NULL;
+    struct local_host_id *hid        = NULL;
     int                   idx, len;
 
     /* Find the proper R1 table and copy the R1 message from the table */
-    HIP_IFEL(!(hid = hip_get_hostid_entry_by_lhi_and_algo(our_hit, 
HIP_ANY_ALGO, -1)),
-             NULL, "Unknown HIT\n");
+    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;
+    }
 
-    hip_r1table = hid->r1[hip_version];
-    idx         = calc_cookie_idx(ip_i, ip_r);
+    idx = calc_cookie_idx(ip_i, ip_r);
     HIP_DEBUG("Calculated index: %d\n", idx);
 
+    if (dh_group_id == -1) {
+        r1_matched = &hid->r1[idx].buf.msg;
+    } else {
+        r1_matched = &hid->r1_v2[dh_group_id][idx].buf.msg;
+    }
     /* Create a copy of the found entry */
-    len = hip_get_msg_total_len(&hip_r1table[idx].buf.msg);
-    r1  = hip_msg_alloc();
-    memcpy(r1, &hip_r1table[idx].buf.msg, len);
-    err = r1;
-
-out_err:
-    if (!err) {
-        free(r1);
-    }
-
-    return err;
+    len = hip_get_msg_total_len(r1_matched);
+    if (len <= 0) {
+        HIP_ERROR("Invalid r1 entry\n");
+        return NULL;
+    }
+
+    if ((r1 = hip_msg_alloc()) == NULL) {
+        return NULL;
+    }
+
+    memcpy(r1, r1_matched, len);
+
+    return r1;
 }
 
 /**
- * precreate an R1 packet
+ * HIPv1 & HIPv2: precreate R1 entries
  *
- * @param r1table     a pointer to R1 table structure
+ * @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;
+    const uint8_t cookie_k = get_cookie_difficulty();
+    int           i, j, group_id;
+
     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++) {
+            hip_msg_init(&id_entry->r1_v2[group_id][i].buf.msg);
+
+            if (hip_create_r1_v2(&id_entry->r1_v2[group_id][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 +282,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 +309,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 +369,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 +388,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-11-01 15:06:33 +0000
@@ -30,32 +30,23 @@
 #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 *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-31 17:00:21 +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();
 }
 
@@ -203,12 +429,15 @@
 {
     uint32_t supported_groups;
 
-    supported_groups = (1 << HIP_DH_OAKLEY_1 |
-                        1 << HIP_DH_OAKLEY_5 |
-                        1 << HIP_DH_384);
+    supported_groups = (1 << HIP_DH_OAKLEY_1   |
+                        1 << HIP_DH_OAKLEY_5   |
+                        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-07-20 07:52:59 +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-07-20 07:52:59 +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-07-28 21:18:08 +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-31 17:00:21 +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,11 +1526,40 @@
              -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),
+    /* 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) {
+        dh_group_id = 0;
+    }
+    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");
 

=== modified file 'libhipl/netdev.c'
--- libhipl/netdev.c    2012-06-03 10:26:55 +0000
+++ libhipl/netdev.c    2012-07-28 21:18:08 +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    2013-08-19 18:30:29 +0000
+++ libhipl/output.c    2013-10-22 12:34:28 +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);
 
@@ -595,38 +672,25 @@
 }
 
 /**
- * Construct a new R1 packet payload
+ * Continue to build R1 packet after the Diffie-Hellman parameter.
  *
- * @param msg          points to a message object 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 msg          pointer to a message backed by HIP_MAX_PACKET bytes of
+ *                     memory to which the R1 message is written.
  * @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,
-                  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 uint8_t hip_version)
+static int build_r1_after_dh_param(struct hip_common *const msg,
+                                   int (*sign)(void *const key, struct 
hip_common *const m),
+                                   void *const private_key,
+                                   const struct hip_host_id *const host_id_pub)
 {
-    int            err = 0;
     struct hip_srv service_list[HIP_TOTAL_EXISTING_SERVICES];
-    uint8_t       *dh_data1      = NULL, *dh_data2 = NULL;
+    unsigned int   service_count = 0;
+    int            err           = 0;
     char           order[]       = "000";
-    int            dh_size1      = 0, dh_size2 = 0;
-    int            mask          = 0, i = 0, written1 = 0, written2 = 0;
-    unsigned int   service_count = 0;
-
-    enum number_dh_keys_t { ONE, TWO };
-    enum number_dh_keys_t number_dh_keys = TWO;
-
+    int            i             = 0;
 
     /* Supported HIP and ESP transforms. */
     hip_transform_suite transform_hip_suite[] = {
@@ -662,6 +726,102 @@
         }
     }
 
+    /* Parameter HIP transform. */
+    err = hip_build_param_hip_transform(msg,
+                                        transform_hip_suite,
+                                        sizeof(transform_hip_suite) /
+                                        sizeof(hip_transform_suite));
+    if (err) {
+        HIP_ERROR("Building of HIP transform failed\n");
+        return err;
+    }
+
+    /* Parameter HOST_ID */
+    if ((err = hip_build_param_host_id(msg, host_id_pub))) {
+        HIP_ERROR("Building of host id failed\n");
+        return err;
+    }
+
+    /* 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. */
+    err = hip_build_param_esp_transform(msg, transform_esp_suite,
+                                        sizeof(transform_esp_suite) /
+                                        sizeof(hip_transform_suite));
+    if (err) {
+        HIP_ERROR("Building of ESP transform failed\n");
+        return err;
+    }
+
+    /********** ESP-PROT transform (OPTIONAL) **********/
+
+    if ((err = esp_prot_r1_add_transforms(msg))) {
+        HIP_ERROR("failed to add optional esp transform parameter\n");
+        return err;
+    }
+
+    /********** ECHO_REQUEST_SIGN (OPTIONAL) *********/
+
+    //HIP_HEXDUMP("Pubkey:", host_id_pub, 
hip_get_param_total_len(host_id_pub));
+
+    /* Parameter Signature 2 */
+
+    if ((err = sign(private_key, msg))) {
+        HIP_ERROR("Signing of R1 failed.\n");
+        return err;
+    }
+
+    /* Parameter ECHO_REQUEST (OPTIONAL) */
+
+    /* Fill puzzle parameters */
+    {
+        struct hip_puzzle *pz;
+
+        if (!(pz = hip_get_param_readwrite(msg, HIP_PARAM_PUZZLE))) {
+            HIP_ERROR("Internal error\n");
+            return -1;
+        }
+
+        /* hardcode kludge */
+        pz->opaque[0] = 'H';
+        pz->opaque[1] = 'I';
+        get_random_bytes(pz->I, PUZZLE_LENGTH);
+    }
+
+    return 0;
+}
+
+/**
+ * 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 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
+ * @return             0 on success, a non-zero value on error.
+ */
+int hip_create_r1(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)
+{
+    int      err      = 0;
+    uint8_t *dh_data1 = NULL, *dh_data2 = NULL;
+    int      dh_size1 = 0, dh_size2 = 0;
+    int      mask     = 0, written1 = 0, written2 = 0;
+
+    enum number_dh_keys_t { ONE, TWO };
+    enum number_dh_keys_t number_dh_keys = TWO;
+
     /* Initialize the message buffer as the message builder depends on it. */
     hip_msg_init(msg);
 
@@ -682,7 +842,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) *********/
 
@@ -714,58 +874,9 @@
                  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';
-        //pz->opaque[2] = 'P';
-        get_random_bytes(pz->I, PUZZLE_LENGTH);
+    if ((err = build_r1_after_dh_param(msg, sign, private_key, host_id_pub)) 
!= 0) {
+        HIP_ERROR("Failed to build R1 after the DH parameter.");
     }
-
     /* Packet ready */
 
 out_err:
@@ -776,6 +887,86 @@
 }
 
 /**
+ * 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;
+    uint8_t *dh_data = NULL;
+    int      dh_size = 0;
+    int      mask    = 0, written = 0;
+
+    /* 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");
+
+    if ((err = build_r1_after_dh_param(msg, sign, private_key, host_id_pub)) 
!= 0) {
+        HIP_ERROR("Failed to build R1 after the DH parameter.");
+    }
+    /* 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 +1057,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, -1)),
+                 -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(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-07-20 07:52:59 +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-31 17:00:21 +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,225 @@
 #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 +457,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 +572,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:

  • » [hipl-dev] [Branch ~hipl-core/hipl/trunk] Rev 6437: Merged lp:~hipl-core/hipl/hipv2-dh-ecdh - noreply