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

Proposed by Xin
Status: Superseded
Proposed branch: lp:~hipl-core/hipl/hipv2-dh-ecdh
Merge into: lp:hipl
Diff against target: 2195 lines (+1445/-227)
15 files modified
libcore/builder.c (+6/-5)
libcore/crypto.c (+177/-1)
libcore/crypto.h (+33/-6)
libcore/protodefs.h (+1/-0)
libhipl/cookie.c (+92/-34)
libhipl/cookie.h (+11/-17)
libhipl/dh.c (+297/-68)
libhipl/dh.h (+14/-6)
libhipl/hidb.c (+6/-11)
libhipl/hidb.h (+19/-3)
libhipl/input.c (+122/-26)
libhipl/netdev.c (+19/-2)
libhipl/output.c (+305/-45)
libhipl/output.h (+12/-2)
test/libcore/crypto.c (+331/-1)
To merge this branch: bzr merge lp:~hipl-core/hipl/hipv2-dh-ecdh
Reviewer Review Type Date Requested Status
Miika Komu Needs Fixing
Christof Mroz Needs Information
Diego Biurrun Needs Fixing
Review via email: mp+123405@code.launchpad.net

This proposal has been superseded by a proposal from 2012-10-28.

Description of the change

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.

To post a comment you must log in.
Revision history for this message
Miika Komu (miika-iki) wrote :

Seems ok to me. I would suggest merging on in a week, let's say 14.9.2012, unless somebody has comments or requests more time.

review: Approve
Revision history for this message
Diego Biurrun (diego-biurrun) wrote :

 review needs-fixing

On Sat, Sep 08, 2012 at 08:35:22AM +0000, Xin wrote:
> Xin has proposed merging lp:~hipl-core/hipl/hipv2-dh-ecdh into lp:hipl.
>
> Requested reviews:
> HIPL core team (hipl-core)
>
> For more details, see:
> https://code.launchpad.net/~hipl-core/hipl/hipv2-dh-ecdh/+merge/123405
>
> 8 September 2012
>
> Revise code based on Diego's review comments.
> Sorry for my delay.

You sort of addressed my comments, but I'm really not sure how thorough.
In order to check for simple oversights I searched this email for "llips"
and immediately caught an error I pointed out but you failed to fix.

It seems that all newly-added memory allocations are checked now. This
is good; unfortunately unchecked memory allocations still happen left
and right in HIPL.

This whole review business is rather pointless if the comments are not
addressed. If I can find mistakes in your revised code literally within
seconds then we have serious quality control issues as a project.

Maybe this is just a minor oversight about a minor issue, maybe not.
Bugs tend to appear in clusters, so I'm suspicious. How could we fix
this? Would some sort of checklist or a list of common mistakes to
look out for help?

> --- libhipl/cookie.c 2012-06-03 10:26:55 +0000
> +++ libhipl/cookie.c 2012-09-08 08:34:18 +0000
> @@ -219,41 +218,93 @@
>
> +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)
> +{
> + /* 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) {

if (

Is your uncrustify hook not working?

Diego

review: Needs Fixing
Revision history for this message
Christof Mroz (christof-mroz) wrote :
Download full text (10.6 KiB)

Looks good overall, I found one potential bug though (the thing about possibly mismatched indices below), but I'm not sure.
The other comments are not critical.

> === modified file 'libcore/builder.c'
> --- libcore/builder.c 2012-07-13 13:16:17 +0000
> +++ libcore/builder.c 2012-09-08 08:34:18 +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));
> -

Why do you let this pass now? Does it make sense to specify anything other than 16 or 32 bit?

> @@ -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 */
> };

Can you easily avoid magic numbers here?

> @@ -701,6 +711,172 @@
> + 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));

Would

RAND_seed(&tv.sec, sizeof(tv.sec));
RAND_seed(&tv.usec, sizeof(tv.usec));

or even

RAND_seed(&tv, sizeof(tv)); // many predictable bytes though. RAND_add()?

work too? I don't know about crypto, but the number of different byte sequences
you can produce this way should be exactly the same as with sprintf().

> + 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);

Can this fail? Also applies to the other openssl *_new() functions.

> + 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");

Does checking for "out != peer_len" suffice?

> + if (key == NULL || out == NULL || outlen < 0 ||
> + EC_KEY_check_key(key) == 0) {
> + HIP_ERROR("Invalid input\n");
> + return -1;
> + }

The first three conditions look like they should be assertions, to me.
The last one too perhaps, because you should have checked the key up to this point anyway.

> === modified file 'libcore/crypto.h'
> --- libcore/crypto.h 2012-05-12 10:21:32 +0000
> +++ libcore/crypto.h 2012-09-08 08:34:18 +0000
> @@ -51,15 +52,25 @@
>
> /* These should be c...

review: Needs Information
Revision history for this message
Xin (eric-nevup) wrote :

Hi,

On 09/10/2012 03:19 PM, Diego Biurrun wrote:
> review needs-fixing
> You sort of addressed my comments, but I'm really not sure how thorough.
> In order to check for simple oversights I searched this email for "llips"
> and immediately caught an error I pointed out but you failed to fix.

oops, I read the merge diff line by line before I commit it, but it
seems that I still miss some points.

>
> It seems that all newly-added memory allocations are checked now. This
> is good; unfortunately unchecked memory allocations still happen left
> and right in HIPL.

This is not related to this merge right? If we should discuss how to fix
them, I think it is better to put it into another mail thread, or fire a
bug?

>
> This whole review business is rather pointless if the comments are not
> addressed. If I can find mistakes in your revised code literally within
> seconds then we have serious quality control issues as a project.

People do make mistakes, if you check how many "llips" I have fixed and
how I fix your other comments, maybe you will feel a sense of relief.

>> --- libhipl/cookie.c 2012-06-03 10:26:55 +0000
>> +++ libhipl/cookie.c 2012-09-08 08:34:18 +0000
>> @@ -219,41 +218,93 @@
>>
>> +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)
>> +{
>> + /* 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) {
> if (
>
> Is your uncrustify hook not working?

Yeah, I turned it off because some of code changes will violate it, but
I should have checked other codes. you have my apology.

--
Best regards,
Xin Gu

Revision history for this message
Xin (eric-nevup) wrote :

Hi,

On 09/13/2012 06:33 AM, Christof Mroz wrote:
> Review: Needs Information
>
> Looks good overall, I found one potential bug though (the thing about possibly mismatched indices below), but I'm not sure.
> The other comments are not critical.
>
>> === modified file 'libcore/builder.c'
>> --- libcore/builder.c 2012-07-13 13:16:17 +0000
>> +++ libcore/builder.c 2012-09-08 08:34:18 +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));
>> -
> Why do you let this pass now? Does it make sense to specify anything other than 16 or 32 bit?

I use this function to build the DH_GROUP_LIST parameter, which is a
list of 8bit items, so I remove this assertion because otherwise you
need to do something like:

if (item_size != sizeof(uint16_t) || item_size != sizeof(uint32_t)) {
     convert_byte_order(...);
}

I think this extra if statement is unnecessary since in the
convert_byte_order function we have checked it already.

====

Thanks for your other comments. I recently have stacked many mails and
realized that I have blocked many processes. My problem is that I have
went back to China and started to work for a startup company. We have a
quite tight development timetable on which I have to spend most of my
time. I will try to fix the HIPL ECDH branch as soon as possible, but it
is really difficult for me to give a time guarantee. If it is urgent,
maybe someone can continue this work since the branch is already owned
by hipl-core,

--
Best regards,
Xin Gu

Revision history for this message
Christof Mroz (christof-mroz) wrote :

On 15.09.2012 18:46, Xin wrote:
>>> - HIP_ASSERT(item_size == sizeof(uint16_t) || item_size == sizeof(uint32_t));
>> Why do you let this pass now? Does it make sense to specify anything other than 16 or 32 bit?
>
> I use this function to build the DH_GROUP_LIST parameter, which is a
> list of 8bit items, so I remove this assertion because otherwise you
> need to do something like:

Ah yes sorry, you wrote that in the docs. Okay then.

> Thanks for your other comments. I recently have stacked many mails and
> realized that I have blocked many processes. My problem is that I have
> went back to China and started to work for a startup company. We have a
> quite tight development timetable on which I have to spend most of my
> time. I will try to fix the HIPL ECDH branch as soon as possible, but it
> is really difficult for me to give a time guarantee. If it is urgent,
> maybe someone can continue this work since the branch is already owned
> by hipl-core,

Only one of my comments was critical I think, and maybe it is no bug at
all. It's the one concerning the possible mixup of array indices. I'll
repeat the one:

On 13.09.2012 00:33, Christof Mroz wrote:
>> + 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[group_id][i].buf.msg, hit, sign,
>> + privkey, pubkey, cookie_k, group_id)) {
>> + HIP_ERROR("Unable to precreate R1_v2\n");
>> + return -1;
>> + }
>
> You use index j for hip_msg_init(), but index group_id for hip_create_r1_v2(). Is this intentional?

Good luck with the startup.

Revision history for this message
Miika Komu (miika-iki) wrote :

Hi,

On 09/15/2012 07:46 PM, Xin wrote:
> Thanks for your other comments. I recently have stacked many mails and
> realized that I have blocked many processes. My problem is that I have
> went back to China and started to work for a startup company. We have a
> quite tight development timetable on which I have to spend most of my
> time. I will try to fix the HIPL ECDH branch as soon as possible, but it
> is really difficult for me to give a time guarantee. If it is urgent,
> maybe someone can continue this work since the branch is already owned
> by hipl-core,

Xin, you efforts are highly appreciated. Thanks for contributing even
though you're not working for us anymore. Let's try to get this code
integrated so that we start interoperating the code with OpenHIP at some
point - this is important also for the standardization.

Revision history for this message
Diego Biurrun (diego-biurrun) wrote :
Download full text (3.4 KiB)

On Sun, Sep 16, 2012 at 12:15:22AM +0800, Xin Gu wrote:
> On 09/10/2012 03:19 PM, Diego Biurrun wrote:
> > review needs-fixing
> >You sort of addressed my comments, but I'm really not sure how thorough.
> >In order to check for simple oversights I searched this email for "llips"
> >and immediately caught an error I pointed out but you failed to fix.
>
> oops, I read the merge diff line by line before I commit it, but it
> seems that I still miss some points.
>
> >It seems that all newly-added memory allocations are checked now. This
> >is good; unfortunately unchecked memory allocations still happen left
> >and right in HIPL.
>
> This is not related to this merge right? If we should discuss how to
> fix them, I think it is better to put it into another mail thread,
> or fire a bug?

Yes. While we do have the boyscout rule, we cannot expect you to fix
all unchecked memory allocation problems in HIPL. Of course you should
not make the problem worse by adding new ones though.

> >This whole review business is rather pointless if the comments are not
> >addressed. If I can find mistakes in your revised code literally within
> >seconds then we have serious quality control issues as a project.
>
> People do make mistakes, if you check how many "llips" I have fixed
> and how I fix your other comments, maybe you will feel a sense of
> relief.

I don't mean to imply that you're not making an effort. Your effort and
contribution is very much appreciated. Nonetheless we need to keep up
code quality and doublecheck each other's work.

If I review your code, notice an issue and find it again in the next
iteration you send, then I have not found a bug in the code, but in your
workflow. What we need to fix then is both the bug and the workflow so
that more such bugs don't reappear again. Everybody wins.

As a general rule, bugs appear in clusters. If I or one of my reviewers
notices a bug in some code I work on, I don't just fix that instance of
the bug. I make an effort to doublecheck the rest of the code I work on
and ideally all of the codebase for similar problems. In 99% of the
cases I stumble over more issues in this way.

How you look for similar issues depends on the case. For typos you can
grep, for other issues you might want to use a regexp grep or look through
relevant files manually.

In the case of your typo, you should not just look at my review comments
and fix all of the ones I pointed out. I could have overlooked one,
reviewers make mistakes as well; grep does not. Plus, it could even be
faster, so everybody wins.

> >>--- libhipl/cookie.c 2012-06-03 10:26:55 +0000
> >>+++ libhipl/cookie.c 2012-09-08 08:34:18 +0000
> >>@@ -219,41 +218,93 @@
> >>+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)
> >>+{
> >>+ /* 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()) == NUL...

Read more...

Revision history for this message
Miika Komu (miika-iki) wrote :

I tried a local merge+commit and the following things break with the hook:

The following differences were found between the code to commit and the rules in '.uncrustify-0.57.cfg':

--- /home/mkomu/projects/hipl-bzr/trunk/libhipl/cookie.c 2012-09-17 15:37:06.982202000 +0300
+++ - 2012-09-17 15:37:59.286725479 +0300
@@ -250,7 +250,7 @@
         return NULL;
     }

- if((r1 = hip_msg_alloc()) == NULL) {
+ if ((r1 = hip_msg_alloc()) == NULL) {
         return NULL;
     }

--- /home/mkomu/projects/hipl-bzr/trunk/libhipl/output.c 2012-09-17 15:37:06.982202000 +0300
+++ - 2012-09-17 15:37:59.438372623 +0300
@@ -341,7 +341,7 @@
 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;
+ : HIP_PARAM_ECHO_REQUEST;

     const struct hip_echo_msg *ping = hip_get_param(ctx->input_msg, param_type);

review: Needs Fixing
lp:~hipl-core/hipl/hipv2-dh-ecdh updated
6262. By Miika Komu

Syntactical changes for commit guards

The modifications to support ECDH were not originally checked with
commit guards. This commit should fix this problem.

6263. By Miika Komu

Synchronized with trunk revision 6396.

6264. By Miika Komu

A bug fix to HIPv2 cookie indexing

Christof Mroz (christof-mroz) found a bug in HIPv2 cookie indexing:
"You use index j for hip_msg_init(), but index group_id for
hip_create_r1_v2(). Is this intentional?"

This is now fixed.

6265. By Miika Komu

Reducing code size of hip_precreate_r1() function in cookie.c

Christof Mroz noticed in the merge request #131786 in launchpad that
a variable was assigned unnecessarily in hip_precreate_r1().

6266. By Xin

Fix the cookie indexing for ECDH groups.

6267. By Xin

Revise code based on Diego's review (except 3 comments on redundant code).

6268. By Xin

Merge duplicated code for creating the R1 packet.

6269. By Xin

Fix the code duplication on hip_get_r1().

6270. By Miika Komu

Synchronized with trunk revision 6406

6271. By Miika Komu

Synchronized with trunk revision 6436

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'libcore/builder.c'
2--- libcore/builder.c 2012-07-13 13:16:17 +0000
3+++ libcore/builder.c 2012-10-28 16:28:23 +0000
4@@ -119,7 +119,8 @@
5 * @param content the buffer to hold all the items
6 * @param count the number of items in the buffer
7 * @param item_size the size of each item in bytes. The function only supports
8- * items in 2 bytes or 4 bytes.
9+ * byte conversion for items in 2 bytes or 4 bytes. For items
10+ * with other size, no conversion will be applied.
11 * @param flag the flag to decide the byte conversion order
12 */
13 static void convert_byte_order(void *content, unsigned count,
14@@ -128,14 +129,12 @@
15 uint32_t (*f32)(uint32_t) = (flag == CBO_HTON) ? htonl : ntohl;
16 uint16_t (*f16)(uint16_t) = (flag == CBO_HTON) ? htons : ntohs;
17
18- HIP_ASSERT(item_size == sizeof(uint16_t) || item_size == sizeof(uint32_t));
19-
20 if (item_size == sizeof(uint16_t)) {
21 uint16_t *p = content;
22 for (unsigned i = 0; i < count; i++) {
23 p[i] = f16(p[i]);
24 }
25- } else {
26+ } else if (item_size == sizeof(uint32_t)) {
27 uint32_t *p = content;
28 for (unsigned i = 0; i < count; i++) {
29 p[i] = f32(p[i]);
30@@ -730,7 +729,8 @@
31 HIP_PARAM_ESP_PROT_ANCHOR,
32 HIP_PARAM_ESP_PROT_BRANCH,
33 HIP_PARAM_ESP_PROT_SECRET,
34- HIP_PARAM_ESP_PROT_ROOT
35+ HIP_PARAM_ESP_PROT_ROOT,
36+ HIP_PARAM_DH_GROUP_LIST
37 };
38 hip_tlv type = hip_get_param_type(param);
39
40@@ -1200,6 +1200,7 @@
41 case HIP_PARAM_CERT: return "HIP_PARAM_CERT";
42 case HIP_PARAM_CERT_X509_REQ: return "HIP_PARAM_CERT_X509_REQ";
43 case HIP_PARAM_CERT_X509_RESP: return "HIP_PARAM_CERT_X509_RESP";
44+ case HIP_PARAM_DH_GROUP_LIST: return "HIP_PARAM_DH_GROUP_LIST";
45 case HIP_PARAM_DH_SHARED_KEY: return "HIP_PARAM_DH_SHARED_KEY";
46 case HIP_PARAM_DIFFIE_HELLMAN: return "HIP_PARAM_DIFFIE_HELLMAN";
47 case HIP_PARAM_DSA_SIGN_DATA: return "HIP_PARAM_DSA_SIGN_DATA";
48
49=== modified file 'libcore/crypto.c'
50--- libcore/crypto.c 2012-05-12 06:54:33 +0000
51+++ libcore/crypto.c 2012-10-28 16:28:23 +0000
52@@ -46,6 +46,7 @@
53 */
54
55 #include <errno.h>
56+#include <stdbool.h>
57 #include <stdint.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60@@ -68,6 +69,11 @@
61 #include "crypto.h"
62
63
64+const uint8_t HIP_DH_GROUP_LIST[HIP_DH_GROUP_LIST_SIZE] = {
65+ HIP_DH_NIST_P_384,
66+ HIP_DH_OAKLEY_15,
67+ HIP_DH_OAKLEY_5
68+};
69 /*
70 * Diffie-Hellman primes
71 */
72@@ -325,6 +331,10 @@
73 sizeof(dhprime_modp_3072),
74 sizeof(dhprime_modp_6144),
75 sizeof(dhprime_modp_8192),
76+ 64, /* NIST P-256 */
77+ 96, /* NIST P-384 */
78+ 132, /* NIST P-512 */
79+ 0, /* SECP 160R1, unsupported */
80 };
81
82 static unsigned char dhgen[HIP_MAX_DH_GROUP_ID] = { 0,
83@@ -701,6 +711,172 @@
84 return dh;
85 }
86
87+#ifdef HAVE_EC_CRYPTO
88+
89+/**
90+ * Test if the current DH group ID belongs to an ECDH group.
91+ *
92+ * @param group_id the Diffie-Hellman group ID
93+ * @return True if the given group is an ECDH group, False otherwise.
94+ */
95+bool hip_is_ecdh_group(const int group_id)
96+{
97+ return group_id == HIP_DH_NIST_P_256 ||
98+ group_id == HIP_DH_NIST_P_384 ||
99+ group_id == HIP_DH_NIST_P_521;
100+}
101+
102+/**
103+ * Generate a new Elliptic Curve Diffie-Hellman key.
104+ *
105+ * @param group_id the group ID of the DH_GROUP defined in HIPv2
106+ * @return a new ECDH key (caller deallocates), or NULL on error.
107+ */
108+EC_KEY *hip_generate_ecdh_key(const int group_id)
109+{
110+ char rnd_seed[20];
111+ struct timeval tv;
112+ EC_KEY *key;
113+ int nid;
114+
115+ if (group_id == HIP_DH_NIST_P_256) {
116+ nid = NID_X9_62_prime256v1;
117+ } else if (group_id == HIP_DH_NIST_P_384) {
118+ nid = NID_secp384r1;
119+ } else if (group_id == HIP_DH_NIST_P_521) {
120+ nid = NID_secp521r1;
121+ } else {
122+ HIP_ERROR("Unsupported ECDH group: %d\n", group_id);
123+ return NULL;
124+ }
125+
126+ gettimeofday(&tv, NULL);
127+ sprintf(rnd_seed, "%x%x", (unsigned int) tv.tv_usec,
128+ (unsigned int) tv.tv_sec);
129+ RAND_seed(rnd_seed, sizeof(rnd_seed));
130+
131+ if ((key = EC_KEY_new_by_curve_name(nid)) == NULL) {
132+ HIP_ERROR("Failed to create a new EC_KEY from nid: %d\n", nid);
133+ return NULL;
134+ }
135+
136+ if (EC_KEY_generate_key(key) == 0) {
137+ HIP_ERROR("Failed to generate parameters for the new EC_KEY.\n");
138+ EC_KEY_free(key);
139+ return NULL;
140+ }
141+
142+ return key;
143+}
144+
145+/**
146+ * Generate a shared key using Elliptic Curve Diffie-Hellman.
147+ * This method only supports keys using Prime Curve.
148+ *
149+ * @param key the Elliptic Curve Diffie-Hellman key
150+ * @param peer_pub_x the x coordinator of the peer's public key
151+ * @param peer_pub_y the y coordinator of the peer's public key
152+ * @param peer_len length of the @c peer_pub_x or @c peer_pub_y (these two
153+ * length values are identical)
154+ * @param shared_key shared key to generate
155+ * @param outlen the length of the @c shared_key
156+ * @return the length of the shared key on success, 0 otherwise
157+ */
158+int hip_gen_ecdh_shared_key(EC_KEY *const key,
159+ const uint8_t *const peer_pub_x,
160+ const uint8_t *const peer_pub_y,
161+ const size_t peer_len,
162+ uint8_t *const shared_key,
163+ const size_t outlen)
164+{
165+ const EC_GROUP *group;
166+ BIGNUM *peer_pubx = NULL;
167+ BIGNUM *peer_puby = NULL;
168+ EC_POINT *peer_pub = NULL;
169+ int err = 1;
170+ unsigned int out;
171+
172+ if (EC_KEY_check_key(key) == 0) {
173+ HIP_ERROR("Invalid input EC_KEY\n");
174+ return 0;
175+ }
176+
177+ group = EC_KEY_get0_group(key);
178+
179+ if (EC_METHOD_get_field_type(EC_GROUP_method_of(group))
180+ != NID_X9_62_prime_field) {
181+ HIP_ERROR("Invalid group method, only prime curve is supported.\n");
182+ return 0;
183+ }
184+
185+ peer_pub = EC_POINT_new(group);
186+ peer_pubx = BN_bin2bn(peer_pub_x, peer_len, NULL);
187+ peer_puby = BN_bin2bn(peer_pub_y, peer_len, NULL);
188+
189+ HIP_IFEL(EC_POINT_set_affine_coordinates_GFp(group, peer_pub, peer_pubx,
190+ peer_puby, NULL) == 0,
191+ 0, "Failed to create peer's public key.\n");
192+
193+ out = ECDH_compute_key(shared_key, outlen, peer_pub, key, NULL);
194+ HIP_IFEL(out == 0 || out != peer_len, 0,
195+ "Failed to compute the ECDH shared key\n");
196+ err = out;
197+
198+out_err:
199+ BN_free(peer_pubx);
200+ BN_free(peer_puby);
201+ EC_POINT_free(peer_pub);
202+ return err;
203+}
204+
205+/**
206+ * Encode an ECDH public key into a character array.
207+ *
208+ * @param key the ECDH key
209+ * @param[out] out the character array
210+ * @param outlen the length of @c out in bytes
211+ * @return the number of bytes written
212+ */
213+int hip_encode_ecdh_publickey(EC_KEY *key, uint8_t *out, int outlen)
214+{
215+ BIGNUM *pubx = NULL;
216+ BIGNUM *puby = NULL;
217+ int len;
218+ int err = 0;
219+
220+ if (key == NULL || out == NULL || outlen < 0 ||
221+ EC_KEY_check_key(key) == 0) {
222+ HIP_ERROR("Invalid input\n");
223+ return -1;
224+ }
225+
226+ pubx = BN_new();
227+ puby = BN_new();
228+ HIP_IFEL(pubx == NULL || puby == NULL, -1, "Failed to initialize Big Number\n");
229+
230+ if (EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(key),
231+ EC_KEY_get0_public_key(key),
232+ pubx, puby, NULL) == 0) {
233+ HIP_ERROR("Failed to get x,y coordinates from the ECDH key\n");
234+ return -1;
235+ }
236+
237+ len = BN_num_bytes(pubx);
238+ HIP_IFEL(outlen < len * 2, -1, "Output buffer too small\n");
239+
240+ bn2bin_safe(pubx, out, outlen / 2);
241+ bn2bin_safe(puby, out + outlen / 2, outlen / 2);
242+
243+ return outlen;
244+
245+out_err:
246+ BN_free(pubx);
247+ BN_free(puby);
248+ return err;
249+}
250+
251+#endif /* HAVE_EC_CRYPTO */
252+
253 /**
254 * Determine the size for required to store DH shared secret.
255 * @param hip_dh_group_type the group type from DIFFIE_HELLMAN parameter
256@@ -714,7 +890,7 @@
257 if (hip_dh_group_type == 0) {
258 HIP_ERROR("Trying to use reserved DH group type 0\n");
259 } else if (hip_dh_group_type > ARRAY_SIZE(dhprime_len)) {
260- HIP_ERROR("Unknown/unsupported MODP group %d\n", hip_dh_group_type);
261+ HIP_ERROR("Unknown/unsupported DH or ECDH group %d\n", hip_dh_group_type);
262 } else {
263 ret = dhprime_len[hip_dh_group_type];
264 }
265
266=== modified file 'libcore/crypto.h'
267--- libcore/crypto.h 2012-05-12 10:21:32 +0000
268+++ libcore/crypto.h 2012-10-28 16:28:23 +0000
269@@ -1,5 +1,5 @@
270 /*
271- * Copyright (c) 2010-2011 Aalto University and RWTH Aachen University.
272+ * Copyright (c) 2010-2012 Aalto University and RWTH Aachen University.
273 *
274 * Permission is hereby granted, free of charge, to any person
275 * obtaining a copy of this software and associated documentation
276@@ -28,6 +28,7 @@
277
278 #include "config.h"
279
280+#include <stdbool.h>
281 #include <stdint.h>
282 #include <netinet/in.h>
283 #include <sys/types.h>
284@@ -51,15 +52,25 @@
285
286 /* These should be consistent with the table length in crypto.c and
287 * crypto/dh.c */
288-#define HIP_DH_384 1 /* 384-bit group */
289-#define HIP_DH_OAKLEY_1 2 /* 768-bit OAKLEY well known group 1 */
290+/* 384-bit group, DEPRECATED from HIPv2 */
291+#define HIP_DH_384 1
292+/* 768-bit OAKLEY well known group 1, DEPRECATED from HIPv2 */
293+#define HIP_DH_OAKLEY_1 2
294 #define HIP_DH_OAKLEY_5 3 /* 1536-bit MODP group */
295 #define HIP_DH_OAKLEY_15 4 /* 3072-bit MODP group */
296-#define HIP_DH_OAKLEY_17 5 /* 6144-bit MODP group */
297-#define HIP_DH_OAKLEY_18 6 /* 8192-bit MODP group */
298+/* 6144-bit MODP group, DEPRECATED from HIPv2 */
299+#define HIP_DH_OAKLEY_17 5
300+/* 8192-bit MODP group, DEPRECATED from HIPv2 */
301+#define HIP_DH_OAKLEY_18 6
302+/* Group 7 to 10 are new groups defined in HIPv2, among which group 7,8 and 9
303+ * are Ellipse Curve groups. */
304+#define HIP_DH_NIST_P_256 7
305+#define HIP_DH_NIST_P_384 8
306+#define HIP_DH_NIST_P_521 9
307+#define HIP_DH_SECP_160_R1 10
308 #define HIP_FIRST_DH_GROUP_ID HIP_DH_OAKLEY_5
309 #define HIP_SECOND_DH_GROUP_ID HIP_DH_384
310-#define HIP_MAX_DH_GROUP_ID 7
311+#define HIP_MAX_DH_GROUP_ID 11
312
313 #define DSA_KEY_DEFAULT_BITS 1024
314 #define RSA_KEY_DEFAULT_BITS 1024
315@@ -86,6 +97,13 @@
316 #define HIP_SHA(buffer, total_len, hash) SHA((buffer), (total_len), (hash))
317 #endif
318
319+/* HIPv2: default value for DH_GROUP_LIST parameter */
320+#define HIP_DH_GROUP_LIST_SIZE 3
321+const uint8_t HIP_DH_GROUP_LIST[HIP_DH_GROUP_LIST_SIZE];
322+
323+/* HIPv2: max acceptable size of DH group list, longer part will be ignored */
324+#define HIP_DH_GROUP_MAX_RECV_SIZE 6
325+
326 int ssl_rsa_verify(uint8_t *digest, uint8_t *public_key, uint8_t *signature, int pub_klen);
327 int ssl_dsa_verify(uint8_t *digest, uint8_t *public_key, uint8_t *signature);
328 /* In kernel these come from crypto/dh.h, included above */
329@@ -121,6 +139,15 @@
330 int impl_ecdsa_verify(const unsigned char *const digest,
331 EC_KEY *const ecdsa,
332 const unsigned char *const signature);
333+bool hip_is_ecdh_group(const int group_id);
334+EC_KEY *hip_generate_ecdh_key(const int group_id);
335+int hip_encode_ecdh_publickey(EC_KEY *key, uint8_t *out, int outlen);
336+int hip_gen_ecdh_shared_key(EC_KEY *const key,
337+ const uint8_t *const peer_pub_x,
338+ const uint8_t *const peer_pub_y,
339+ const size_t peer_len,
340+ uint8_t *const shared_key,
341+ const size_t outlen);
342 #endif /* HAVE_EC_CRYPTO */
343
344 #endif /* HIPL_LIBCORE_CRYPTO_H */
345
346=== modified file 'libcore/protodefs.h'
347--- libcore/protodefs.h 2012-07-12 11:32:14 +0000
348+++ libcore/protodefs.h 2012-10-28 16:28:23 +0000
349@@ -143,6 +143,7 @@
350 #define HIP_PARAM_SOLUTION 321
351 #define HIP_PARAM_SEQ 385
352 #define HIP_PARAM_ACK 449
353+#define HIP_PARAM_DH_GROUP_LIST 511
354 #define HIP_PARAM_DIFFIE_HELLMAN 513
355 #define HIP_PARAM_HIP_TRANSFORM 577
356 #define HIP_PARAM_ENCRYPTED 641
357
358=== modified file 'libhipl/cookie.c'
359--- libhipl/cookie.c 2012-06-03 10:26:55 +0000
360+++ libhipl/cookie.c 2012-10-28 16:28:23 +0000
361@@ -182,14 +182,13 @@
362 * @param ip_i Initiator's IPv6
363 * @param ip_r Responder's IPv6
364 * @param our_hit Our HIT
365- * @param hip_version HIP message version
366 *
367 * @note Comments for the if 0 code are inlined below.
368 *
369 * Returns NULL if error.
370 */
371 struct hip_common *hip_get_r1(struct in6_addr *ip_i, struct in6_addr *ip_r,
372- struct in6_addr *our_hit, uint8_t hip_version)
373+ struct in6_addr *our_hit)
374 {
375 struct hip_common *err = NULL, *r1 = NULL;
376 struct hip_r1entry *hip_r1table = NULL;
377@@ -200,7 +199,7 @@
378 HIP_IFEL(!(hid = hip_get_hostid_entry_by_lhi_and_algo(our_hit, HIP_ANY_ALGO, -1)),
379 NULL, "Unknown HIT\n");
380
381- hip_r1table = hid->r1[hip_version];
382+ hip_r1table = hid->r1;
383 idx = calc_cookie_idx(ip_i, ip_r);
384 HIP_DEBUG("Calculated index: %d\n", idx);
385
386@@ -219,41 +218,93 @@
387 }
388
389 /**
390- * precreate an R1 packet
391- *
392- * @param r1table a pointer to R1 table structure
393+ * HIPv2: get a copy of R1entry structure.
394+ *
395+ * @param ip_i Initiator's IPv6
396+ * @param ip_r Responder's IPv6
397+ * @param our_hit Our HIT
398+ * @param dh_group_id Diffie Hellman group ID
399+ * @return A R1 packet copy on success, NULL on error
400+ */
401+struct hip_common *hip_get_r1_v2(struct in6_addr *ip_i, struct in6_addr *ip_r,
402+ struct in6_addr *our_hit, const int dh_group_id)
403+{
404+ struct hip_common *r1 = NULL;
405+ struct local_host_id *hid = NULL;
406+ int idx, len;
407+
408+ /* Find the proper R1 table and copy the R1 message from the table */
409+ hid = hip_get_hostid_entry_by_lhi_and_algo(our_hit, HIP_ANY_ALGO, -1);
410+ if (hid == NULL) {
411+ HIP_ERROR("Unknown HIT\n");
412+ return NULL;
413+ }
414+
415+ idx = calc_cookie_idx(ip_i, ip_r);
416+ HIP_DEBUG("Calculated index: %d\n", idx);
417+
418+ /* Create a copy of the found entry */
419+ len = hip_get_msg_total_len(&hid->r1_v2[dh_group_id][idx].buf.msg);
420+ if (len <= 0) {
421+ HIP_ERROR("Invalid r1_v2 entry at %d, %d\n", dh_group_id, idx);
422+ return NULL;
423+ }
424+
425+ if ((r1 = hip_msg_alloc()) == NULL) {
426+ return NULL;
427+ }
428+
429+ memcpy(r1, &hid->r1_v2[dh_group_id][idx].buf.msg, len);
430+
431+ return r1;
432+}
433+
434+/**
435+ * HIPv1 & HIPv2: precreate R1 entries
436+ *
437+ * @param id_entry a pointer to host ID entry
438 * @param hit the local HIT
439 * @param sign a signing callback function
440 * @param privkey the private key to use for signing
441 * @param pubkey the host id (public key)
442- * @param hip_version HIP message version
443 * @return zero on success and non-zero on error
444 */
445-int hip_precreate_r1(struct hip_r1entry *const r1table,
446- const struct in6_addr *const hit,
447+int hip_precreate_r1(struct local_host_id *id_entry,
448+ const hip_hit_t *const hit,
449 int (*sign)(void *const key, struct hip_common *const m),
450 void *const privkey,
451- const struct hip_host_id *const pubkey,
452- const uint8_t hip_version)
453+ const struct hip_host_id *const pubkey)
454 {
455- int i = 0;
456+ int i, j, group_id, cookie_k;
457+
458 for (i = 0; i < HIP_R1TABLESIZE; i++) {
459- int cookie_k;
460-
461 cookie_k = get_cookie_difficulty();
462-
463- hip_msg_init(&r1table[i].buf.msg);
464-
465- if (hip_create_r1(&r1table[i].buf.msg, hit, sign, privkey, pubkey,
466- cookie_k, hip_version)) {
467+ hip_msg_init(&id_entry->r1[i].buf.msg);
468+
469+ if (hip_create_r1(&id_entry->r1[i].buf.msg, hit, sign, privkey,
470+ pubkey, cookie_k)) {
471 HIP_ERROR("Unable to precreate R1s\n");
472- return 0;
473- }
474-
475- HIP_DEBUG("Packet %d created\n", i);
476- }
477-
478- return 1;
479+ return -1;
480+ }
481+ HIP_DEBUG("R1 Packet %d created\n", i);
482+ }
483+
484+ for (j = 0; j < HIP_DH_GROUP_LIST_SIZE; j++) {
485+ group_id = HIP_DH_GROUP_LIST[j];
486+ for (i = 0; i < HIP_R1TABLESIZE; i++) {
487+ cookie_k = get_cookie_difficulty();
488+ hip_msg_init(&id_entry->r1_v2[j][i].buf.msg);
489+
490+ if (hip_create_r1_v2(&id_entry->r1_v2[j][i].buf.msg, hit, sign,
491+ privkey, pubkey, cookie_k, group_id)) {
492+ HIP_ERROR("Unable to precreate R1_v2\n");
493+ return -1;
494+ }
495+ HIP_DEBUG("R1_v2 Packets %d created for group: %d\n", i, group_id);
496+ }
497+ }
498+
499+ return 0;
500 }
501
502 /**
503@@ -266,13 +317,17 @@
504 * @param hdr a pointer to HIP packet common header
505 * @param solution a pointer to a solution structure
506 * @param hip_version HIP message version
507+ * @param dh_group_id the Diffie-Hellman group ID of the R1 entry. This
508+ * parameter is required for a HIPv2 cookie verification.
509+ * For v1, this parameter will be ignored.
510 * @return Zero if the cookie was verified successfully, negative
511 * otherwise.
512 */
513 int hip_verify_cookie(struct in6_addr *ip_i, struct in6_addr *ip_r,
514 struct hip_common *hdr,
515 const struct hip_solution *solution,
516- const uint8_t hip_version)
517+ const uint8_t hip_version,
518+ const int dh_group_id)
519 {
520 /* In a effort to conform the HIPL coding convention, the return value
521 * of this function was inverted. I.e. This function now returns
522@@ -289,7 +344,12 @@
523 HIP_ANY_ALGO,
524 -1)),
525 -1, "Requested source HIT not (any more) available.\n");
526- result = &hid->r1[hip_version][calc_cookie_idx(ip_i, ip_r)];
527+
528+ if (hip_version == HIP_V1) {
529+ result = &hid->r1[calc_cookie_idx(ip_i, ip_r)];
530+ } else {
531+ result = &hid->r1_v2[dh_group_id][calc_cookie_idx(ip_i, ip_r)];
532+ }
533
534 puzzle = hip_get_param(&result->buf.msg, HIP_PARAM_PUZZLE);
535 HIP_IFEL(!puzzle, -1, "Internal error: could not find the cookie\n");
536@@ -344,7 +404,6 @@
537 static int recreate_r1s_for_entry_move(struct local_host_id *entry,
538 UNUSED void *opaque)
539 {
540- int i;
541 int (*signature_func)(void *const key, struct hip_common *const m);
542
543 switch (hip_get_host_id_algo(&entry->host_id)) {
544@@ -364,11 +423,10 @@
545 return -1;
546 }
547
548- for (i = 1; i < HIP_MAX_VERSION; i++) {
549- if (!hip_precreate_r1(entry->r1[i], &entry->hit, signature_func,
550- entry->private_key, &entry->host_id, i)) {
551- return -1;
552- }
553+ if (hip_precreate_r1(entry, &entry->hit, signature_func,
554+ entry->private_key, &entry->host_id) < 0) {
555+ HIP_ERROR("Precreate r1 failed\n");
556+ return -1;
557 }
558
559 return 0;
560
561=== modified file 'libhipl/cookie.h'
562--- libhipl/cookie.h 2012-06-03 10:26:55 +0000
563+++ libhipl/cookie.h 2012-10-28 16:28:23 +0000
564@@ -30,32 +30,26 @@
565 #include <netinet/in.h>
566
567 #include "libcore/protodefs.h"
568-
569-#define HIP_R1TABLESIZE 3 /* precreate only this many R1s */
570-
571-struct hip_r1entry {
572- union hip_msg_bfr buf;
573- uint32_t generation;
574- uint8_t Ci[PUZZLE_LENGTH];
575- uint8_t Ck;
576- uint8_t Copaque[HIP_PUZZLE_OPAQUE_LEN];
577-};
578+#include "libhipl/hidb.h"
579
580 struct hip_common *hip_get_r1(struct in6_addr *ip_i,
581 struct in6_addr *ip_r,
582- struct in6_addr *peer_hit,
583- uint8_t hip_version);
584+ struct in6_addr *peer_hit);
585+struct hip_common *hip_get_r1_v2(struct in6_addr *ip_i,
586+ struct in6_addr *ip_r,
587+ struct in6_addr *our_hit,
588+ const int dh_group_id);
589 int hip_recreate_all_precreated_r1_packets(void);
590-int hip_precreate_r1(struct hip_r1entry *const r1table,
591- const struct in6_addr *const hit,
592+int hip_precreate_r1(struct local_host_id *id_entry,
593+ const hip_hit_t *const hit,
594 int (*sign)(void *const key, struct hip_common *const m),
595 void *const privkey,
596- const struct hip_host_id *const pubkey,
597- const uint8_t hip_version);
598+ const struct hip_host_id *const pubkey);
599 int hip_verify_cookie(struct in6_addr *ip_i, struct in6_addr *ip_r,
600 struct hip_common *hdr,
601 const struct hip_solution *cookie,
602- const uint8_t hip_version);
603+ const uint8_t hip_version,
604+ const int dh_group_id);
605 int hip_inc_cookie_difficulty(void);
606 int hip_dec_cookie_difficulty(void);
607 int hip_get_puzzle_difficulty_msg(struct hip_common *msg);
608
609=== modified file 'libhipl/dh.c'
610--- libhipl/dh.c 2012-05-12 10:21:32 +0000
611+++ libhipl/dh.c 2012-10-28 16:28:23 +0000
612@@ -1,5 +1,5 @@
613 /*
614- * Copyright (c) 2010 Aalto University and RWTH Aachen University.
615+ * Copyright (c) 2010, 2012 Aalto University and RWTH Aachen University.
616 *
617 * Permission is hereby granted, free of charge, to any person
618 * obtaining a copy of this software and associated documentation
619@@ -47,6 +47,8 @@
620 */
621 static DH *dh_table[HIP_MAX_DH_GROUP_ID] = { 0 };
622
623+static EC_KEY *ecdh_table[HIP_MAX_DH_GROUP_ID] = { 0 };
624+
625 /**
626 * insert the current DH-key into the buffer
627 *
628@@ -95,66 +97,288 @@
629 }
630
631 /**
632- * create a shared secret based on the public key of the peer
633+ * Store the bytes of the current ECDH public key in the given buffer.
634+ *
635+ * A new ECDH key will be created if it doesn't exist,
636+ *
637+ * @param buffer buffer to store the public part of the ECDH key
638+ * @param bufsize size of the @c buffer
639+ * @param group_id group ID of the ECDH key
640+ * @return the number of bytes written to the buffer, -1 on error.
641+ */
642+int hip_insert_ecdh(uint8_t *buffer, int bufsize, int group_id)
643+{
644+ EC_KEY *key;
645+ int ret;
646+
647+ if (!hip_is_ecdh_group(group_id)) {
648+ HIP_ERROR("Invalid group id for ECDH: %d\n", group_id);
649+ return -1;
650+ }
651+
652+ if (ecdh_table[group_id] == NULL) {
653+ key = hip_generate_ecdh_key(group_id);
654+ if (key == NULL) {
655+ HIP_ERROR("Failed to generate an ECDH key for group: %d\n",
656+ group_id);
657+ return -1;
658+ }
659+ ecdh_table[group_id] = key;
660+ }
661+
662+ key = ecdh_table[group_id];
663+ if ((ret = hip_encode_ecdh_publickey(key, buffer, bufsize)) < 0) {
664+ HIP_ERROR("Failed to encode the ECDH public key\n");
665+ return -1;
666+ }
667+
668+ return ret;
669+}
670+
671+/**
672+ * HIPv2: Store the bytes of the current ECDH/DH public key to the given buffer.
673+ *
674+ * An ECDH/DH key will be created if it does not exist.
675+ *
676+ * @param buffer the buffer to store the ECDH/DH public key
677+ * @param bufsize the size of the @c buffer
678+ * @param group_id the group ID of the ECDH/DH key
679+ * @return the number of bytes written to the buffer
680+ */
681+int hip_insert_dh_v2(uint8_t *buffer, int bufsize, int group_id)
682+{
683+ if (group_id <= 0 || group_id >= HIP_MAX_DH_GROUP_ID) {
684+ HIP_ERROR("Invalid DH_GROUP_ID: %d\n", group_id);
685+ return -1;
686+ }
687+
688+ if (hip_is_ecdh_group(group_id)) {
689+ return hip_insert_ecdh(buffer, bufsize, group_id);
690+ } else {
691+ return hip_insert_dh(buffer, bufsize, group_id);
692+ }
693+}
694+
695+/**
696+ * Match the first identical DH group ID in local and peer's list.
697+ *
698+ * @param dh_group_list the DH_GROUP_LIST parameter sent from the peer
699+ * @param our_dh_group the local DH list
700+ * @param our_group_size the size of the @c our_dh_group
701+ * @return ID of the matched group on success, -1 otherwise.
702+ */
703+int hip_match_dh_group_list(const struct hip_tlv_common *const dh_group_list,
704+ const uint8_t *const our_dh_group,
705+ const int our_group_size)
706+{
707+ int list_size = HIP_DH_GROUP_MAX_RECV_SIZE;
708+ uint8_t list[list_size];
709+ int i, j;
710+
711+ list_size = hip_get_list_from_param(dh_group_list, list, list_size,
712+ sizeof(uint8_t));
713+ for (i = 0; i < list_size; i++) {
714+ for (j = 0; j < our_group_size; j++) {
715+ if (our_dh_group[j] == list[i]) {
716+ return our_dh_group[j];
717+ }
718+ }
719+ }
720+
721+ return -1;
722+}
723+
724+/**
725+ * Calculate a Diffie-Hellman shared secret based on the public key of the peer
726 * (passed as an argument) and own DH private key (created beforehand).
727 *
728- * @param public_value Peer's Diffie-Hellman public key
729+ * @param group_id the Diffie-Hellman group ID
730+ * @param public_value the Diffie-Hellman public key of the peer
731+ * @param len the length of the @c public_value
732+ * @param buffer the buffer that holds enough space for the shared secret
733+ * @param bufsize the size of the @c buffer
734+ *
735+ * @return the length of the shared secret in octets if successful,
736+ * or -1 if an error occurred.
737+ */
738+static int hip_calculate_dh_shared_secret(const uint16_t group_id,
739+ const uint8_t *const public_value,
740+ const int len,
741+ unsigned char *const buffer,
742+ const int bufsize)
743+{
744+ DH *key;
745+ int secret_len;
746+
747+ if (group_id <= 0 || group_id >= HIP_MAX_DH_GROUP_ID) {
748+ HIP_ERROR("Invalid Group ID: %d.\n", group_id);
749+ return -1;
750+ }
751+
752+ if (dh_table[group_id] == NULL) {
753+ if (NULL == (key = hip_generate_dh_key(group_id))) {
754+ HIP_ERROR("Failed to generate a DH key for group: %d\n", group_id);
755+ return -1;
756+ }
757+ dh_table[group_id] = key;
758+ }
759+ key = dh_table[group_id];
760+
761+ secret_len = hip_gen_dh_shared_key(dh_table[group_id], public_value, len,
762+ buffer, bufsize);
763+ if (secret_len < 0) {
764+ HIP_ERROR("failed to create a DH shared secret\n");
765+ return -1;
766+ }
767+
768+ return secret_len;
769+}
770+
771+/**
772+ * Calculate an Elliptic Curve Diffie-Hellman shared secret.
773+ *
774+ * The length of the public value should match the corresponding ECDH group; The
775+ * buffer to hold the shared secret should be at least larger than the length of
776+ * the public value divided by 2.
777+ *
778+ * @param group_id the ECDH group ID
779+ * @param public_value Peer's ECDH public key
780+ * @param pubkey_len the length of the @c public_value
781+ * @param buffer Buffer that holds enough space for the shared secret
782+ * @param bufsize size of the @c buffer
783+ *
784+ * @return the length of the shared secret in octets if successful,
785+ * or -1 if an error occurred.
786+ */
787+static int hip_calculate_ecdh_shared_secret(const uint16_t group_id,
788+ const uint8_t *const public_value,
789+ const int pubkey_len,
790+ unsigned char *const buffer,
791+ const int bufsize)
792+{
793+ EC_KEY *key;
794+ int key_len;
795+
796+ if (ecdh_table[group_id] == NULL) {
797+ if (NULL == (key = hip_generate_ecdh_key(group_id))) {
798+ HIP_ERROR("Failed to generate an ECDH key for group: %d\n",
799+ group_id);
800+ return -1;
801+ }
802+ ecdh_table[group_id] = key;
803+ }
804+ key = ecdh_table[group_id];
805+
806+ key_len = hip_get_dh_size(group_id);
807+ if (key_len != pubkey_len || key_len / 2 > bufsize) {
808+ HIP_ERROR("Invalid public key length (%d) or buffer size (%d)\n",
809+ pubkey_len, bufsize);
810+ return -1;
811+ }
812+ int out = hip_gen_ecdh_shared_key(key, public_value,
813+ public_value + key_len / 2,
814+ key_len / 2,
815+ buffer,
816+ bufsize);
817+ if (out <= 0) {
818+ HIP_ERROR("Failed to generate a shared secret\n");
819+ return -1;
820+ }
821+
822+ return out;
823+}
824+
825+/**
826+ * Calculate a shared secret for Diffie-Hellman exchange.
827+ *
828+ * This function supports both normal DH and ECDH groups. The DH private key
829+ * is created beforehand.
830+ *
831+ * @param group_id the Diffie-Hellman group ID
832+ * @param public_value the Diffie-Hellman public key of the peer
833+ * @param len the length of the @c public_value
834+ * @param buffer Buffer that holds the shared secret
835+ * @param bufsize size of the @c buffer
836+ *
837+ * @return the length of the shared secret in octets if successful,
838+ * or -1 if an error occurred.
839+ */
840+int hip_calculate_shared_secret(const uint16_t group_id,
841+ const uint8_t *const public_value,
842+ const int len,
843+ unsigned char *const buffer,
844+ const int bufsize)
845+{
846+ if (group_id <= 0 || group_id >= HIP_MAX_DH_GROUP_ID) {
847+ HIP_ERROR("Invalid Diffie-Hellman group ID: %d\n", group_id);
848+ return -1;
849+ }
850+
851+ if (hip_is_ecdh_group(group_id)) {
852+ return hip_calculate_ecdh_shared_secret(group_id, public_value, len,
853+ buffer, bufsize);
854+ } else {
855+ return hip_calculate_dh_shared_secret(group_id, public_value, len,
856+ buffer, bufsize);
857+ }
858+}
859+
860+/**
861+ * Re-generate a DH key for a given group ID.
862+ *
863 * @param group_id the Diffie-Hellman group ID
864- * @param len the length of the public value
865- * @param buffer Buffer that holds enough space for the shared secret.
866- * @param bufsize size of the buffer
867- *
868- * @return the length of the shared secret in octets if successful,
869- * or -1 if an error occured.
870- */
871-int hip_calculate_shared_secret(const uint8_t *public_value,
872- uint8_t group_id,
873- signed int len,
874- unsigned char *buffer,
875- int bufsize)
876-{
877- int err = 0;
878- DH *tmp;
879-
880- if (group_id <= 0 || group_id >= HIP_MAX_DH_GROUP_ID) {
881- HIP_ERROR("The Group ID %d is invalid\n", group_id);
882- return -1;
883- }
884-
885- /*
886- * First check that we have the key available.
887- * Then encode it into the buffer
888- */
889-
890- if (dh_table[group_id] == NULL) {
891- tmp = hip_generate_dh_key(group_id);
892- dh_table[group_id] = tmp;
893-
894- if (dh_table[group_id] == NULL) {
895- HIP_ERROR("Unsupported DH group: %d\n", group_id);
896- return -1;
897- }
898- }
899-
900- err = hip_gen_dh_shared_key(dh_table[group_id], public_value,
901- len, buffer, bufsize);
902- if (err < 0) {
903- HIP_ERROR("Could not create shared secret\n");
904- return -1;
905- }
906-
907- return err;
908-}
909-
910-/**
911- * regenerate Diffie-Hellman keys for HIP
912- * @param bitmask Mask of groups to generate.
913- *
914- * @note Use only this function to generate DH keys.
915- */
916-static void regen_dh_keys(uint32_t bitmask)
917+ * @return 0 on success, -1 otherwise
918+ */
919+static int regen_dh_key(const int group_id)
920 {
921 DH *tmp, *okey;
922+
923+ tmp = hip_generate_dh_key(group_id);
924+ if (!tmp) {
925+ HIP_INFO("Failed to generate a DH key for group: %d\n", group_id);
926+ return -1;
927+ }
928+
929+ okey = dh_table[group_id];
930+ dh_table[group_id] = tmp;
931+
932+ DH_free(okey);
933+ return 0;
934+}
935+
936+#ifdef HAVE_EC_CRYPTO
937+/**
938+ * Re-generate DH key for a given ECDH group ID.
939+ *
940+ * @param group_id the ECDH group ID
941+ * @return 0 on success, -1 otherwise
942+ */
943+static int regen_ecdh_key(const int group_id)
944+{
945+ EC_KEY *tmp, *okey;
946+
947+ tmp = hip_generate_ecdh_key(group_id);
948+ if (!tmp) {
949+ HIP_INFO("Failed to generate an ECDH key for group: %d\n", group_id);
950+ return -1;
951+ }
952+
953+ okey = ecdh_table[group_id];
954+ ecdh_table[group_id] = tmp;
955+
956+ EC_KEY_free(okey);
957+ return 0;
958+}
959+
960+#endif /* HAVE_EC_CRYPTO */
961+
962+/**
963+ * HIPv2: regenerate Diffie-Hellman keys.
964+ *
965+ * @param bitmask the mask of groups to generate
966+ */
967+static void regen_dh_keys_v2(uint32_t bitmask)
968+{
969 int maxmask, i;
970 int cnt = 0;
971
972@@ -164,19 +388,13 @@
973
974 for (i = 1; i < HIP_MAX_DH_GROUP_ID; i++) {
975 if (bitmask & (1 << i)) {
976- tmp = hip_generate_dh_key(i);
977- if (!tmp) {
978- HIP_INFO("Error while generating group: %d\n", i);
979- continue;
980+ if (hip_is_ecdh_group(i)) {
981+ regen_ecdh_key(i);
982+ } else {
983+ regen_dh_key(i);
984 }
985
986- okey = dh_table[i];
987- dh_table[i] = tmp;
988-
989- DH_free(okey);
990-
991 cnt++;
992-
993 HIP_DEBUG("DH key for group %d generated\n", i);
994 }
995 }
996@@ -193,6 +411,14 @@
997 DH_free(dh_table[i]);
998 dh_table[i] = NULL;
999 }
1000+
1001+#ifdef HAVE_EC_CRYPTO
1002+ for (i = 1; i < HIP_MAX_DH_GROUP_ID; i++) {
1003+ EC_KEY_free(ecdh_table[i]);
1004+ ecdh_table[i] = NULL;
1005+ }
1006+#endif /* HAVE_EC_CRYPTO */
1007+
1008 CRYPTO_cleanup_all_ex_data();
1009 }
1010
1011@@ -205,10 +431,13 @@
1012
1013 supported_groups = (1 << HIP_DH_OAKLEY_1 |
1014 1 << HIP_DH_OAKLEY_5 |
1015- 1 << HIP_DH_384);
1016+ 1 << HIP_DH_384 |
1017+ 1 << HIP_DH_NIST_P_256 |
1018+ 1 << HIP_DH_NIST_P_384 |
1019+ 1 << HIP_DH_NIST_P_521);
1020
1021 HIP_DEBUG("Generating DH keys\n");
1022- regen_dh_keys(supported_groups);
1023+ regen_dh_keys_v2(supported_groups);
1024
1025 return 1;
1026 }
1027
1028=== modified file 'libhipl/dh.h'
1029--- libhipl/dh.h 2012-05-12 10:21:32 +0000
1030+++ libhipl/dh.h 2012-10-28 16:28:23 +0000
1031@@ -1,5 +1,5 @@
1032 /*
1033- * Copyright (c) 2010 Aalto University and RWTH Aachen University.
1034+ * Copyright (c) 2010, 2012 Aalto University and RWTH Aachen University.
1035 *
1036 * Permission is hereby granted, free of charge, to any person
1037 * obtaining a copy of this software and associated documentation
1038@@ -28,13 +28,21 @@
1039
1040 #include <stdint.h>
1041
1042+#include "libcore/protodefs.h"
1043+
1044+
1045 int hip_insert_dh(uint8_t *buffer, int bufsize, int group_id);
1046 void hip_dh_uninit(void);
1047-int hip_calculate_shared_secret(const uint8_t *public_value,
1048- uint8_t group_id,
1049- signed int len,
1050- unsigned char *buffer,
1051- int bufsize);
1052+int hip_calculate_shared_secret(const uint16_t group_id,
1053+ const uint8_t *const pulic_value,
1054+ const int len,
1055+ unsigned char *const buffer,
1056+ const int bufsize);
1057 int hip_init_cipher(void);
1058
1059+int hip_insert_dh_v2(uint8_t *buffer, int bufsize, int group_id);
1060+int hip_insert_ecdh(uint8_t *buffer, int bufsize, int group_id);
1061+int hip_match_dh_group_list(const struct hip_tlv_common *const dh_group_list,
1062+ const uint8_t *our_dh_group, const int our_group_size);
1063+
1064 #endif /* HIPL_LIBHIPL_DH_H */
1065
1066=== modified file 'libhipl/hidb.c'
1067--- libhipl/hidb.c 2012-06-03 10:26:55 +0000
1068+++ libhipl/hidb.c 2012-10-28 16:28:23 +0000
1069@@ -429,7 +429,6 @@
1070 hip_lsi_t *lsi,
1071 const struct hip_host_id_priv *host_id)
1072 {
1073- int i;
1074 int err = 0;
1075 struct local_host_id *id_entry = NULL;
1076 struct local_host_id *old_entry;
1077@@ -493,16 +492,12 @@
1078 err = -1;
1079 goto out_err;
1080 }
1081- for (i = 1; i < HIP_MAX_VERSION; i++) {
1082- HIP_IFEL(!hip_precreate_r1(id_entry->r1[i],
1083- &hit,
1084- signature_func,
1085- id_entry->private_key,
1086- &id_entry->host_id,
1087- i),
1088- -ENOENT,
1089- "Unable to precreate R1s.\n");
1090- }
1091+
1092+ HIP_IFEL(hip_precreate_r1(id_entry, &hit, signature_func,
1093+ id_entry->private_key,
1094+ &id_entry->host_id) < 0,
1095+ -ENOENT,
1096+ "Unable to precreate R1s.\n");
1097
1098 out_err:
1099 if (err && id_entry) {
1100
1101=== modified file 'libhipl/hidb.h'
1102--- libhipl/hidb.h 2012-06-03 10:26:55 +0000
1103+++ libhipl/hidb.h 2012-10-28 16:28:23 +0000
1104@@ -35,9 +35,19 @@
1105 #include <stdbool.h>
1106 #include <netinet/in.h>
1107
1108+#include "libcore/crypto.h"
1109 #include "libcore/protodefs.h"
1110-#include "cookie.h"
1111-
1112+
1113+
1114+#define HIP_R1TABLESIZE 3 /* precreate only this many R1s */
1115+
1116+struct hip_r1entry {
1117+ union hip_msg_bfr buf;
1118+ uint32_t generation;
1119+ uint8_t Ci[PUZZLE_LENGTH];
1120+ uint8_t Ck;
1121+ uint8_t Copaque[HIP_PUZZLE_OPAQUE_LEN];
1122+};
1123
1124 struct local_host_id {
1125 hip_hit_t hit;
1126@@ -45,7 +55,13 @@
1127 hip_lsi_t lsi;
1128 struct hip_host_id host_id;
1129 void *private_key; /* RSA or DSA */
1130- struct hip_r1entry r1[HIP_MAX_VERSION][HIP_R1TABLESIZE]; /* precreated R1s */
1131+
1132+ /* precreated R1 entries.
1133+ * Due to the introduction of DH_GROUP_LIST in HIPv2, R1's DIFFIE_HELLMAN
1134+ * parameter must match one of the group ID of initiator's I1. Therefore we
1135+ * precreate R1 for all DH groups we support. */
1136+ struct hip_r1entry r1[HIP_R1TABLESIZE];
1137+ struct hip_r1entry r1_v2[HIP_MAX_DH_GROUP_ID][HIP_R1TABLESIZE];
1138 };
1139
1140 struct local_host_id *hip_get_hostid_entry_by_lhi_and_algo(const struct in6_addr *const hit,
1141
1142=== modified file 'libhipl/input.c'
1143--- libhipl/input.c 2012-07-13 13:16:17 +0000
1144+++ libhipl/input.c 2012-10-28 16:28:23 +0000
1145@@ -110,6 +110,43 @@
1146 }
1147
1148 /**
1149+ * HIPv2: Check potential downgrade possibility for DH group selection by
1150+ * matching our DH list with the peer's DH list. If the peer doesn't select
1151+ * the strongest group, DH downgrade occurs.
1152+ *
1153+ * @param peer_group the DH group peer has selected
1154+ * @param peer_param the peer's DH group list parameter
1155+ * @return 0 if no downgrade detected, -1 otherwise.
1156+ */
1157+static int check_dh_downgrade_v2(const uint8_t peer_group,
1158+ const struct hip_tlv_common *const peer_param)
1159+{
1160+ int i, j;
1161+ int list_size = HIP_DH_GROUP_MAX_RECV_SIZE;
1162+ uint8_t list[list_size];
1163+
1164+ list_size = hip_get_list_from_param(peer_param, list, list_size,
1165+ sizeof(list[0]));
1166+ for (i = 0; i < HIP_DH_GROUP_LIST_SIZE; i++) {
1167+ for (j = 0; j < list_size; j++) {
1168+ if (HIP_DH_GROUP_LIST[i] == list[j]) {
1169+ if (list[j] == peer_group) {
1170+ return 0;
1171+ } else {
1172+ HIP_ERROR("Detect DH group downgrade. "
1173+ "Expect group: %d, Got: %d\n",
1174+ list[j], peer_group);
1175+ return -1;
1176+ }
1177+ }
1178+ }
1179+ }
1180+
1181+ HIP_ERROR("No identical group in the DH group lists\n");
1182+ return -1;
1183+}
1184+
1185+/**
1186 * Verifies gerenal HMAC in HIP msg
1187 *
1188 * @param msg HIP packet
1189@@ -325,11 +362,14 @@
1190 HIP_DEBUG("Start PERF_DH_CREATE\n");
1191 hip_perf_start_benchmark(perf_set, PERF_DH_CREATE);
1192 #endif
1193- HIP_IFEL((dh_shared_len = hip_calculate_shared_secret(dhpv->public_value, dhpv->group_id,
1194- ntohs(dhpv->pub_len),
1195- (unsigned char *) dh_shared_key,
1196- dh_shared_len)) < 0,
1197- -EINVAL, "Calculation of shared secret failed.\n");
1198+
1199+ dh_shared_len = hip_calculate_shared_secret(dhpv->group_id, dhpv->public_value,
1200+ ntohs(dhpv->pub_len),
1201+ (unsigned char *) dh_shared_key,
1202+ dh_shared_len);
1203+ HIP_IFEL(dh_shared_len <= 0, -EINVAL, "Calculation of shared secret failed.\n");
1204+ HIP_DEBUG("DH group %d, shared secret length is %d\n",
1205+ dhpv->group_id, dh_shared_len);
1206
1207 hip_make_keymat(dh_shared_key,
1208 dh_shared_len,
1209@@ -763,6 +803,24 @@
1210 HIP_IFE(hip_init_peer(ctx->hadb_entry, &peer_host_id),
1211 -EINVAL);
1212
1213+ /* HIPv2: check possible DH group downgrade */
1214+ if (ctx->hadb_entry->hip_version == HIP_V2) {
1215+ const struct hip_tlv_common *dh_list_param;
1216+ const struct hip_diffie_hellman *dh_param;
1217+
1218+ dh_list_param = hip_get_param(ctx->input_msg, HIP_PARAM_DH_GROUP_LIST);
1219+ HIP_IFEL(dh_list_param == NULL, -ENOENT,
1220+ "No DH_GROUP_LIST parameter found in R1\n");
1221+
1222+ dh_param = hip_get_param(ctx->input_msg, HIP_PARAM_DIFFIE_HELLMAN);
1223+ HIP_IFEL(dh_param == NULL, -ENOENT,
1224+ "No DIFFIE_HELLMAN parameter found in R1\n");
1225+
1226+ HIP_IFEL(check_dh_downgrade_v2(dh_param->pub_val.group_id,
1227+ dh_list_param) < 0,
1228+ -EINVAL, "DH group downgrade check failed.\n");
1229+ }
1230+
1231 #ifdef CONFIG_HIP_PERFORMANCE
1232 HIP_DEBUG("Start PERF_VERIFY\n");
1233 hip_perf_start_benchmark(perf_set, PERF_VERIFY);
1234@@ -945,7 +1003,8 @@
1235 HIP_ERROR("Failed to allocate memory for public value\n");
1236 return -ENOMEM;
1237 }
1238- if ((pub_len = hip_insert_dh(public_value, pub_len, dhpv->group_id)) < 0) {
1239+
1240+ if ((pub_len = hip_insert_dh_v2(public_value, pub_len, dhpv->group_id)) < 0) {
1241 HIP_ERROR("Could not extract the DH public key\n");
1242 return -1;
1243 }
1244@@ -1363,19 +1422,22 @@
1245 UNUSED const enum hip_state ha_state,
1246 struct hip_packet_context *ctx)
1247 {
1248- int hip_version = 0;
1249- int err = 0, is_loopback = 0;
1250- bool skip_key_creation = false;
1251- uint16_t mask = HIP_PACKET_CTRL_ANON;
1252- uint16_t crypto_len = 0;
1253- char *tmp_enc = NULL;
1254- const char *enc = NULL;
1255- unsigned char *iv = NULL;
1256- const struct hip_solution *solution = NULL;
1257- const struct hip_r1_counter *r1cntr = NULL;
1258- const struct hip_hip_transform *hip_transform = NULL;
1259- struct hip_host_id *host_id_in_enc = NULL;
1260- struct hip_host_id host_id;
1261+ int hip_version = 0;
1262+ int err = 0, is_loopback = 0;
1263+ bool skip_key_creation = false;
1264+ uint16_t mask = HIP_PACKET_CTRL_ANON;
1265+ uint16_t crypto_len = 0;
1266+ char *tmp_enc = NULL;
1267+ const char *enc = NULL;
1268+ unsigned char *iv = NULL;
1269+ const struct hip_solution *solution = NULL;
1270+ const struct hip_diffie_hellman *dh_param = NULL;
1271+ const struct hip_r1_counter *r1cntr = NULL;
1272+ const struct hip_hip_transform *hip_transform = NULL;
1273+ struct hip_host_id *host_id_in_enc = NULL;
1274+ struct hip_host_id host_id;
1275+ int dh_group_id, i;
1276+
1277 #ifdef CONFIG_HIP_PERFORMANCE
1278 HIP_DEBUG("Start PERF_I2\n");
1279 hip_perf_start_benchmark(perf_set, PERF_I2);
1280@@ -1464,13 +1526,47 @@
1281 -ENODATA,
1282 "SOLUTION parameter missing from I2 packet. Dropping\n");
1283
1284- HIP_IFEL(hip_verify_cookie(&ctx->src_addr,
1285- &ctx->dst_addr,
1286- ctx->input_msg,
1287- solution,
1288- ctx->hadb_entry->hip_version),
1289- -EPROTO,
1290- "Cookie solution rejected. Dropping the I2 packet.\n");
1291+ /* Validate DIFFIE_HELLMAN parameter */
1292+ if (NULL == (dh_param = hip_get_param(ctx->input_msg,
1293+ HIP_PARAM_DIFFIE_HELLMAN))) {
1294+ HIP_ERROR("DIFFIE_HELLMAN parameter missing from I2 packet\n");
1295+ ctx->error = -ENODATA;
1296+ return ctx->error;
1297+ }
1298+ dh_group_id = dh_param->pub_val.group_id;
1299+ for (i = 0; i < HIP_DH_GROUP_LIST_SIZE; i++) {
1300+ if (dh_group_id == HIP_DH_GROUP_LIST[i]) {
1301+ break;
1302+ }
1303+ }
1304+ if (i == HIP_DH_GROUP_LIST_SIZE) {
1305+ HIP_ERROR("Invalid group %d for DIFFIE_HELLMAN parameter.\n",
1306+ dh_group_id);
1307+ ctx->error = -EINVAL;
1308+ return ctx->error;
1309+ }
1310+ if (hip_get_dh_size(dh_group_id) != ntohs(dh_param->pub_val.pub_len)) {
1311+ HIP_ERROR("Invalid public key length for DIFFIE_HELLMAN parameter. "
1312+ "Expect: %d, Got: %d\n", hip_get_dh_size(dh_group_id),
1313+ ntohs(dh_param->pub_val.pub_len));
1314+ ctx->error = -EINVAL;
1315+ return ctx->error;
1316+ }
1317+
1318+ /* Verify cookie */
1319+ if (hip_version == HIP_V1) {
1320+ HIP_IFEL(hip_verify_cookie(&ctx->src_addr, &ctx->dst_addr,
1321+ ctx->input_msg, solution,
1322+ hip_version, 0),
1323+ -EPROTO,
1324+ "Cookie solution rejected. Dropping the I2 packet.\n");
1325+ } else {
1326+ HIP_IFEL(hip_verify_cookie(&ctx->src_addr, &ctx->dst_addr,
1327+ ctx->input_msg, solution,
1328+ hip_version, dh_group_id),
1329+ -EPROTO,
1330+ "Cookie solution rejected. Dropping the I2 packet.\n");
1331+ }
1332
1333 /* Shared secrets are reused when the received I2 is a retransmission. */
1334 if (skip_key_creation) {
1335
1336=== modified file 'libhipl/netdev.c'
1337--- libhipl/netdev.c 2012-06-03 10:26:55 +0000
1338+++ libhipl/netdev.c 2012-10-28 16:28:23 +0000
1339@@ -987,8 +987,25 @@
1340
1341 HIP_DEBUG("Using ifindex %d\n", if_index);
1342
1343- HIP_IFEL(hip_send_i1(&entry->hit_our, &entry->hit_peer, entry), -1,
1344- "Sending of I1 failed\n");
1345+ switch (entry->hip_version) {
1346+ case HIP_V1:
1347+ if (hip_send_i1(&entry->hit_our, &entry->hit_peer, entry) < 0) {
1348+ HIP_ERROR("Failed to send the I1(v1) message.\n");
1349+ return -1;
1350+ }
1351+ break;
1352+
1353+ case HIP_V2:
1354+ if (hip_send_i1_v2(&entry->hit_our, &entry->hit_peer, entry) < 0) {
1355+ HIP_ERROR("Failed to send the I1(v2) message.\n");
1356+ return -1;
1357+ }
1358+ break;
1359+
1360+ default:
1361+ HIP_ERROR("Unknown HIP version: %d\n", entry->hip_version);
1362+ return -1;
1363+ }
1364
1365 out_err:
1366
1367
1368=== modified file 'libhipl/output.c'
1369--- libhipl/output.c 2012-06-07 12:45:16 +0000
1370+++ libhipl/output.c 2012-10-28 16:28:23 +0000
1371@@ -161,7 +161,111 @@
1372 }
1373
1374 /**
1375- * Send an I1 packet to the Responder
1376+ * Send an I1 packet to the responder.
1377+ *
1378+ * This method checks the shotgun status and decides whether to use shotgun
1379+ * mode or not for I1 sending.
1380+ *
1381+ * @param i1 the I1 packet to be sent
1382+ * @param entry a pointer to the current host association database state.
1383+ * @return zero on success, or negative error value on error.
1384+ */
1385+static int send_i1_internal(struct hip_common *const i1,
1386+ struct hip_hadb_state *const entry)
1387+{
1388+ struct in6_addr *local_addr = NULL;
1389+ struct in6_addr peer_addr;
1390+ LHASH_NODE *item = NULL, *tmp = NULL;
1391+ struct hip_peer_addr_list_item *addr;
1392+ int err = 0, i = 0;
1393+
1394+ HIP_DEBUG("Sending I1 to the following addresses:\n");
1395+ print_peer_addresses_to_be_added(entry);
1396+
1397+ if (hip_shotgun_status == HIP_MSG_SHOTGUN_OFF ||
1398+ (entry->peer_addr_list_to_be_added == NULL)) {
1399+ if (hip_hadb_get_peer_addr(entry, &peer_addr)) {
1400+ HIP_ERROR("No preferred IP address for the peer.\n");
1401+ return -1;
1402+ }
1403+
1404+ local_addr = &entry->our_addr;
1405+ return send_i1_pkt(i1, local_addr, &peer_addr, entry->local_udp_port,
1406+ entry->peer_udp_port, entry);
1407+ } else {
1408+ HIP_DEBUG("Number of items in the peer addr list: %d ",
1409+ ((struct lhash_st *) entry->peer_addr_list_to_be_added)->num_items);
1410+ list_for_each_safe(item, tmp, entry->peer_addr_list_to_be_added, i)
1411+ {
1412+ addr = list_entry(item);
1413+ ipv6_addr_copy(&peer_addr, &addr->address);
1414+
1415+ err = send_i1_pkt(i1, NULL, &peer_addr, entry->local_udp_port,
1416+ entry->peer_udp_port, entry);
1417+ }
1418+ return err;
1419+ }
1420+}
1421+
1422+/**
1423+ * HIPv2: send an I1 packet to the responder.
1424+ *
1425+ * @param src_hit a pointer to the source host identity tag.
1426+ * @param dst_hit a pointer to the destination host identity tag.
1427+ * @param entry a pointer to the host association database state reserved for
1428+ * the peer.
1429+ * @return zero on success, or negative value on error.
1430+ */
1431+int hip_send_i1_v2(hip_hit_t *const src_hit, const hip_hit_t *const dst_hit,
1432+ struct hip_hadb_state *const entry)
1433+{
1434+ struct hip_common *i1 = NULL;
1435+ int err = 0;
1436+
1437+ int group_size = HIP_DH_GROUP_LIST_SIZE;
1438+ uint8_t dh_group[group_size];
1439+
1440+ memcpy(dh_group, HIP_DH_GROUP_LIST, group_size);
1441+
1442+ if (entry->state == HIP_STATE_ESTABLISHED) {
1443+ HIP_DEBUG("HIP association established, not triggering bex\n");
1444+ return 0;
1445+ }
1446+
1447+ /* Assign a local private key, public key and HIT to HA */
1448+ HIP_DEBUG_HIT("src_hit", src_hit);
1449+ HIP_DEBUG_HIT("entry->src_hit", &entry->hit_our);
1450+ HIP_IFEL(hip_init_us(entry, src_hit), -EINVAL,
1451+ "Could not assign a local host id\n");
1452+ HIP_DEBUG_HIT("entry->src_hit", &entry->hit_our);
1453+
1454+ if ((i1 = hip_msg_alloc()) == NULL) {
1455+ return -1;
1456+ }
1457+
1458+ hip_build_network_hdr(i1, HIP_I1, 0, &entry->hit_our,
1459+ dst_hit, entry->hip_version);
1460+
1461+ /* Calculate the HIP header length */
1462+ hip_calc_hdr_len(i1);
1463+
1464+ /* Build DH_GROUP_LIST */
1465+ HIP_IFEL(hip_build_param_list(i1, HIP_PARAM_DH_GROUP_LIST, dh_group,
1466+ group_size, sizeof(uint8_t)),
1467+ -1, "Failed to build param: DH_GROUP_LIST\n");
1468+
1469+ HIP_DEBUG_HIT("HIT source", &i1->hit_sender);
1470+ HIP_DEBUG_HIT("HIT dest", &i1->hit_receiver);
1471+
1472+ HIP_IFEL(send_i1_internal(i1, entry), -1, "send_i1_internal() failed\n");
1473+
1474+out_err:
1475+ free(i1);
1476+ return err;
1477+}
1478+
1479+/**
1480+ * HIPv1: send an I1 packet to the responder.
1481 *
1482 * @param src_hit a pointer to source host identity tag.
1483 * @param dst_hit a pointer to destination host identity tag.
1484@@ -172,13 +276,8 @@
1485 int hip_send_i1(hip_hit_t *src_hit, const hip_hit_t *dst_hit,
1486 struct hip_hadb_state *entry)
1487 {
1488- struct hip_common *i1 = 0;
1489- uint16_t mask = 0;
1490- int err = 0, i = 0;
1491- LHASH_NODE *item = NULL, *tmp = NULL;
1492- struct hip_peer_addr_list_item *addr;
1493- struct in6_addr *local_addr = NULL;
1494- struct in6_addr peer_addr;
1495+ struct hip_common *i1 = 0;
1496+ int err = 0;
1497
1498 #ifdef CONFIG_HIP_PERFORMANCE
1499 HIP_DEBUG("Start PERF_I1_SEND, PERF_BASE\n");
1500@@ -209,7 +308,7 @@
1501
1502 i1 = hip_msg_alloc();
1503
1504- hip_build_network_hdr(i1, HIP_I1, mask, &entry->hit_our,
1505+ hip_build_network_hdr(i1, HIP_I1, 0, &entry->hit_our,
1506 dst_hit, entry->hip_version);
1507
1508 /* Calculate the HIP header length */
1509@@ -218,30 +317,8 @@
1510 HIP_DEBUG_HIT("HIT source", &i1->hit_sender);
1511 HIP_DEBUG_HIT("HIT dest", &i1->hit_receiver);
1512
1513- HIP_DEBUG("Sending I1 to the following addresses:\n");
1514- print_peer_addresses_to_be_added(entry);
1515-
1516- if (hip_shotgun_status == HIP_MSG_SHOTGUN_OFF ||
1517- (entry->peer_addr_list_to_be_added == NULL)) {
1518- HIP_IFEL(hip_hadb_get_peer_addr(entry, &peer_addr), -1,
1519- "No preferred IP address for the peer.\n");
1520-
1521- local_addr = &entry->our_addr;
1522- err = send_i1_pkt(i1, local_addr, &peer_addr,
1523- entry->local_udp_port,
1524- entry->peer_udp_port, entry);
1525- } else {
1526- HIP_DEBUG("Number of items in the peer addr list: %d ",
1527- ((struct lhash_st *) entry->peer_addr_list_to_be_added)->num_items);
1528- list_for_each_safe(item, tmp, entry->peer_addr_list_to_be_added, i)
1529- {
1530- addr = list_entry(item);
1531- ipv6_addr_copy(&peer_addr, &addr->address);
1532-
1533- err = send_i1_pkt(i1, NULL, &peer_addr, entry->local_udp_port,
1534- entry->peer_udp_port, entry);
1535- }
1536- }
1537+ HIP_IFEL(send_i1_internal(i1, entry), -1, "send_i1_internal() failed\n");
1538+
1539 #ifdef CONFIG_HIP_PERFORMANCE
1540 HIP_DEBUG("Stop and write PERF_I1_SEND\n");
1541 hip_perf_stop_benchmark(perf_set, PERF_I1_SEND);
1542@@ -263,8 +340,8 @@
1543 */
1544 static int add_echo_response(struct hip_packet_context *ctx, int sign)
1545 {
1546- int param_type = sign ? HIP_PARAM_ECHO_REQUEST_SIGN
1547- : HIP_PARAM_ECHO_REQUEST;
1548+ int param_type =
1549+ sign ? HIP_PARAM_ECHO_REQUEST_SIGN : HIP_PARAM_ECHO_REQUEST;
1550
1551 const struct hip_echo_msg *ping = hip_get_param(ctx->input_msg, param_type);
1552
1553@@ -597,15 +674,14 @@
1554 /**
1555 * Construct a new R1 packet payload
1556 *
1557- * @param msg points to a message object backed by HIP_MAX_PACKET bytes
1558- * of memory to which the R1 message is written.
1559+ * @param msg pointer to a message backed by HIP_MAX_PACKET bytes of
1560+ * memory to which the R1 message is written.
1561 * @param src_hit a pointer to the source host identity tag used in the
1562 * packet.
1563 * @param sign a funtion pointer to a signature funtion.
1564 * @param private_key a pointer to the local host private key
1565 * @param host_id_pub a pointer to the public host id of the local host
1566 * @param cookie_k the difficulty value for the puzzle
1567- * @param hip_version HIP message version
1568 * @return 0 on success, a non-zero value on error.
1569 */
1570 int hip_create_r1(struct hip_common *const msg,
1571@@ -613,8 +689,7 @@
1572 int (*sign)(void *const key, struct hip_common *const m),
1573 void *const private_key,
1574 const struct hip_host_id *const host_id_pub,
1575- const int cookie_k,
1576- const uint8_t hip_version)
1577+ const int cookie_k)
1578 {
1579 int err = 0;
1580 struct hip_srv service_list[HIP_TOTAL_EXISTING_SERVICES];
1581@@ -682,7 +757,7 @@
1582 /** @todo TH: hip_build_network_hdr has to be replaced with an
1583 * appropriate function pointer */
1584 HIP_DEBUG_HIT("src_hit used to build r1 network header", src_hit);
1585- hip_build_network_hdr(msg, HIP_R1, mask, src_hit, NULL, hip_version);
1586+ hip_build_network_hdr(msg, HIP_R1, mask, src_hit, NULL, HIP_V1);
1587
1588 /********** R1_COUNTER (OPTIONAL) *********/
1589
1590@@ -776,6 +851,172 @@
1591 }
1592
1593 /**
1594+ * Construct a new R1 packet payload.
1595+ *
1596+ * @param msg pointer to a message backed by HIP_MAX_PACKET bytes
1597+ * of memory to which the R1 message is written
1598+ * @param src_hit a pointer to the source HIT used in the packet
1599+ * @param sign a function pointer to a signature function
1600+ * @param private_key a pointer to the local host private key
1601+ * @param host_id_pub a pointer to the public host id of the local host
1602+ * @param cookie_k the difficulty value for the puzzle
1603+ * @param dh_group_id the Diffie-Hellman group ID which will be used by this
1604+ * new R1 entry
1605+ * @return 0 on success, a non-zero value on error
1606+ */
1607+int hip_create_r1_v2(struct hip_common *const msg,
1608+ const struct in6_addr *const src_hit,
1609+ int (*sign)(void *const key, struct hip_common *const m),
1610+ void *const private_key,
1611+ const struct hip_host_id *const host_id_pub,
1612+ const int cookie_k,
1613+ const int dh_group_id)
1614+{
1615+ int err = 0;
1616+ struct hip_srv service_list[HIP_TOTAL_EXISTING_SERVICES];
1617+ uint8_t *dh_data = NULL;
1618+ char order[] = "000";
1619+ int dh_size = 0;
1620+ int mask = 0, i = 0, written = 0;
1621+ unsigned int service_count = 0;
1622+
1623+ /* Supported HIP and ESP transforms. */
1624+ hip_transform_suite transform_hip_suite[] = {
1625+ HIP_HIP_AES_SHA1,
1626+ HIP_HIP_3DES_SHA1,
1627+ HIP_HIP_NULL_SHA1
1628+ };
1629+ hip_transform_suite transform_esp_suite[] = {
1630+ HIP_ESP_AES_SHA1,
1631+ HIP_ESP_3DES_SHA1,
1632+ HIP_ESP_NULL_SHA1
1633+ };
1634+
1635+ /* change order if necessary */
1636+ sprintf(order, "%d", hip_transform_order);
1637+ for (i = 0; i < 3; i++) {
1638+ switch (order[i]) {
1639+ case '1':
1640+ transform_hip_suite[i] = HIP_HIP_AES_SHA1;
1641+ transform_esp_suite[i] = HIP_ESP_AES_SHA1;
1642+ HIP_DEBUG("Transform order index %d is AES\n", i);
1643+ break;
1644+ case '2':
1645+ transform_hip_suite[i] = HIP_HIP_3DES_SHA1;
1646+ transform_esp_suite[i] = HIP_ESP_3DES_SHA1;
1647+ HIP_DEBUG("Transform order index %d is 3DES\n", i);
1648+ break;
1649+ case '3':
1650+ transform_hip_suite[i] = HIP_HIP_NULL_SHA1;
1651+ transform_esp_suite[i] = HIP_ESP_NULL_SHA1;
1652+ HIP_DEBUG("Transform order index %d is NULL_SHA1\n", i);
1653+ break;
1654+ }
1655+ }
1656+
1657+ /* Initialize the message buffer as the message builder depends on it. */
1658+ hip_msg_init(msg);
1659+
1660+ /* Allocate memory for writing the Diffie-Hellman public value */
1661+ if ((dh_size = hip_get_dh_size(dh_group_id)) == 0) {
1662+ HIP_ERROR("Could not get dh_size\n");
1663+ return -1;
1664+ }
1665+ if ((dh_data = calloc(1, dh_size)) == NULL) {
1666+ HIP_ERROR("Failed to allocate memory for dh_data\n");
1667+ return -1;
1668+ }
1669+
1670+ /* Ready to begin building of the R1 packet */
1671+ HIP_DEBUG_HIT("src_hit used to build r1 network header", src_hit);
1672+ hip_build_network_hdr(msg, HIP_R1, mask, src_hit, NULL, HIP_V2);
1673+
1674+ /********** R1_COUNTER (OPTIONAL) *********/
1675+
1676+ /********** Parameter PUZZLE ************/
1677+ const uint8_t zero_i[PUZZLE_LENGTH] = { 0 };
1678+ //2^(42-32) sec lifetime
1679+ err = hip_build_param_puzzle(msg, cookie_k, 42, 0, zero_i);
1680+ HIP_IFEL(err, err, "Cookies were burned. Bummer!\n");
1681+
1682+ /* Parameter DH_GROUP_LIST */
1683+ uint8_t dh_group[HIP_DH_GROUP_LIST_SIZE];
1684+ memcpy(dh_group, HIP_DH_GROUP_LIST, HIP_DH_GROUP_LIST_SIZE);
1685+ HIP_IFEL(hip_build_param_list(msg, HIP_PARAM_DH_GROUP_LIST, dh_group,
1686+ HIP_DH_GROUP_LIST_SIZE, sizeof(uint8_t)),
1687+ -1, "Failed to build param DH_GROUP_LIST.\n");
1688+
1689+ /******** Parameter DIFFIE_HELLMAN ********/
1690+ HIP_IFEL((written = hip_insert_dh_v2(dh_data, dh_size, dh_group_id)) < 0,
1691+ written, "Could not extract DH public key\n");
1692+
1693+ HIP_IFEL((err = hip_build_param_diffie_hellman_contents(msg, dh_group_id,
1694+ dh_data, written,
1695+ HIP_MAX_DH_GROUP_ID,
1696+ NULL, 0)),
1697+ err, "Building of DH failed.\n");
1698+
1699+ /* Parameter HIP transform. */
1700+ HIP_IFEL((err = hip_build_param_hip_transform(msg,
1701+ transform_hip_suite,
1702+ sizeof(transform_hip_suite) /
1703+ sizeof(hip_transform_suite))),
1704+ err, "Building of HIP transform failed\n");
1705+
1706+ /* Parameter HOST_ID */
1707+ HIP_IFEL((err = hip_build_param_host_id(msg, host_id_pub)),
1708+ err, "Building of host id failed\n");
1709+
1710+ /* Parameter REG_INFO */
1711+ hip_get_active_services(service_list, &service_count);
1712+ HIP_DEBUG("Found %d active service(s) \n", service_count);
1713+ hip_build_param_reg_info(msg, service_list, service_count);
1714+
1715+ /* Parameter ESP-ENC transform. */
1716+ HIP_IFEL((err = hip_build_param_esp_transform(msg,
1717+ transform_esp_suite,
1718+ sizeof(transform_esp_suite) /
1719+ sizeof(hip_transform_suite))),
1720+ err, "Building of ESP transform failed\n");
1721+
1722+ /********** ESP-PROT transform (OPTIONAL) **********/
1723+
1724+ HIP_IFEL((err = esp_prot_r1_add_transforms(msg)), err,
1725+ "failed to add optional esp transform parameter\n");
1726+
1727+ /********** ECHO_REQUEST_SIGN (OPTIONAL) *********/
1728+
1729+ //HIP_HEXDUMP("Pubkey:", host_id_pub, hip_get_param_total_len(host_id_pub));
1730+
1731+ /* Parameter Signature 2 */
1732+
1733+ HIP_IFEL((err = sign(private_key, msg)), err, "Signing of R1 failed.\n");
1734+
1735+ /* Parameter ECHO_REQUEST (OPTIONAL) */
1736+
1737+ /* Fill puzzle parameters */
1738+ {
1739+ struct hip_puzzle *pz;
1740+
1741+ HIP_IFEL(!(pz = hip_get_param_readwrite(msg, HIP_PARAM_PUZZLE)), -1,
1742+ "Internal error\n");
1743+
1744+ /* hardcode kludge */
1745+ pz->opaque[0] = 'H';
1746+ pz->opaque[1] = 'I';
1747+
1748+ get_random_bytes(pz->I, PUZZLE_LENGTH);
1749+ }
1750+
1751+ /* Packet ready */
1752+
1753+out_err:
1754+ free(dh_data);
1755+
1756+ return err;
1757+}
1758+
1759+/**
1760 * Transmit an R1 packet to the network.
1761 *
1762 * Send an R1 packet to the peer and store the cookie information that was
1763@@ -866,10 +1107,29 @@
1764 }
1765 }
1766
1767- HIP_IFEL(!(r1pkt = hip_get_r1(r1_dst_addr, &ctx->dst_addr,
1768- &ctx->input_msg->hit_receiver,
1769- hip_get_msg_version(ctx->input_msg))),
1770- -ENOENT, "No precreated R1\n");
1771+ if (hip_get_msg_version(ctx->input_msg) == HIP_V1) {
1772+ HIP_IFEL(!(r1pkt = hip_get_r1(r1_dst_addr, &ctx->dst_addr,
1773+ &ctx->input_msg->hit_receiver)),
1774+ -ENOENT, "No precreated R1\n");
1775+ } else {
1776+ const struct hip_tlv_common *dh_group_list;
1777+ int selected_group;
1778+
1779+ dh_group_list = hip_get_param(ctx->input_msg, HIP_PARAM_DH_GROUP_LIST);
1780+ HIP_IFEL(dh_group_list == NULL, -1, "No DH_GROUP_LIST parameter in r1\n");
1781+
1782+ selected_group = hip_match_dh_group_list(dh_group_list,
1783+ HIP_DH_GROUP_LIST,
1784+ HIP_DH_GROUP_LIST_SIZE);
1785+ HIP_IFEL(selected_group == -1, -1,
1786+ "Cannot find a matchness for DH_GROUP_LIST\n");
1787+ HIP_DEBUG("Selected DH group: %d\n", selected_group);
1788+
1789+ r1pkt = hip_get_r1_v2(r1_dst_addr, &ctx->dst_addr,
1790+ &ctx->input_msg->hit_receiver, selected_group);
1791+ HIP_IFEL(r1pkt == NULL, -ENOENT, "No precreated R1_v2 for group: %d\n",
1792+ selected_group);
1793+ }
1794
1795 if (&ctx->input_msg->hit_sender) {
1796 ipv6_addr_copy(&r1pkt->hit_receiver, &ctx->input_msg->hit_sender);
1797
1798=== modified file 'libhipl/output.h'
1799--- libhipl/output.h 2012-06-03 10:26:55 +0000
1800+++ libhipl/output.h 2012-10-28 16:28:23 +0000
1801@@ -52,8 +52,15 @@
1802 int (*sign)(void *const key, struct hip_common *const m),
1803 void *const private_key,
1804 const struct hip_host_id *const host_id_pub,
1805- const int cookie_k,
1806- const uint8_t hip_version);
1807+ const int cookie_k);
1808+
1809+int hip_create_r1_v2(struct hip_common *const msg,
1810+ const struct in6_addr *const src_hit,
1811+ int (*sign)(void *const key, struct hip_common *const m),
1812+ void *const private_key,
1813+ const struct hip_host_id *const host_id_pub,
1814+ const int cookie_k,
1815+ const int dh_group_id);
1816
1817 int hip_send_r1(const uint8_t packet_type,
1818 const enum hip_state ha_state,
1819@@ -81,6 +88,9 @@
1820
1821 int hip_send_i1(hip_hit_t *, const hip_hit_t *, struct hip_hadb_state *);
1822
1823+int hip_send_i1_v2(hip_hit_t *const src_hit, const hip_hit_t *const dst_hit,
1824+ struct hip_hadb_state *const entry);
1825+
1826 int hip_add_signed_echo_response(const uint8_t packet_type,
1827 const enum hip_state ha_state,
1828 struct hip_packet_context *ctx);
1829
1830=== modified file 'test/libcore/crypto.c'
1831--- test/libcore/crypto.c 2012-05-12 06:54:33 +0000
1832+++ test/libcore/crypto.c 2012-10-28 16:28:23 +0000
1833@@ -1,5 +1,5 @@
1834 /*
1835- * Copyright (c) 2011 Aalto University and RWTH Aachen University.
1836+ * Copyright (c) 2011-2012 Aalto University and RWTH Aachen University.
1837 *
1838 * Permission is hereby granted, free of charge, to any person
1839 * obtaining a copy of this software and associated documentation
1840@@ -28,12 +28,235 @@
1841 #include <string.h>
1842 #include <stdio.h>
1843 #include <unistd.h>
1844+#ifdef HAVE_EC_CRYPTO
1845+#include <openssl/ecdh.h>
1846+#endif
1847
1848 #include "libcore/crypto.h"
1849 #include "config.h"
1850 #include "test_suites.h"
1851
1852+
1853 #ifdef HAVE_EC_CRYPTO
1854+
1855+static const int TEST_ECDH_PRIV_A = 0;
1856+static const int TEST_ECDH_PUBX_A = 1;
1857+static const int TEST_ECDH_PUBY_A = 2;
1858+static const int TEST_ECDH_PRIV_B = 3;
1859+static const int TEST_ECDH_PUBX_B = 4;
1860+static const int TEST_ECDH_PUBY_B = 5;
1861+static const int TEST_ECDH_SHARED = 6;
1862+
1863+/* An example for testing from RFC5903, section 8.1 */
1864+static unsigned char TEST_ECDH_NIST_P_256[] = {
1865+ 0xC8, 0x8F, 0x01, 0xF5, 0x10, 0xD9, 0xAC, 0x3F, 0x70, 0xA2,
1866+ 0x92, 0xDA, 0xA2, 0x31, 0x6D, 0xE5, 0x44, 0xE9, 0xAA, 0xB8,
1867+ 0xAF, 0xE8, 0x40, 0x49, 0xC6, 0x2A, 0x9C, 0x57, 0x86, 0x2D,
1868+ 0x14, 0x33,
1869+
1870+ 0xDA, 0xD0, 0xB6, 0x53, 0x94, 0x22, 0x1C, 0xF9, 0xB0, 0x51,
1871+ 0xE1, 0xFE, 0xCA, 0x57, 0x87, 0xD0, 0x98, 0xDF, 0xE6, 0x37,
1872+ 0xFC, 0x90, 0xB9, 0xEF, 0x94, 0x5D, 0x0C, 0x37, 0x72, 0x58,
1873+ 0x11, 0x80,
1874+
1875+ 0x52, 0x71, 0xA0, 0x46, 0x1C, 0xDB, 0x82, 0x52, 0xD6, 0x1F,
1876+ 0x1C, 0x45, 0x6F, 0xA3, 0xE5, 0x9A, 0xB1, 0xF4, 0x5B, 0x33,
1877+ 0xAC, 0xCF, 0x5F, 0x58, 0x38, 0x9E, 0x05, 0x77, 0xB8, 0x99,
1878+ 0x0B, 0xB3,
1879+
1880+ 0xC6, 0xEF, 0x9C, 0x5D, 0x78, 0xAE, 0x01, 0x2A, 0x01, 0x11,
1881+ 0x64, 0xAC, 0xB3, 0x97, 0xCE, 0x20, 0x88, 0x68, 0x5D, 0x8F,
1882+ 0x06, 0xBF, 0x9B, 0xE0, 0xB2, 0x83, 0xAB, 0x46, 0x47, 0x6B,
1883+ 0xEE, 0x53,
1884+
1885+ 0xD1, 0x2D, 0xFB, 0x52, 0x89, 0xC8, 0xD4, 0xF8, 0x12, 0x08,
1886+ 0xB7, 0x02, 0x70, 0x39, 0x8C, 0x34, 0x22, 0x96, 0x97, 0x0A,
1887+ 0x0B, 0xCC, 0xB7, 0x4C, 0x73, 0x6F, 0xC7, 0x55, 0x44, 0x94,
1888+ 0xBF, 0x63,
1889+
1890+ 0x56, 0xFB, 0xF3, 0xCA, 0x36, 0x6C, 0xC2, 0x3E, 0x81, 0x57,
1891+ 0x85, 0x4C, 0x13, 0xC5, 0x8D, 0x6A, 0xAC, 0x23, 0xF0, 0x46,
1892+ 0xAD, 0xA3, 0x0F, 0x83, 0x53, 0xE7, 0x4F, 0x33, 0x03, 0x98,
1893+ 0x72, 0xAB,
1894+
1895+ 0xD6, 0x84, 0x0F, 0x6B, 0x42, 0xF6, 0xED, 0xAF, 0xD1, 0x31,
1896+ 0x16, 0xE0, 0xE1, 0x25, 0x65, 0x20, 0x2F, 0xEF, 0x8E, 0x9E,
1897+ 0xCE, 0x7D, 0xCE, 0x03, 0x81, 0x24, 0x64, 0xD0, 0x4B, 0x94,
1898+ 0x42, 0xDE,
1899+};
1900+
1901+/* An example for testing from RFC5903, section 8.2 */
1902+static unsigned char TEST_ECDH_NIST_P_384[] = {
1903+ 0x09, 0x9F, 0x3C, 0x70, 0x34, 0xD4, 0xA2, 0xC6, 0x99, 0x88,
1904+ 0x4D, 0x73, 0xA3, 0x75, 0xA6, 0x7F, 0x76, 0x24, 0xEF, 0x7C,
1905+ 0x6B, 0x3C, 0x0F, 0x16, 0x06, 0x47, 0xB6, 0x74, 0x14, 0xDC,
1906+ 0xE6, 0x55, 0xE3, 0x5B, 0x53, 0x80, 0x41, 0xE6, 0x49, 0xEE,
1907+ 0x3F, 0xAE, 0xF8, 0x96, 0x78, 0x3A, 0xB1, 0x94,
1908+
1909+ 0x66, 0x78, 0x42, 0xD7, 0xD1, 0x80, 0xAC, 0x2C, 0xDE, 0x6F,
1910+ 0x74, 0xF3, 0x75, 0x51, 0xF5, 0x57, 0x55, 0xC7, 0x64, 0x5C,
1911+ 0x20, 0xEF, 0x73, 0xE3, 0x16, 0x34, 0xFE, 0x72, 0xB4, 0xC5,
1912+ 0x5E, 0xE6, 0xDE, 0x3A, 0xC8, 0x08, 0xAC, 0xB4, 0xBD, 0xB4,
1913+ 0xC8, 0x87, 0x32, 0xAE, 0xE9, 0x5F, 0x41, 0xAA,
1914+
1915+ 0x94, 0x82, 0xED, 0x1F, 0xC0, 0xEE, 0xB9, 0xCA, 0xFC, 0x49,
1916+ 0x84, 0x62, 0x5C, 0xCF, 0xC2, 0x3F, 0x65, 0x03, 0x21, 0x49,
1917+ 0xE0, 0xE1, 0x44, 0xAD, 0xA0, 0x24, 0x18, 0x15, 0x35, 0xA0,
1918+ 0xF3, 0x8E, 0xEB, 0x9F, 0xCF, 0xF3, 0xC2, 0xC9, 0x47, 0xDA,
1919+ 0xE6, 0x9B, 0x4C, 0x63, 0x45, 0x73, 0xA8, 0x1C,
1920+
1921+ 0x41, 0xCB, 0x07, 0x79, 0xB4, 0xBD, 0xB8, 0x5D, 0x47, 0x84,
1922+ 0x67, 0x25, 0xFB, 0xEC, 0x3C, 0x94, 0x30, 0xFA, 0xB4, 0x6C,
1923+ 0xC8, 0xDC, 0x50, 0x60, 0x85, 0x5C, 0xC9, 0xBD, 0xA0, 0xAA,
1924+ 0x29, 0x42, 0xE0, 0x30, 0x83, 0x12, 0x91, 0x6B, 0x8E, 0xD2,
1925+ 0x96, 0x0E, 0x4B, 0xD5, 0x5A, 0x74, 0x48, 0xFC,
1926+
1927+ 0xE5, 0x58, 0xDB, 0xEF, 0x53, 0xEE, 0xCD, 0xE3, 0xD3, 0xFC,
1928+ 0xCF, 0xC1, 0xAE, 0xA0, 0x8A, 0x89, 0xA9, 0x87, 0x47, 0x5D,
1929+ 0x12, 0xFD, 0x95, 0x0D, 0x83, 0xCF, 0xA4, 0x17, 0x32, 0xBC,
1930+ 0x50, 0x9D, 0x0D, 0x1A, 0xC4, 0x3A, 0x03, 0x36, 0xDE, 0xF9,
1931+ 0x6F, 0xDA, 0x41, 0xD0, 0x77, 0x4A, 0x35, 0x71,
1932+
1933+ 0xDC, 0xFB, 0xEC, 0x7A, 0xAC, 0xF3, 0x19, 0x64, 0x72, 0x16,
1934+ 0x9E, 0x83, 0x84, 0x30, 0x36, 0x7F, 0x66, 0xEE, 0xBE, 0x3C,
1935+ 0x6E, 0x70, 0xC4, 0x16, 0xDD, 0x5F, 0x0C, 0x68, 0x75, 0x9D,
1936+ 0xD1, 0xFF, 0xF8, 0x3F, 0xA4, 0x01, 0x42, 0x20, 0x9D, 0xFF,
1937+ 0x5E, 0xAA, 0xD9, 0x6D, 0xB9, 0xE6, 0x38, 0x6C,
1938+
1939+ 0x11, 0x18, 0x73, 0x31, 0xC2, 0x79, 0x96, 0x2D, 0x93, 0xD6,
1940+ 0x04, 0x24, 0x3F, 0xD5, 0x92, 0xCB, 0x9D, 0x0A, 0x92, 0x6F,
1941+ 0x42, 0x2E, 0x47, 0x18, 0x75, 0x21, 0x28, 0x7E, 0x71, 0x56,
1942+ 0xC5, 0xC4, 0xD6, 0x03, 0x13, 0x55, 0x69, 0xB9, 0xE9, 0xD0,
1943+ 0x9C, 0xF5, 0xD4, 0xA2, 0x70, 0xF5, 0x97, 0x46
1944+};
1945+
1946+/* An example for testing from RFC5903, section 8.3 */
1947+static unsigned char TEST_ECDH_NIST_P_521[] = {
1948+ 0x00, 0x37, 0xAD, 0xE9, 0x31, 0x9A, 0x89, 0xF4, 0xDA, 0xBD,
1949+ 0xB3, 0xEF, 0x41, 0x1A, 0xAC, 0xCC, 0xA5, 0x12, 0x3C, 0x61,
1950+ 0xAC, 0xAB, 0x57, 0xB5, 0x39, 0x3D, 0xCE, 0x47, 0x60, 0x81,
1951+ 0x72, 0xA0, 0x95, 0xAA, 0x85, 0xA3, 0x0F, 0xE1, 0xC2, 0x95,
1952+ 0x2C, 0x67, 0x71, 0xD9, 0x37, 0xBA, 0x97, 0x77, 0xF5, 0x95,
1953+ 0x7B, 0x26, 0x39, 0xBA, 0xB0, 0x72, 0x46, 0x2F, 0x68, 0xC2,
1954+ 0x7A, 0x57, 0x38, 0x2D, 0x4A, 0x52,
1955+
1956+ 0x00, 0x15, 0x41, 0x7E, 0x84, 0xDB, 0xF2, 0x8C, 0x0A, 0xD3,
1957+ 0xC2, 0x78, 0x71, 0x33, 0x49, 0xDC, 0x7D, 0xF1, 0x53, 0xC8,
1958+ 0x97, 0xA1, 0x89, 0x1B, 0xD9, 0x8B, 0xAB, 0x43, 0x57, 0xC9,
1959+ 0xEC, 0xBE, 0xE1, 0xE3, 0xBF, 0x42, 0xE0, 0x0B, 0x8E, 0x38,
1960+ 0x0A, 0xEA, 0xE5, 0x7C, 0x2D, 0x10, 0x75, 0x64, 0x94, 0x18,
1961+ 0x85, 0x94, 0x2A, 0xF5, 0xA7, 0xF4, 0x60, 0x17, 0x23, 0xC4,
1962+ 0x19, 0x5D, 0x17, 0x6C, 0xED, 0x3E,
1963+
1964+ 0x01, 0x7C, 0xAE, 0x20, 0xB6, 0x64, 0x1D, 0x2E, 0xEB, 0x69,
1965+ 0x57, 0x86, 0xD8, 0xC9, 0x46, 0x14, 0x62, 0x39, 0xD0, 0x99,
1966+ 0xE1, 0x8E, 0x1D, 0x5A, 0x51, 0x4C, 0x73, 0x9D, 0x7C, 0xB4,
1967+ 0xA1, 0x0A, 0xD8, 0xA7, 0x88, 0x01, 0x5A, 0xC4, 0x05, 0xD7,
1968+ 0x79, 0x9D, 0xC7, 0x5E, 0x7B, 0x7D, 0x5B, 0x6C, 0xF2, 0x26,
1969+ 0x1A, 0x6A, 0x7F, 0x15, 0x07, 0x43, 0x8B, 0xF0, 0x1B, 0xEB,
1970+ 0x6C, 0xA3, 0x92, 0x6F, 0x95, 0x82,
1971+
1972+ 0x01, 0x45, 0xBA, 0x99, 0xA8, 0x47, 0xAF, 0x43, 0x79, 0x3F,
1973+ 0xDD, 0x0E, 0x87, 0x2E, 0x7C, 0xDF, 0xA1, 0x6B, 0xE3, 0x0F,
1974+ 0xDC, 0x78, 0x0F, 0x97, 0xBC, 0xCC, 0x3F, 0x07, 0x83, 0x80,
1975+ 0x20, 0x1E, 0x9C, 0x67, 0x7D, 0x60, 0x0B, 0x34, 0x37, 0x57,
1976+ 0xA3, 0xBD, 0xBF, 0x2A, 0x31, 0x63, 0xE4, 0xC2, 0xF8, 0x69,
1977+ 0xCC, 0xA7, 0x45, 0x8A, 0xA4, 0xA4, 0xEF, 0xFC, 0x31, 0x1F,
1978+ 0x5C, 0xB1, 0x51, 0x68, 0x5E, 0xB9,
1979+
1980+ 0x00, 0xD0, 0xB3, 0x97, 0x5A, 0xC4, 0xB7, 0x99, 0xF5, 0xBE,
1981+ 0xA1, 0x6D, 0x5E, 0x13, 0xE9, 0xAF, 0x97, 0x1D, 0x5E, 0x9B,
1982+ 0x98, 0x4C, 0x9F, 0x39, 0x72, 0x8B, 0x5E, 0x57, 0x39, 0x73,
1983+ 0x5A, 0x21, 0x9B, 0x97, 0xC3, 0x56, 0x43, 0x6A, 0xDC, 0x6E,
1984+ 0x95, 0xBB, 0x03, 0x52, 0xF6, 0xBE, 0x64, 0xA6, 0xC2, 0x91,
1985+ 0x2D, 0x4E, 0xF2, 0xD0, 0x43, 0x3C, 0xED, 0x2B, 0x61, 0x71,
1986+ 0x64, 0x00, 0x12, 0xD9, 0x46, 0x0F,
1987+
1988+ 0x01, 0x5C, 0x68, 0x22, 0x63, 0x83, 0x95, 0x6E, 0x3B, 0xD0,
1989+ 0x66, 0xE7, 0x97, 0xB6, 0x23, 0xC2, 0x7C, 0xE0, 0xEA, 0xC2,
1990+ 0xF5, 0x51, 0xA1, 0x0C, 0x2C, 0x72, 0x4D, 0x98, 0x52, 0x07,
1991+ 0x7B, 0x87, 0x22, 0x0B, 0x65, 0x36, 0xC5, 0xC4, 0x08, 0xA1,
1992+ 0xD2, 0xAE, 0xBB, 0x8E, 0x86, 0xD6, 0x78, 0xAE, 0x49, 0xCB,
1993+ 0x57, 0x09, 0x1F, 0x47, 0x32, 0x29, 0x65, 0x79, 0xAB, 0x44,
1994+ 0xFC, 0xD1, 0x7F, 0x0F, 0xC5, 0x6A,
1995+
1996+ 0x01, 0x14, 0x4C, 0x7D, 0x79, 0xAE, 0x69, 0x56, 0xBC, 0x8E,
1997+ 0xDB, 0x8E, 0x7C, 0x78, 0x7C, 0x45, 0x21, 0xCB, 0x08, 0x6F,
1998+ 0xA6, 0x44, 0x07, 0xF9, 0x78, 0x94, 0xE5, 0xE6, 0xB2, 0xD7,
1999+ 0x9B, 0x04, 0xD1, 0x42, 0x7E, 0x73, 0xCA, 0x4B, 0xAA, 0x24,
2000+ 0x0A, 0x34, 0x78, 0x68, 0x59, 0x81, 0x0C, 0x06, 0xB3, 0xC7,
2001+ 0x15, 0xA3, 0xA8, 0xCC, 0x31, 0x51, 0xF2, 0xBE, 0xE4, 0x17,
2002+ 0x99, 0x6D, 0x19, 0xF3, 0xDD, 0xEA,
2003+};
2004+
2005+enum ecdh_data { SIDE_A_KEY, SIDE_B_KEY, SHARED_SECRET };
2006+static void *generate_test_ecdh_data(const int group_id,
2007+ enum ecdh_data request_data)
2008+{
2009+ uint8_t *data_set;
2010+ int size;
2011+ EC_KEY *key;
2012+ const EC_GROUP *group;
2013+ const BIGNUM *k_priv = NULL;
2014+ const BIGNUM *k_pubx = NULL;
2015+ const BIGNUM *k_puby = NULL;
2016+ EC_POINT *k_pub = NULL;
2017+
2018+ switch (group_id) {
2019+ case HIP_DH_NIST_P_256:
2020+ data_set = TEST_ECDH_NIST_P_256;
2021+ break;
2022+
2023+ case HIP_DH_NIST_P_384:
2024+ data_set = TEST_ECDH_NIST_P_384;
2025+ break;
2026+
2027+ case HIP_DH_NIST_P_521:
2028+ data_set = TEST_ECDH_NIST_P_521;
2029+ break;
2030+
2031+ default:
2032+ return NULL;
2033+ }
2034+
2035+ size = hip_get_dh_size(group_id) / 2;
2036+
2037+ switch (request_data) {
2038+ case SIDE_A_KEY:
2039+ key = hip_generate_ecdh_key(group_id);
2040+ group = EC_KEY_get0_group(key);
2041+ k_priv = BN_bin2bn(data_set + size * TEST_ECDH_PRIV_A, size, NULL);
2042+ k_pubx = BN_bin2bn(data_set + size * TEST_ECDH_PUBX_A, size, NULL);
2043+ k_puby = BN_bin2bn(data_set + size * TEST_ECDH_PUBY_A, size, NULL);
2044+ k_pub = EC_POINT_new(group);
2045+
2046+ EC_POINT_set_affine_coordinates_GFp(group, k_pub, k_pubx, k_puby, NULL);
2047+ EC_KEY_set_public_key(key, k_pub);
2048+ EC_KEY_set_private_key(key, k_priv);
2049+
2050+ return key;
2051+
2052+ case SIDE_B_KEY:
2053+ key = hip_generate_ecdh_key(group_id);
2054+ group = EC_KEY_get0_group(key);
2055+ k_priv = BN_bin2bn(data_set + size * TEST_ECDH_PRIV_B, size, NULL);
2056+ k_pubx = BN_bin2bn(data_set + size * TEST_ECDH_PUBX_B, size, NULL);
2057+ k_puby = BN_bin2bn(data_set + size * TEST_ECDH_PUBY_B, size, NULL);
2058+ k_pub = EC_POINT_new(group);
2059+
2060+ EC_POINT_set_affine_coordinates_GFp(group, k_pub, k_pubx, k_puby, NULL);
2061+ EC_KEY_set_public_key(key, k_pub);
2062+ EC_KEY_set_private_key(key, k_priv);
2063+
2064+ return key;
2065+
2066+ case SHARED_SECRET:
2067+ return data_set + size * TEST_ECDH_SHARED;
2068+ }
2069+
2070+ return NULL;
2071+}
2072+
2073 START_TEST(test_create_ecdsa_key_invalid_id)
2074 {
2075 HIP_DEBUG("Trying to create some invalid ECDSA keys.\n");
2076@@ -244,6 +467,108 @@
2077 }
2078 END_TEST
2079
2080+#define TEST_ECDH_GROUP_SIZE 3
2081+static int TEST_ECDH_GROUPS[TEST_ECDH_GROUP_SIZE] = { HIP_DH_NIST_P_256,
2082+ HIP_DH_NIST_P_384,
2083+ HIP_DH_NIST_P_521 };
2084+
2085+START_TEST(test_generate_ecdh_key_invalid_group_id)
2086+{
2087+ fail_unless(hip_generate_ecdh_key(0) == NULL);
2088+ fail_unless(hip_generate_ecdh_key(-1) == NULL);
2089+ fail_unless(hip_generate_ecdh_key(HIP_MAX_DH_GROUP_ID) == NULL);
2090+}
2091+END_TEST
2092+
2093+START_TEST(test_generate_ecdh_key_valid_group_id)
2094+{
2095+ EC_KEY *key;
2096+ int i;
2097+
2098+ for (i = 0; i < TEST_ECDH_GROUP_SIZE; i++) {
2099+ key = hip_generate_ecdh_key(TEST_ECDH_GROUPS[i]);
2100+ fail_if(key == NULL || EC_KEY_check_key(key) == 0);
2101+ }
2102+}
2103+END_TEST
2104+
2105+START_TEST(test_ecdh_generate_2_keys_and_share_secret)
2106+{
2107+ EC_KEY *key1;
2108+ EC_KEY *key2;
2109+ int out1, out2;
2110+ int len1, len2;
2111+ int i;
2112+ int group_id;
2113+ int pubkey_size;
2114+
2115+ for (i = 0; i < TEST_ECDH_GROUP_SIZE; i++) {
2116+ group_id = TEST_ECDH_GROUPS[i];
2117+ pubkey_size = hip_get_dh_size(group_id);
2118+ fail_if(pubkey_size <= 0);
2119+
2120+ key1 = hip_generate_ecdh_key(group_id);
2121+ key2 = hip_generate_ecdh_key(group_id);
2122+ fail_if(key1 == NULL || key2 == NULL);
2123+
2124+ const EC_POINT *k1pub = EC_KEY_get0_public_key(key1);
2125+ const EC_POINT *k2pub = EC_KEY_get0_public_key(key2);
2126+
2127+ len1 = len2 = pubkey_size / 2;
2128+ unsigned char share1[len1];
2129+ unsigned char share2[len2];
2130+
2131+ out1 = ECDH_compute_key(share1, len1, k2pub, key1, NULL);
2132+ out2 = ECDH_compute_key(share2, len2, k1pub, key2, NULL);
2133+ fail_if(out1 <= 0 || out2 <= 0);
2134+ fail_if(out1 != len1 && out2 != len2);
2135+ fail_if(memcmp(share1, share2, len1) != 0);
2136+ }
2137+}
2138+END_TEST
2139+
2140+START_TEST(test_ecdh_encode_publickey)
2141+{
2142+ int i, group_id, key_size;
2143+
2144+ for (i = 0; i < TEST_ECDH_GROUP_SIZE; i++) {
2145+ group_id = TEST_ECDH_GROUPS[i];
2146+ key_size = hip_get_dh_size(group_id);
2147+ uint8_t out[key_size];
2148+ EC_KEY *key = hip_generate_ecdh_key(group_id);
2149+ fail_if(hip_encode_ecdh_publickey(key, out, key_size) != key_size);
2150+ }
2151+}
2152+END_TEST
2153+
2154+START_TEST(test_ecdh_gen_shared_key)
2155+{
2156+ int i, group_id, size, res;
2157+
2158+ for (i = 0; i < TEST_ECDH_GROUP_SIZE; i++) {
2159+ group_id = TEST_ECDH_GROUPS[i];
2160+ size = hip_get_dh_size(group_id) / 2;
2161+ uint8_t pub[size * 2];
2162+ uint8_t out[size];
2163+ EC_KEY *a = generate_test_ecdh_data(group_id, SIDE_A_KEY);
2164+ EC_KEY *b = generate_test_ecdh_data(group_id, SIDE_B_KEY);
2165+ void *secret = generate_test_ecdh_data(group_id, SHARED_SECRET);
2166+ fail_if(a == NULL || b == NULL || secret == NULL);
2167+ fail_if(EC_KEY_check_key(a) == 0 || EC_KEY_check_key(b) == 0);
2168+
2169+ hip_encode_ecdh_publickey(b, pub, size * 2);
2170+ res = hip_gen_ecdh_shared_key(a, pub, pub + size, size, out, size);
2171+ fail_if(res != size);
2172+ fail_if(memcmp(secret, out, size) != 0);
2173+
2174+ hip_encode_ecdh_publickey(a, pub, size * 2);
2175+ res = hip_gen_ecdh_shared_key(b, pub, pub + size, size, out, size);
2176+ fail_if(res != size);
2177+ fail_if(memcmp(secret, out, size) != 0);
2178+ }
2179+}
2180+END_TEST
2181+
2182 Suite *libcore_crypto(void)
2183 {
2184 Suite *s = suite_create("libcore/crypto");
2185@@ -257,6 +582,11 @@
2186 tcase_add_test(tc_core, test_load_invalid_ecdsa_key);
2187 tcase_add_test(tc_core, test_impl_ecdsa_sign_verify);
2188 tcase_add_test(tc_core, test_invalid_impl_ecdsa_sign_verify);
2189+ tcase_add_test(tc_core, test_generate_ecdh_key_invalid_group_id);
2190+ tcase_add_test(tc_core, test_generate_ecdh_key_valid_group_id);
2191+ tcase_add_test(tc_core, test_ecdh_generate_2_keys_and_share_secret);
2192+ tcase_add_test(tc_core, test_ecdh_encode_publickey);
2193+ tcase_add_test(tc_core, test_ecdh_gen_shared_key);
2194
2195 suite_add_tcase(s, tc_core);
2196

Subscribers

People subscribed via source and target branches

to all changes: