kernel-netlink: Check return value of both halfs when installing default route in...
[strongswan.git] / src / libipsec / esp_context.c
1 /*
2 * Copyright (C) 2012-2013 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * HSR Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include <limits.h>
19 #include <stdint.h>
20
21 #include "esp_context.h"
22
23 #include <library.h>
24 #include <utils/debug.h>
25
26 /**
27 * Should be a multiple of 8
28 */
29 #define ESP_DEFAULT_WINDOW_SIZE 128
30
31 typedef struct private_esp_context_t private_esp_context_t;
32
33 /**
34 * Private additions to esp_context_t.
35 */
36 struct private_esp_context_t {
37
38 /**
39 * Public members
40 */
41 esp_context_t public;
42
43 /**
44 * AEAD wrapper or method to encrypt/decrypt/authenticate ESP packets
45 */
46 aead_t *aead;
47
48 /**
49 * The highest sequence number that was successfully verified
50 * and authenticated, or assigned in an outbound context
51 */
52 uint32_t last_seqno;
53
54 /**
55 * The bit in the window of the highest authenticated sequence number
56 */
57 u_int seqno_index;
58
59 /**
60 * The size of the anti-replay window (in bits)
61 */
62 u_int window_size;
63
64 /**
65 * The anti-replay window buffer
66 */
67 chunk_t window;
68
69 /**
70 * TRUE in case of an inbound ESP context
71 */
72 bool inbound;
73 };
74
75 /**
76 * Set or unset a bit in the window.
77 */
78 static inline void set_window_bit(private_esp_context_t *this,
79 u_int index, bool set)
80 {
81 u_int i = index / CHAR_BIT;
82
83 if (set)
84 {
85 this->window.ptr[i] |= 1 << (index % CHAR_BIT);
86 }
87 else
88 {
89 this->window.ptr[i] &= ~(1 << (index % CHAR_BIT));
90 }
91 }
92
93 /**
94 * Get a bit from the window.
95 */
96 static inline bool get_window_bit(private_esp_context_t *this, u_int index)
97 {
98 u_int i = index / CHAR_BIT;
99
100 return this->window.ptr[i] & (1 << index % CHAR_BIT);
101 }
102
103 /**
104 * Returns TRUE if the supplied seqno is not already marked in the window
105 */
106 static bool check_window(private_esp_context_t *this, uint32_t seqno)
107 {
108 u_int offset;
109
110 offset = this->last_seqno - seqno;
111 offset = (this->seqno_index - offset) % this->window_size;
112 return !get_window_bit(this, offset);
113 }
114
115 METHOD(esp_context_t, verify_seqno, bool,
116 private_esp_context_t *this, uint32_t seqno)
117 {
118 if (!this->inbound)
119 {
120 return FALSE;
121 }
122
123 if (seqno > this->last_seqno)
124 { /* |----------------------------------------|
125 * <---------^ ^ or <---------^ ^
126 * WIN H S WIN H S
127 */
128 return TRUE;
129 }
130 else if (seqno > 0 && this->window_size > this->last_seqno - seqno)
131 { /* |----------------------------------------|
132 * <---------^ or <---------^
133 * WIN ^ H WIN ^ H
134 * S S
135 */
136 return check_window(this, seqno);
137 }
138 else
139 { /* |----------------------------------------|
140 * ^ <---------^
141 * S WIN H
142 */
143 return FALSE;
144 }
145 }
146
147 METHOD(esp_context_t, set_authenticated_seqno, void,
148 private_esp_context_t *this, uint32_t seqno)
149 {
150 u_int i, shift;
151
152 if (!this->inbound)
153 {
154 return;
155 }
156
157 if (seqno > this->last_seqno)
158 { /* shift the window to the new highest authenticated seqno */
159 shift = seqno - this->last_seqno;
160 shift = shift < this->window_size ? shift : this->window_size;
161 for (i = 0; i < shift; ++i)
162 {
163 this->seqno_index = (this->seqno_index + 1) % this->window_size;
164 set_window_bit(this, this->seqno_index, FALSE);
165 }
166 set_window_bit(this, this->seqno_index, TRUE);
167 this->last_seqno = seqno;
168 }
169 else
170 { /* seqno is inside the window, set the corresponding window bit */
171 i = this->last_seqno - seqno;
172 set_window_bit(this, (this->seqno_index - i) % this->window_size, TRUE);
173 }
174 }
175
176 METHOD(esp_context_t, get_seqno, uint32_t,
177 private_esp_context_t *this)
178 {
179 return this->last_seqno;
180 }
181
182 METHOD(esp_context_t, next_seqno, bool,
183 private_esp_context_t *this, uint32_t *seqno)
184 {
185 if (this->inbound || this->last_seqno == UINT32_MAX)
186 { /* inbound or segno would cycle */
187 return FALSE;
188 }
189 *seqno = ++this->last_seqno;
190 return TRUE;
191 }
192
193 METHOD(esp_context_t, get_aead, aead_t*,
194 private_esp_context_t *this)
195 {
196 return this->aead;
197 }
198
199 METHOD(esp_context_t, destroy, void,
200 private_esp_context_t *this)
201 {
202 chunk_free(&this->window);
203 DESTROY_IF(this->aead);
204 free(this);
205 }
206
207 /**
208 * Create an AEAD algorithm
209 */
210 static bool create_aead(private_esp_context_t *this, int alg,
211 chunk_t key)
212 {
213 size_t salt = 0;
214
215 switch (alg)
216 {
217 case ENCR_AES_GCM_ICV8:
218 case ENCR_AES_GCM_ICV12:
219 case ENCR_AES_GCM_ICV16:
220 case ENCR_CHACHA20_POLY1305:
221 salt = 4;
222 break;
223 case ENCR_AES_CCM_ICV8:
224 case ENCR_AES_CCM_ICV12:
225 case ENCR_AES_CCM_ICV16:
226 case ENCR_CAMELLIA_CCM_ICV8:
227 case ENCR_CAMELLIA_CCM_ICV12:
228 case ENCR_CAMELLIA_CCM_ICV16:
229 salt = 3;
230 break;
231 default:
232 break;
233 }
234 if (salt)
235 {
236 this->aead = lib->crypto->create_aead(lib->crypto, alg,
237 key.len - salt, salt);
238 }
239 if (!this->aead)
240 {
241 DBG1(DBG_ESP, "failed to create ESP context: unsupported AEAD "
242 "algorithm %N", encryption_algorithm_names, alg);
243 return FALSE;
244 }
245 if (!this->aead->set_key(this->aead, key))
246 {
247 DBG1(DBG_ESP, "failed to create ESP context: setting AEAD key failed");
248 return FALSE;
249 }
250 return TRUE;
251 }
252
253 /**
254 * Create AEAD wrapper around traditional encryption/integrity algorithms
255 */
256 static bool create_traditional(private_esp_context_t *this, int enc_alg,
257 chunk_t enc_key, int int_alg, chunk_t int_key)
258 {
259 crypter_t *crypter = NULL;
260 signer_t *signer = NULL;
261 iv_gen_t *ivg;
262
263 switch (enc_alg)
264 {
265 case ENCR_AES_CTR:
266 case ENCR_CAMELLIA_CTR:
267 /* the key includes a 4 byte salt */
268 crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
269 enc_key.len - 4);
270 break;
271 default:
272 crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
273 enc_key.len);
274 break;
275 }
276 if (!crypter)
277 {
278 DBG1(DBG_ESP, "failed to create ESP context: unsupported encryption "
279 "algorithm %N", encryption_algorithm_names, enc_alg);
280 goto failed;
281 }
282 if (!crypter->set_key(crypter, enc_key))
283 {
284 DBG1(DBG_ESP, "failed to create ESP context: setting encryption key "
285 "failed");
286 goto failed;
287 }
288
289 signer = lib->crypto->create_signer(lib->crypto, int_alg);
290 if (!signer)
291 {
292 DBG1(DBG_ESP, "failed to create ESP context: unsupported integrity "
293 "algorithm %N", integrity_algorithm_names, int_alg);
294 goto failed;
295 }
296 if (!signer->set_key(signer, int_key))
297 {
298 DBG1(DBG_ESP, "failed to create ESP context: setting signature key "
299 "failed");
300 goto failed;
301 }
302 ivg = iv_gen_create_for_alg(enc_alg);
303 if (!ivg)
304 {
305 DBG1(DBG_ESP, "failed to create ESP context: creating iv gen failed");
306 goto failed;
307 }
308 this->aead = aead_create(crypter, signer, ivg);
309 return TRUE;
310
311 failed:
312 DESTROY_IF(crypter);
313 DESTROY_IF(signer);
314 return FALSE;
315 }
316
317 /**
318 * Described in header.
319 */
320 esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key,
321 int int_alg, chunk_t int_key, bool inbound)
322 {
323 private_esp_context_t *this;
324
325 INIT(this,
326 .public = {
327 .get_aead = _get_aead,
328 .get_seqno = _get_seqno,
329 .next_seqno = _next_seqno,
330 .verify_seqno = _verify_seqno,
331 .set_authenticated_seqno = _set_authenticated_seqno,
332 .destroy = _destroy,
333 },
334 .inbound = inbound,
335 .window_size = ESP_DEFAULT_WINDOW_SIZE,
336 );
337
338 if (encryption_algorithm_is_aead(enc_alg))
339 {
340 if (!create_aead(this, enc_alg, enc_key))
341 {
342 destroy(this);
343 return NULL;
344 }
345 }
346 else
347 {
348 if (!create_traditional(this, enc_alg, enc_key, int_alg, int_key))
349 {
350 destroy(this);
351 return NULL;
352 }
353 }
354
355 if (inbound)
356 {
357 this->window = chunk_alloc(this->window_size / CHAR_BIT + 1);
358 memset(this->window.ptr, 0, this->window.len);
359 }
360 return &this->public;
361 }