3e6ec4a228abc271d4f636e768f6ac9e30edebff
[linux-flexiantxendom0-3.2.10.git] / net / ipv6 / mobile_ip6 / rr_crypto.c
1 /*
2  *      rr_cookie.c - Mobile IPv6 return routability crypto  
3  *      Author :  Henrik Petander <henrik.petander@hut.fi>
4  * 
5  *      $Id: s.rr_crypto.c 1.20 03/04/10 13:02:40+03:00 anttit@jon.mipl.mediapoli.com $
6  *
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.
11  *
12  *
13  *
14  */
15
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>
25
26 #include <net/ipv6.h>
27
28 #include "debug.h"
29 #include "hmac.h"
30 #include "rr_crypto.h"
31
32 #define DBG_RR 5
33
34 u8 k_CN[HMAC_SHA1_KEY_SIZE]; // secret key of CN 
35
36 u16 curr_index = 0;
37
38 struct nonce_timestamp nonce_table[MAX_NONCES];
39 spinlock_t nonce_lock = SPIN_LOCK_UNLOCKED;
40 void update_nonces(void);
41
42 /** nonce_is_fresh - whether the nonce was generated recently
43  *  
44  * @non_ts : table entry containing the nonce and a timestamp
45  * @interval : if nonce was generated within interval seconds it is fresh
46  *
47  * Returns 1 if the nonce is fresh, 0 otherwise.
48  */
49 static int nonce_is_fresh(struct nonce_timestamp *non_ts, unsigned long interval)
50 {
51         if (time_before(jiffies, non_ts->timestamp + interval * HZ))
52                 return 1;
53         return 0;
54 }
55
56 /* Returns a pointer to a new nonce  */
57 struct mipv6_rr_nonce * mipv6_rr_get_new_nonce(void)
58 {
59         struct mipv6_rr_nonce *nce = kmalloc(sizeof(*nce), GFP_ATOMIC);
60
61         if (!nce)
62                 return NULL;
63         // Lock nonces here
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
68                 curr_index++;
69                 // Wrap around
70                 if (curr_index == MAX_NONCES)
71                         curr_index = 0;
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;
77         }
78         spin_unlock_bh(&nonce_lock);
79         memcpy(nce, &nonce_table[curr_index].nonce, sizeof(*nce));
80         // Unlock nonces
81         return nce;
82 }
83 /** mipv6_rr_nonce_get_by_index - returns a nonce for index 
84  * @nonce_ind : index of the nonce
85  *
86  * Returns a nonce or NULL if the nonce index was invalid or the nonce 
87  * for the index was not fresh.
88  */
89 struct mipv6_rr_nonce * mipv6_rr_nonce_get_by_index(u16 nonce_ind)
90 {
91         struct mipv6_rr_nonce *nce = NULL;
92         
93         spin_lock_bh(&nonce_lock);
94         if (nonce_ind >= MAX_NONCES) {
95                 DEBUG(DBG_WARNING, "Nonce index field from BU invalid");
96
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
100                  */
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));
104         }
105         spin_unlock_bh(&nonce_lock);
106
107         return nce;
108 }
109
110 /* Fills rr test init cookies with random bytes */  
111 void mipv6_rr_mn_cookie_create(u8 *cookie)
112 {
113         get_random_bytes(cookie, MIPV6_RR_COOKIE_LENGTH);
114 }
115
116 /** mipv6_rr_cookie_create - builds a home or care-of cookie
117  * 
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
121  *
122  */
123 int mipv6_rr_cookie_create(struct in6_addr *addr, u8 **ckie,
124                 u16 nonce_index)
125 {
126         struct ah_processing ah_proc;
127         u8 digest[HMAC_SHA1_HASH_LEN];
128         struct mipv6_rr_nonce *nce;
129
130         if ((nce = mipv6_rr_nonce_get_by_index(nonce_index))== NULL)
131                 return -1;
132
133         if (*ckie == NULL && (*ckie = kmalloc(MIPV6_RR_COOKIE_LENGTH,
134                                         GFP_ATOMIC)) == NULL) {
135                 kfree(nce);
136                 return -1;
137         }
138         /* Calculate the full hmac-sha1 digest from address and nonce using the secret key of cn */
139         
140         if (ah_hmac_sha1_init(&ah_proc, k_CN, HMAC_SHA1_KEY_SIZE) < 0) {
141                 DEBUG(DBG_ERROR, "Hmac sha1 initialization failed");
142                 kfree(nce);
143                 return -1;
144         }
145
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);
149
150         
151         /* clean up nonce */
152         kfree(nce);
153
154         /* Copy first 64 bits of hash target to the cookie */ 
155         memcpy(*ckie, digest, MIPV6_RR_COOKIE_LENGTH);
156         return 0;
157 }
158
159 /** mipv6_rr_key_calc - creates BU authentication key
160  * 
161  * @hoc : Home Cookie 
162  * @coc : Care-of Cookie 
163  * 
164  * Returns BU authentication key of length HMAC_SHA1_KEY_SIZE  or NULL in error cases, 
165  * caller needs to free the key.
166  */
167 u8 *mipv6_rr_key_calc(u8 *hoc, u8 *coc)
168 {
169         
170         u8 *key_bu = kmalloc(HMAC_SHA1_KEY_SIZE, GFP_ATOMIC);
171         SHA1_CTX c;
172
173         if (!key_bu) {
174                 DEBUG(DBG_CRITICAL, "Memory allocation failed, could nort create BU authentication key");
175                 return NULL;
176         }
177
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
181          */
182         sha1_init(&c);
183         sha1_compute(&c, hoc, MIPV6_RR_COOKIE_LENGTH);
184         if (coc)
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);
189         if (coc)        
190                 debug_print_buffer(DBG_RR, coc,  MIPV6_RR_COOKIE_LENGTH);
191
192         return key_bu;
193 }
194
195 void mipv6_rr_init(void)
196 {
197         get_random_bytes(k_CN, HMAC_SHA1_KEY_SIZE);
198         memset(nonce_table, 0, MAX_NONCES * sizeof(struct nonce_timestamp));
199 }
200
201 #ifdef TEST_MIPV6_RR_CRYPTO
202 void mipv6_test_rr(void)
203 {
204         struct mipv6_rr_nonce *nonce;
205         struct in6_addr a1, a2;
206         int ind1, ind2;
207         u8 *ckie1 = NULL, *ckie2 = NULL;
208         u8 *key_mn = NULL, *key_cn = NULL;
209         mipv6_init_rr();
210
211         nonce = mipv6_rr_get_new_nonce();
212         if (!nonce) {
213                 printk("mipv6_rr_get_new_nonce() failed, at 1! \n");
214                 return;
215         }
216         mipv6_rr_cookie_create(&a1, &ckie1, nonce->index);
217         ind1 = nonce->index;
218         kfree(nonce);
219
220         nonce = mipv6_rr_get_new_nonce();
221         if (!nonce) {
222                 printk("mipv6_rr_get_new_nonce() failed, at 2! \n");
223                 return;
224         }
225
226         mipv6_rr_cookie_create(&a2, &ckie2, nonce->index); 
227         ind2 = nonce->index;
228         key_mn =  mipv6_rr_key_calc(ckie1, ckie2);
229
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");
236                 return;
237         }
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");
240         else
241                 printk("mipv6_rr_crypto test OK\n");
242         kfree(nonce);
243         kfree(key_cn);
244         kfree(key_mn);
245 }
246 #endif
247 EXPORT_SYMBOL(mipv6_rr_key_calc);
248 EXPORT_SYMBOL(mipv6_rr_mn_cookie_create);