keymat: Create inbound and outbound AEAD transforms
[strongswan.git] / src / charon-tkm / src / tkm / tkm_keymat.c
1 /*
2 * Copyrigth (C) 2012 Reto Buerki
3 * Copyright (C) 2012 Adrian-Ken Rueegsegger
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <daemon.h>
18 #include <sa/ikev2/keymat_v2.h>
19 #include <tkm/constants.h>
20 #include <tkm/client.h>
21
22 #include "tkm.h"
23 #include "tkm_utils.h"
24 #include "tkm_diffie_hellman.h"
25 #include "tkm_keymat.h"
26
27 typedef struct private_tkm_keymat_t private_tkm_keymat_t;
28
29 /**
30 * Private data of a keymat_t object.
31 */
32 struct private_tkm_keymat_t {
33
34 /**
35 * Public tkm_keymat_t interface.
36 */
37 tkm_keymat_t public;
38
39 /**
40 * IKEv2 keymat proxy (will be removed).
41 */
42 keymat_v2_t *proxy;
43
44 /**
45 * IKE_SA Role, initiator or responder.
46 */
47 bool initiator;
48
49 /**
50 * Inbound AEAD.
51 */
52 aead_t *aead_in;
53
54 /**
55 * Outbound AEAD.
56 */
57 aead_t *aead_out;
58
59 };
60
61 METHOD(keymat_t, get_version, ike_version_t,
62 private_tkm_keymat_t *this)
63 {
64 return IKEV2;
65 }
66
67 METHOD(keymat_t, create_dh, diffie_hellman_t*,
68 private_tkm_keymat_t *this, diffie_hellman_group_t group)
69 {
70 return lib->crypto->create_dh(lib->crypto, group);
71 }
72
73 METHOD(keymat_t, create_nonce_gen, nonce_gen_t*,
74 private_tkm_keymat_t *this)
75 {
76 return lib->crypto->create_nonce_gen(lib->crypto);
77 }
78
79 METHOD(tkm_keymat_t, derive_ike_keys, bool,
80 private_tkm_keymat_t *this, proposal_t *proposal, diffie_hellman_t *dh,
81 chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id,
82 pseudo_random_function_t rekey_function, chunk_t rekey_skd)
83 {
84 /* Check encryption and integrity algorithms */
85 u_int16_t enc_alg, int_alg, key_size;
86 if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_alg, &key_size))
87 {
88 DBG1(DBG_IKE, "no %N selected", transform_type_names,
89 ENCRYPTION_ALGORITHM);
90 return FALSE;
91 }
92 if (encryption_algorithm_is_aead(enc_alg))
93 {
94 DBG1(DBG_IKE, "AEAD algorithm %N not supported",
95 encryption_algorithm_names, enc_alg);
96 return FALSE;
97 }
98 if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_alg, NULL))
99 {
100 DBG1(DBG_IKE, "no %N selected", transform_type_names,
101 INTEGRITY_ALGORITHM);
102 return FALSE;
103 }
104 DBG2(DBG_IKE, "using %N for encryption, %N for integrity",
105 encryption_algorithm_names, enc_alg,
106 integrity_algorithm_names, int_alg);
107
108 /* Acquire nonce context id */
109 chunk_t * const nonce = this->initiator ? &nonce_i : &nonce_r;
110 const uint64_t nc_id = tkm->chunk_map->get_id(tkm->chunk_map, nonce);
111 if (!nc_id)
112 {
113 DBG1(DBG_IKE, "unable to acquire context id for nonce");
114 return FALSE;
115 }
116
117 /* Get DH context id */
118 tkm_diffie_hellman_t * const tkm_dh = (tkm_diffie_hellman_t *)dh;
119 const dh_id_type dh_id = tkm_dh->get_id(tkm_dh);
120
121 nonce_type nonce_rem;
122 u_int64_t spi_loc, spi_rem;
123
124 if (this->initiator)
125 {
126 chunk_to_sequence(&nonce_r, &nonce_rem);
127 spi_loc = id->get_initiator_spi(id);
128 spi_rem = id->get_responder_spi(id);
129 }
130 else
131 {
132 chunk_to_sequence(&nonce_i, &nonce_rem);
133 spi_loc = id->get_responder_spi(id);
134 spi_rem = id->get_initiator_spi(id);
135 }
136
137 key_type sk_ai, sk_ar, sk_ei, sk_er;
138 DBG1(DBG_IKE, "deriving IKE keys (nc: %llu, dh: %llu, spi_loc: %llx, "
139 "spi_rem: %llx)", nc_id, dh_id, spi_loc, spi_rem);
140 /* Fake some data for now */
141 if (ike_isa_create(1, 1, 1, dh_id, nc_id, nonce_rem, 1, spi_loc, spi_rem,
142 &sk_ai, &sk_ar, &sk_ei, &sk_er) != TKM_OK)
143 {
144 DBG1(DBG_IKE, "key derivation failed");
145 return FALSE;
146 }
147
148 /* Initialize AEAD with crypters and signers */
149 signer_t * const signer_i = lib->crypto->create_signer(lib->crypto, int_alg);
150 signer_t * const signer_r = lib->crypto->create_signer(lib->crypto, int_alg);
151 if (signer_i == NULL || signer_r == NULL)
152 {
153 DBG1(DBG_IKE, "%N %N not supported!",
154 transform_type_names, INTEGRITY_ALGORITHM,
155 integrity_algorithm_names, int_alg);
156 return FALSE;
157 }
158 crypter_t * const crypter_i = lib->crypto->create_crypter(lib->crypto,
159 enc_alg, key_size / 8);
160 crypter_t * const crypter_r = lib->crypto->create_crypter(lib->crypto,
161 enc_alg, key_size / 8);
162 if (crypter_i == NULL || crypter_r == NULL)
163 {
164 signer_i->destroy(signer_i);
165 signer_r->destroy(signer_r);
166 DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
167 transform_type_names, ENCRYPTION_ALGORITHM,
168 encryption_algorithm_names, enc_alg, key_size);
169 return FALSE;
170 }
171
172 chunk_t key;
173 sequence_to_chunk(sk_ai.data, sk_ai.size, &key);
174 DBG4(DBG_IKE, "Sk_ai %B", &key);
175 if (!signer_i->set_key(signer_i, key))
176 {
177 return FALSE;
178 }
179 chunk_clear(&key);
180
181 sequence_to_chunk(sk_ar.data, sk_ar.size, &key);
182 DBG4(DBG_IKE, "Sk_ar %B", &key);
183 if (!signer_r->set_key(signer_r, key))
184 {
185 return FALSE;
186 }
187 chunk_clear(&key);
188
189 sequence_to_chunk(sk_ei.data, sk_ei.size, &key);
190 DBG4(DBG_IKE, "Sk_ei %B", &key);
191 if (!crypter_i->set_key(crypter_i, key))
192 {
193 return FALSE;
194 }
195 chunk_clear(&key);
196
197 sequence_to_chunk(sk_er.data, sk_er.size, &key);
198 DBG4(DBG_IKE, "Sk_er %B", &key);
199 if (!crypter_r->set_key(crypter_r, key))
200 {
201 return FALSE;
202 }
203 chunk_clear(&key);
204
205 if (this->initiator)
206 {
207 this->aead_in = aead_create(crypter_r, signer_r);
208 this->aead_out = aead_create(crypter_i, signer_i);
209 }
210 else
211 {
212 this->aead_in = aead_create(crypter_i, signer_i);
213 this->aead_out = aead_create(crypter_r, signer_r);
214 }
215
216 /* TODO: Add failure handler (see keymat_v2.c) */
217
218 if (this->proxy->derive_ike_keys(this->proxy, proposal, dh, nonce_i,
219 nonce_r, id, rekey_function, rekey_skd))
220 {
221 tkm->chunk_map->remove(tkm->chunk_map, nonce);
222 if (ike_nc_reset(nc_id) != TKM_OK)
223 {
224 DBG1(DBG_IKE, "failed to reset nonce context %llu", nc_id);
225 }
226 tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nc_id);
227
228 return TRUE;
229 }
230 return FALSE;
231 }
232
233 METHOD(tkm_keymat_t, derive_child_keys, bool,
234 private_tkm_keymat_t *this, proposal_t *proposal, diffie_hellman_t *dh,
235 chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i,
236 chunk_t *encr_r, chunk_t *integ_r)
237 {
238 DBG1(DBG_CHD, "deriving child keys");
239 return this->proxy->derive_child_keys(this->proxy, proposal, dh, nonce_i,
240 nonce_r, encr_i, integ_i, encr_r, integ_r);
241 }
242
243 METHOD(keymat_t, get_aead, aead_t*,
244 private_tkm_keymat_t *this, bool in)
245 {
246 return in ? this->aead_in : this->aead_out;
247 }
248
249 METHOD(tkm_keymat_t, get_auth_octets, bool,
250 private_tkm_keymat_t *this, bool verify, chunk_t ike_sa_init,
251 chunk_t nonce, identification_t *id, char reserved[3], chunk_t *octets)
252 {
253 DBG1(DBG_IKE, "returning auth octets");
254 return this->proxy->get_auth_octets(this->proxy, verify, ike_sa_init, nonce,
255 id, reserved, octets);
256 }
257
258 METHOD(tkm_keymat_t, get_skd, pseudo_random_function_t,
259 private_tkm_keymat_t *this, chunk_t *skd)
260 {
261 DBG1(DBG_IKE, "returning skd");
262 return this->proxy->get_skd(this->proxy, skd);
263 }
264
265 METHOD(tkm_keymat_t, get_psk_sig, bool,
266 private_tkm_keymat_t *this, bool verify, chunk_t ike_sa_init, chunk_t nonce,
267 chunk_t secret, identification_t *id, char reserved[3], chunk_t *sig)
268 {
269 DBG1(DBG_IKE, "returning PSK signature");
270 return this->proxy->get_psk_sig(this->proxy, verify, ike_sa_init, nonce,
271 secret, id, reserved, sig);
272 }
273
274 METHOD(keymat_t, destroy, void,
275 private_tkm_keymat_t *this)
276 {
277 DESTROY_IF(this->aead_in);
278 DESTROY_IF(this->aead_out);
279 this->proxy->keymat.destroy(&this->proxy->keymat);
280 free(this);
281 }
282
283 /**
284 * See header.
285 */
286 tkm_keymat_t *tkm_keymat_create(bool initiator)
287 {
288 private_tkm_keymat_t *this;
289
290 INIT(this,
291 .public = {
292 .keymat = {
293 .get_version = _get_version,
294 .create_dh = _create_dh,
295 .create_nonce_gen = _create_nonce_gen,
296 .get_aead = _get_aead,
297 .destroy = _destroy,
298 },
299 .derive_ike_keys = _derive_ike_keys,
300 .derive_child_keys = _derive_child_keys,
301 .get_skd = _get_skd,
302 .get_auth_octets = _get_auth_octets,
303 .get_psk_sig = _get_psk_sig,
304 },
305 .initiator = initiator,
306 .proxy = keymat_v2_create(initiator),
307 );
308
309 return &this->public;
310 }