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