Annotation of embedaddon/strongswan/src/libipsec/esp_context.c, revision 1.1.1.1
1.1 misho 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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>