Added a simple AEAD wrapper for IKEv1 encryption/decryption.
[strongswan.git] / src / libcharon / sa / keymat_v1.c
1 /*
2 * Copyright (C) 2011 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "keymat_v1.h"
17
18 #include <daemon.h>
19
20 typedef struct private_keymat_v1_t private_keymat_v1_t;
21
22 /**
23 * Private data of an keymat_t object.
24 */
25 struct private_keymat_v1_t {
26
27 /**
28 * Public keymat_v1_t interface.
29 */
30 keymat_v1_t public;
31
32 /**
33 * IKE_SA Role, initiator or responder
34 */
35 bool initiator;
36
37 /**
38 * General purpose PRF
39 */
40 prf_t *prf;
41
42 /**
43 * Negotiated PRF algorithm
44 */
45 pseudo_random_function_t prf_alg;
46
47 /**
48 * Crypter wrapped in an aead_t interface
49 */
50 aead_t *aead;
51
52 /**
53 * Key used for authentication during main mode
54 */
55 chunk_t skeyid;
56
57 /**
58 * Key to derive key material from for non-ISAKMP SAs, rekeying
59 */
60 chunk_t skeyid_d;
61
62 /**
63 * Key used for authentication after main mode
64 */
65 chunk_t skeyid_a;
66 };
67
68 /**
69 * Constants used in key derivation.
70 */
71 static const chunk_t octet_0 = chunk_from_chars(0x00);
72 static const chunk_t octet_1 = chunk_from_chars(0x01);
73 static const chunk_t octet_2 = chunk_from_chars(0x02);
74
75 /**
76 * Simple aead_t implementation without support for authentication.
77 */
78 typedef struct {
79 /** implements aead_t interface */
80 aead_t aead;
81 /** crypter to be used */
82 crypter_t *crypter;
83 } private_aead_t;
84
85
86 METHOD(aead_t, encrypt, void,
87 private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
88 chunk_t *encrypted)
89 {
90 this->crypter->encrypt(this->crypter, plain, iv, encrypted);
91 }
92
93 METHOD(aead_t, decrypt, bool,
94 private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
95 chunk_t *plain)
96 {
97 this->crypter->decrypt(this->crypter, encrypted, iv, plain);
98 return TRUE;
99 }
100
101 METHOD(aead_t, get_block_size, size_t,
102 private_aead_t *this)
103 {
104 return this->crypter->get_block_size(this->crypter);
105 }
106
107 METHOD(aead_t, get_icv_size, size_t,
108 private_aead_t *this)
109 {
110 return 0;
111 }
112
113 METHOD(aead_t, get_iv_size, size_t,
114 private_aead_t *this)
115 {
116 /* in order to create the messages properly we return 0 here */
117 return 0;
118 }
119
120 METHOD(aead_t, get_key_size, size_t,
121 private_aead_t *this)
122 {
123 return this->crypter->get_key_size(this->crypter);
124 }
125
126 METHOD(aead_t, set_key, void,
127 private_aead_t *this, chunk_t key)
128 {
129 this->crypter->set_key(this->crypter, key);
130 }
131
132 METHOD(aead_t, aead_destroy, void,
133 private_aead_t *this)
134 {
135 this->crypter->destroy(this->crypter);
136 free(this);
137 }
138
139 /**
140 * Expand SKEYID_e according to Appendix B in RFC 2409.
141 * TODO-IKEv1: verify keys (e.g. for weak keys, see Appendix B)
142 */
143 static chunk_t expand_skeyid_e(chunk_t skeyid_e, size_t key_size, prf_t *prf)
144 {
145 size_t block_size;
146 chunk_t seed, ka;
147 int i;
148
149 if (skeyid_e.len >= key_size)
150 { /* no expansion required, reduce to key_size */
151 skeyid_e.len = key_size;
152 return skeyid_e;
153 }
154 block_size = prf->get_block_size(prf);
155 ka = chunk_alloc((key_size / block_size + 1) * block_size);
156 ka.len = key_size;
157
158 /* Ka = K1 | K2 | ..., K1 = prf(SKEYID_e, 0), K2 = prf(SKEYID_e, K1) ... */
159 prf->set_key(prf, skeyid_e);
160 seed = octet_0;
161 for (i = 0; i < key_size; i += block_size)
162 {
163 prf->get_bytes(prf, seed, ka.ptr + i);
164 seed = chunk_create(ka.ptr + i, block_size);
165 }
166 chunk_clear(&skeyid_e);
167 return ka;
168 }
169
170 /**
171 * Create a simple implementation of the aead_t interface which only encrypts
172 * or decrypts data.
173 */
174 static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e)
175 {
176 private_aead_t *this;
177 u_int16_t alg, key_size;
178 crypter_t *crypter;
179 chunk_t ka;
180
181 if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg,
182 &key_size))
183 {
184 DBG1(DBG_IKE, "no %N selected",
185 transform_type_names, ENCRYPTION_ALGORITHM);
186 return NULL;
187 }
188 crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
189 if (!crypter)
190 {
191 DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
192 transform_type_names, ENCRYPTION_ALGORITHM,
193 encryption_algorithm_names, alg, key_size);
194 return NULL;
195 }
196 key_size = crypter->get_key_size(crypter);
197 ka = expand_skeyid_e(skeyid_e, crypter->get_key_size(crypter), prf);
198 DBG4(DBG_IKE, "encryption key Ka %B", &ka);
199 crypter->set_key(crypter, ka);
200 chunk_clear(&ka);
201
202 INIT(this,
203 .aead = {
204 .encrypt = _encrypt,
205 .decrypt = _decrypt,
206 .get_block_size = _get_block_size,
207 .get_icv_size = _get_icv_size,
208 .get_iv_size = _get_iv_size,
209 .get_key_size = _get_key_size,
210 .set_key = _set_key,
211 .destroy = _aead_destroy,
212 },
213 .crypter = crypter,
214 );
215 return &this->aead;
216 }
217
218 /**
219 * Converts integrity algorithm to PRF algorithm
220 */
221 static u_int16_t auth_to_prf(u_int16_t alg)
222 {
223 switch (alg)
224 {
225 case AUTH_HMAC_SHA1_96:
226 return PRF_HMAC_SHA1;
227 case AUTH_HMAC_SHA2_256_128:
228 return PRF_HMAC_SHA2_256;
229 case AUTH_HMAC_SHA2_384_192:
230 return PRF_HMAC_SHA2_384;
231 case AUTH_HMAC_SHA2_512_256:
232 return PRF_HMAC_SHA2_512;
233 case AUTH_HMAC_MD5_96:
234 return PRF_HMAC_MD5;
235 case AUTH_AES_XCBC_96:
236 return PRF_AES128_XCBC;
237 default:
238 return PRF_UNDEFINED;
239 }
240 }
241
242 /**
243 * Adjust the key length for PRF algorithms that expect a fixed key length.
244 */
245 static void adjust_keylen(u_int16_t alg, chunk_t *key)
246 {
247 switch (alg)
248 {
249 case PRF_AES128_XCBC:
250 /* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does
251 * not and therefore fixed key semantics apply to XCBC for key
252 * derivation. */
253 key->len = min(key->len, 16);
254 break;
255 default:
256 /* all other algorithms use variable key length */
257 break;
258 }
259 }
260
261 METHOD(keymat_v1_t, derive_ike_keys, bool,
262 private_keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh,
263 chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id,
264 auth_class_t auth, shared_key_t *shared_key)
265 {
266 chunk_t g_xy, g_xi, g_xr, dh_me, spi_i, spi_r, nonces, data, skeyid_e;
267 u_int16_t alg;
268
269 spi_i = chunk_alloca(sizeof(u_int64_t));
270 spi_r = chunk_alloca(sizeof(u_int64_t));
271
272 if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
273 { /* no PRF negotiated, use HMAC version of integrity algorithm instead */
274 if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL)
275 || (alg = auth_to_prf(alg)) == PRF_UNDEFINED)
276 {
277 DBG1(DBG_IKE, "no %N selected",
278 transform_type_names, PSEUDO_RANDOM_FUNCTION);
279 return FALSE;
280 }
281 }
282 this->prf_alg = alg;
283 this->prf = lib->crypto->create_prf(lib->crypto, alg);
284 if (!this->prf)
285 {
286 DBG1(DBG_IKE, "%N %N not supported!",
287 transform_type_names, PSEUDO_RANDOM_FUNCTION,
288 pseudo_random_function_names, alg);
289 return FALSE;
290 }
291 if (this->prf->get_block_size(this->prf) <
292 this->prf->get_key_size(this->prf))
293 { /* TODO-IKEv1: support PRF output expansion (RFC 2409, Appendix B) */
294 DBG1(DBG_IKE, "expansion of %N %N output not supported!",
295 transform_type_names, PSEUDO_RANDOM_FUNCTION,
296 pseudo_random_function_names, alg);
297 return FALSE;
298 }
299
300 if (dh->get_shared_secret(dh, &g_xy) != SUCCESS)
301 {
302 return FALSE;
303 }
304 DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &g_xy);
305
306 *((u_int64_t*)spi_i.ptr) = id->get_initiator_spi(id);
307 *((u_int64_t*)spi_r.ptr) = id->get_responder_spi(id);
308 nonces = chunk_cata("cc", nonce_i, nonce_r);
309
310 switch (auth)
311 {
312 case AUTH_CLASS_PSK:
313 { /* SKEYID = prf(pre-shared-key, Ni_b | Nr_b) */
314 chunk_t psk;
315 if (!shared_key)
316 {
317 chunk_clear(&g_xy);
318 return FALSE;
319 }
320 psk = shared_key->get_key(shared_key);
321 adjust_keylen(alg, &psk);
322 this->prf->set_key(this->prf, psk);
323 this->prf->allocate_bytes(this->prf, nonces, &this->skeyid);
324 break;
325 }
326 case AUTH_CLASS_PUBKEY:
327 {
328 /* signatures : SKEYID = prf(Ni_b | Nr_b, g^xy)
329 * pubkey encr: SKEYID = prf(hash(Ni_b | Nr_b), CKY-I | CKY-R) */
330 /* TODO-IKEv1: implement key derivation for other schemes,
331 * fall for now */
332 }
333 default:
334 /* authentication class not supported */
335 chunk_clear(&g_xy);
336 return FALSE;
337 }
338 adjust_keylen(alg, &this->skeyid);
339 DBG4(DBG_IKE, "SKEYID %B", &this->skeyid);
340
341 /* SKEYID_d = prf(SKEYID, g^xy | CKY-I | CKY-R | 0) */
342 data = chunk_cat("cccc", g_xy, spi_i, spi_r, octet_0);
343 this->prf->set_key(this->prf, this->skeyid);
344 this->prf->allocate_bytes(this->prf, data, &this->skeyid_d);
345 chunk_clear(&data);
346 DBG4(DBG_IKE, "SKEYID_d %B", &this->skeyid_d);
347
348 /* SKEYID_a = prf(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1) */
349 data = chunk_cat("ccccc", this->skeyid_d, g_xy, spi_i, spi_r, octet_1);
350 this->prf->set_key(this->prf, this->skeyid);
351 this->prf->allocate_bytes(this->prf, data, &this->skeyid_a);
352 chunk_clear(&data);
353 DBG4(DBG_IKE, "SKEYID_a %B", &this->skeyid_a);
354
355 /* SKEYID_e = prf(SKEYID, SKEYID_a | g^xy | CKY-I | CKY-R | 2) */
356 data = chunk_cat("ccccc", this->skeyid_a, g_xy, spi_i, spi_r, octet_2);
357 this->prf->set_key(this->prf, this->skeyid);
358 this->prf->allocate_bytes(this->prf, data, &skeyid_e);
359 chunk_clear(&data);
360 DBG4(DBG_IKE, "SKEYID_e %B", &skeyid_e);
361
362 chunk_clear(&g_xy);
363
364 this->aead = create_aead(proposal, this->prf, skeyid_e);
365 if (!this->aead)
366 {
367 return FALSE;
368 }
369
370 return TRUE;
371 }
372
373 METHOD(keymat_t, create_dh, diffie_hellman_t*,
374 private_keymat_v1_t *this, diffie_hellman_group_t group)
375 {
376 return lib->crypto->create_dh(lib->crypto, group);
377 }
378
379 METHOD(keymat_t, get_aead, aead_t*,
380 private_keymat_v1_t *this, bool in)
381 {
382 return this->aead;
383 }
384
385 METHOD(keymat_t, destroy, void,
386 private_keymat_v1_t *this)
387 {
388 DESTROY_IF(this->prf);
389 DESTROY_IF(this->aead);
390 chunk_clear(&this->skeyid);
391 chunk_clear(&this->skeyid_d);
392 chunk_clear(&this->skeyid_a);
393 free(this);
394 }
395
396 /**
397 * See header
398 */
399 keymat_v1_t *keymat_v1_create(bool initiator)
400 {
401 private_keymat_v1_t *this;
402
403 INIT(this,
404 .public = {
405 .keymat = {
406 .create_dh = _create_dh,
407 .get_aead = _get_aead,
408 .destroy = _destroy,
409 },
410 .derive_ike_keys = _derive_ike_keys,
411 },
412 .initiator = initiator,
413 .prf_alg = PRF_UNDEFINED,
414 );
415
416 return &this->public;
417 }