2 * rr_cookie.c - Mobile IPv6 return routability crypto
3 * Author : Henrik Petander <henrik.petander@hut.fi>
5 * $Id: s.rr_crypto.c 1.20 03/04/10 13:02:40+03:00 anttit@jon.mipl.mediapoli.com $
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
16 #include <linux/kernel.h>
17 #include <linux/types.h>
18 #include <linux/spinlock.h>
19 #include <linux/sched.h>
20 #include <linux/timer.h>
21 #include <linux/in6.h>
22 #include <linux/init.h>
23 #include <linux/random.h>
24 #include <linux/module.h>
30 #include "rr_crypto.h"
34 u8 k_CN[HMAC_SHA1_KEY_SIZE]; // secret key of CN
38 struct nonce_timestamp nonce_table[MAX_NONCES];
39 spinlock_t nonce_lock = SPIN_LOCK_UNLOCKED;
40 void update_nonces(void);
42 /** nonce_is_fresh - whether the nonce was generated recently
44 * @non_ts : table entry containing the nonce and a timestamp
45 * @interval : if nonce was generated within interval seconds it is fresh
47 * Returns 1 if the nonce is fresh, 0 otherwise.
49 static int nonce_is_fresh(struct nonce_timestamp *non_ts, unsigned long interval)
51 if (time_before(jiffies, non_ts->timestamp + interval * HZ))
56 /* Returns a pointer to a new nonce */
57 struct mipv6_rr_nonce * mipv6_rr_get_new_nonce(void)
59 struct mipv6_rr_nonce *nce = kmalloc(sizeof(*nce), GFP_ATOMIC);
64 spin_lock_bh(&nonce_lock);
65 // If nonce is not fresh create new one
66 if (!nonce_is_fresh(&nonce_table[curr_index], MIPV6_RR_NONCE_LIFETIME)) {
67 // increment the last nonce pointer and create new nonce
70 if (curr_index == MAX_NONCES)
72 // Get random data to fill the nonce data
73 get_random_bytes(nonce_table[curr_index].nonce.data, MIPV6_RR_NONCE_DATA_LENGTH);
74 // Fill the index field
75 nonce_table[curr_index].nonce.index = curr_index;
76 nonce_table[curr_index].timestamp = jiffies;
78 spin_unlock_bh(&nonce_lock);
79 memcpy(nce, &nonce_table[curr_index].nonce, sizeof(*nce));
83 /** mipv6_rr_nonce_get_by_index - returns a nonce for index
84 * @nonce_ind : index of the nonce
86 * Returns a nonce or NULL if the nonce index was invalid or the nonce
87 * for the index was not fresh.
89 struct mipv6_rr_nonce * mipv6_rr_nonce_get_by_index(u16 nonce_ind)
91 struct mipv6_rr_nonce *nce = NULL;
93 spin_lock_bh(&nonce_lock);
94 if (nonce_ind >= MAX_NONCES) {
95 DEBUG(DBG_WARNING, "Nonce index field from BU invalid");
97 /* Here a double of the nonce_lifetime is used for freshness
98 * verification, since the nonces
99 * are not created in response to every initiator packet
101 } else if (nonce_is_fresh(&nonce_table[nonce_ind], 2 * MIPV6_RR_NONCE_LIFETIME)) {
102 nce = kmalloc(sizeof(*nce), GFP_ATOMIC);
103 memcpy(nce, &nonce_table[nonce_ind].nonce, sizeof(*nce));
105 spin_unlock_bh(&nonce_lock);
110 /* Fills rr test init cookies with random bytes */
111 void mipv6_rr_mn_cookie_create(u8 *cookie)
113 get_random_bytes(cookie, MIPV6_RR_COOKIE_LENGTH);
116 /** mipv6_rr_cookie_create - builds a home or care-of cookie
118 * @addr : the home or care-of address from HoTI or CoTI
119 * @ckie : memory where the cookie is copied to
120 * @nce : pointer to a nonce used for the calculation, nce is freed during the function
123 int mipv6_rr_cookie_create(struct in6_addr *addr, u8 **ckie,
126 struct ah_processing ah_proc;
127 u8 digest[HMAC_SHA1_HASH_LEN];
128 struct mipv6_rr_nonce *nce;
130 if ((nce = mipv6_rr_nonce_get_by_index(nonce_index))== NULL)
133 if (*ckie == NULL && (*ckie = kmalloc(MIPV6_RR_COOKIE_LENGTH,
134 GFP_ATOMIC)) == NULL) {
138 /* Calculate the full hmac-sha1 digest from address and nonce using the secret key of cn */
140 if (ah_hmac_sha1_init(&ah_proc, k_CN, HMAC_SHA1_KEY_SIZE) < 0) {
141 DEBUG(DBG_ERROR, "Hmac sha1 initialization failed");
146 ah_hmac_sha1_loop(&ah_proc, addr, sizeof(*addr));
147 ah_hmac_sha1_loop(&ah_proc, nce->data, MIPV6_RR_NONCE_DATA_LENGTH);
148 ah_hmac_sha1_result(&ah_proc, digest);
154 /* Copy first 64 bits of hash target to the cookie */
155 memcpy(*ckie, digest, MIPV6_RR_COOKIE_LENGTH);
159 /** mipv6_rr_key_calc - creates BU authentication key
162 * @coc : Care-of Cookie
164 * Returns BU authentication key of length HMAC_SHA1_KEY_SIZE or NULL in error cases,
165 * caller needs to free the key.
167 u8 *mipv6_rr_key_calc(u8 *hoc, u8 *coc)
170 u8 *key_bu = kmalloc(HMAC_SHA1_KEY_SIZE, GFP_ATOMIC);
174 DEBUG(DBG_CRITICAL, "Memory allocation failed, could nort create BU authentication key");
178 /* Calculate the key from home and care-of cookies
179 * Kbu = sha1(home_cookie | care-of cookie)
180 * or KBu = sha1(home_cookie), if MN deregisters
183 sha1_compute(&c, hoc, MIPV6_RR_COOKIE_LENGTH);
185 sha1_compute(&c, coc, MIPV6_RR_COOKIE_LENGTH);
186 sha1_final(&c, key_bu);
187 DEBUG(DBG_RR, "Home and Care-of cookies used for calculating key ");
188 debug_print_buffer(DBG_RR, hoc, MIPV6_RR_COOKIE_LENGTH);
190 debug_print_buffer(DBG_RR, coc, MIPV6_RR_COOKIE_LENGTH);
195 void mipv6_rr_init(void)
197 get_random_bytes(k_CN, HMAC_SHA1_KEY_SIZE);
198 memset(nonce_table, 0, MAX_NONCES * sizeof(struct nonce_timestamp));
201 #ifdef TEST_MIPV6_RR_CRYPTO
202 void mipv6_test_rr(void)
204 struct mipv6_rr_nonce *nonce;
205 struct in6_addr a1, a2;
207 u8 *ckie1 = NULL, *ckie2 = NULL;
208 u8 *key_mn = NULL, *key_cn = NULL;
211 nonce = mipv6_rr_get_new_nonce();
213 printk("mipv6_rr_get_new_nonce() failed, at 1! \n");
216 mipv6_rr_cookie_create(&a1, &ckie1, nonce->index);
220 nonce = mipv6_rr_get_new_nonce();
222 printk("mipv6_rr_get_new_nonce() failed, at 2! \n");
226 mipv6_rr_cookie_create(&a2, &ckie2, nonce->index);
228 key_mn = mipv6_rr_key_calc(ckie1, ckie2);
230 /* Create home and coa cookies based on indices */
231 mipv6_rr_cookie_create(&a1, &ckie1, ind1);
232 mipv6_rr_cookie_create(&a2, &ckie2, ind2);
233 key_cn = mipv6_rr_key_calc(ckie1, ckie2);
234 if (!key_cn || !key_mn) {
235 printk("creation of secret key failed!\n");
238 if(memcmp(key_cn, key_mn, HMAC_SHA1_KEY_SIZE))
239 printk("mipv6_rr_key_calc produced different keys for MN and CN \n");
241 printk("mipv6_rr_crypto test OK\n");
247 EXPORT_SYMBOL(mipv6_rr_key_calc);
248 EXPORT_SYMBOL(mipv6_rr_mn_cookie_create);