Added not-yet used sa_payload parameters used in IKEv1
[strongswan.git] / src / conftest / hooks / pretend_auth.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
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 "hook.h"
17
18 #include <sa/keymat_v2.h>
19 #include <encoding/payloads/nonce_payload.h>
20 #include <encoding/payloads/cert_payload.h>
21 #include <encoding/payloads/auth_payload.h>
22 #include <encoding/payloads/id_payload.h>
23 #include <encoding/payloads/sa_payload.h>
24 #include <encoding/payloads/ts_payload.h>
25
26 typedef struct private_pretend_auth_t private_pretend_auth_t;
27
28 /**
29 * Private data of an pretend_auth_t object.
30 */
31 struct private_pretend_auth_t {
32
33 /**
34 * Implements the hook_t interface.
35 */
36 hook_t hook;
37
38 /**
39 * remote peer identity
40 */
41 identification_t *id;
42
43 /**
44 * reserved bytes of ID payload
45 */
46 char reserved[3];
47
48 /**
49 * IKE_SA_INIT data for signature
50 */
51 chunk_t ike_init;
52
53 /**
54 * Nonce for signature
55 */
56 chunk_t nonce;
57
58 /**
59 * Selected CHILD_SA proposal
60 */
61 proposal_t *proposal;
62
63 /**
64 * List of initiators Traffic Selectors
65 */
66 linked_list_t *tsi;
67
68 /**
69 * List of responders Traffic Selectors
70 */
71 linked_list_t *tsr;
72 };
73
74 /**
75 * Process IKE_SA_INIT request message, outgoing
76 */
77 static void process_init_request(private_pretend_auth_t *this,
78 ike_sa_t *ike_sa, message_t *message)
79 {
80 nonce_payload_t *nonce;
81
82 nonce = (nonce_payload_t*)message->get_payload(message, NONCE);
83 if (nonce)
84 {
85 free(this->nonce.ptr);
86 this->nonce = nonce->get_nonce(nonce);
87 }
88 }
89
90 /**
91 * Process IKE_AUTH request message, outgoing
92 */
93 static void process_auth_request(private_pretend_auth_t *this,
94 ike_sa_t *ike_sa, message_t *message)
95 {
96 id_payload_t *id;
97 sa_payload_t *sa;
98 ts_payload_t *tsi, *tsr;
99 linked_list_t *proposals;
100
101 id = (id_payload_t*)message->get_payload(message, ID_RESPONDER);
102 if (id)
103 {
104 this->id->destroy(this->id);
105 this->id = id->get_identification(id);
106 }
107 sa = (sa_payload_t*)message->get_payload(message, SECURITY_ASSOCIATION);
108 if (sa)
109 {
110 proposals = sa->get_proposals(sa);
111 proposals->remove_first(proposals, (void**)&this->proposal);
112 if (this->proposal)
113 {
114 this->proposal->set_spi(this->proposal, htonl(0x12345678));
115 }
116 proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
117 }
118 tsi = (ts_payload_t*)message->get_payload(message,
119 TRAFFIC_SELECTOR_INITIATOR);
120 if (tsi)
121 {
122 this->tsi = tsi->get_traffic_selectors(tsi);
123 }
124 tsr = (ts_payload_t*)message->get_payload(message,
125 TRAFFIC_SELECTOR_RESPONDER);
126 if (tsr)
127 {
128 this->tsr = tsr->get_traffic_selectors(tsr);
129 }
130
131 }
132
133 /**
134 * Process IKE_SA_INIT response message, incoming
135 */
136 static void process_init_response(private_pretend_auth_t *this,
137 ike_sa_t *ike_sa, message_t *message)
138 {
139 this->ike_init = chunk_clone(message->get_packet_data(message));
140 }
141
142 /**
143 * Build CERT payloads
144 */
145 static void build_certs(private_pretend_auth_t *this,
146 ike_sa_t *ike_sa, message_t *message, auth_cfg_t *auth)
147 {
148 enumerator_t *enumerator;
149 cert_payload_t *payload;
150 certificate_t *cert;
151 auth_rule_t type;
152
153 /* get subject cert first, then issuing certificates */
154 cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
155 if (cert)
156 {
157 payload = cert_payload_create_from_cert(cert, CERTIFICATE);
158 if (payload)
159 {
160 DBG1(DBG_IKE, "pretending end entity cert \"%Y\"",
161 cert->get_subject(cert));
162 message->add_payload(message, (payload_t*)payload);
163 }
164 }
165 enumerator = auth->create_enumerator(auth);
166 while (enumerator->enumerate(enumerator, &type, &cert))
167 {
168 if (type == AUTH_RULE_IM_CERT)
169 {
170 payload = cert_payload_create_from_cert(cert, CERTIFICATE);
171 if (payload)
172 {
173 DBG1(DBG_IKE, "pretending issuer cert \"%Y\"",
174 cert->get_subject(cert));
175 message->add_payload(message, (payload_t*)payload);
176 }
177 }
178 }
179 enumerator->destroy(enumerator);
180 }
181
182 /**
183 * Build faked AUTH payload
184 */
185 static bool build_auth(private_pretend_auth_t *this,
186 ike_sa_t *ike_sa, message_t *message)
187 {
188 chunk_t octets, auth_data;
189 private_key_t *private;
190 auth_cfg_t *auth;
191 auth_payload_t *auth_payload;
192 auth_method_t auth_method;
193 signature_scheme_t scheme;
194 keymat_v2_t *keymat;
195
196 auth = auth_cfg_create();
197 private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, this->id, auth);
198 build_certs(this, ike_sa, message, auth);
199 auth->destroy(auth);
200 if (private == NULL)
201 {
202 DBG1(DBG_CFG, "no private key found for '%Y' to pretend AUTH", this->id);
203 return FALSE;
204 }
205
206 switch (private->get_type(private))
207 {
208 case KEY_RSA:
209 scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
210 auth_method = AUTH_RSA;
211 break;
212 case KEY_ECDSA:
213 /* we try to deduct the signature scheme from the keysize */
214 switch (private->get_keysize(private))
215 {
216 case 256:
217 scheme = SIGN_ECDSA_256;
218 auth_method = AUTH_ECDSA_256;
219 break;
220 case 384:
221 scheme = SIGN_ECDSA_384;
222 auth_method = AUTH_ECDSA_384;
223 break;
224 case 521:
225 scheme = SIGN_ECDSA_521;
226 auth_method = AUTH_ECDSA_521;
227 break;
228 default:
229 DBG1(DBG_CFG, "%d bit ECDSA private key size not supported",
230 private->get_keysize(private));
231 return FALSE;
232 }
233 break;
234 default:
235 DBG1(DBG_CFG, "private key of type %N not supported",
236 key_type_names, private->get_type(private));
237 return FALSE;
238 }
239 keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
240 octets = keymat->get_auth_octets(keymat, TRUE, this->ike_init,
241 this->nonce, this->id, this->reserved);
242 if (!private->sign(private, scheme, octets, &auth_data))
243 {
244 chunk_free(&octets);
245 private->destroy(private);
246 return FALSE;
247 }
248 auth_payload = auth_payload_create();
249 auth_payload->set_auth_method(auth_payload, auth_method);
250 auth_payload->set_data(auth_payload, auth_data);
251 chunk_free(&auth_data);
252 chunk_free(&octets);
253 private->destroy(private);
254 message->add_payload(message, (payload_t*)auth_payload);
255 DBG1(DBG_CFG, "pretending AUTH payload for '%Y' with %N",
256 this->id, auth_method_names, auth_method);
257 return TRUE;
258 }
259
260 /**
261 * Process IKE_AUTH response message, incoming
262 */
263 static void process_auth_response(private_pretend_auth_t *this,
264 ike_sa_t *ike_sa, message_t *message)
265 {
266 enumerator_t *enumerator;
267 payload_t *payload;
268
269 /* check for, and remove AUTHENTICATION_FAILED notify */
270 enumerator = message->create_payload_enumerator(message);
271 while (enumerator->enumerate(enumerator, &payload))
272 {
273 notify_payload_t *notify = (notify_payload_t*)payload;
274
275 if (payload->get_type(payload) != NOTIFY ||
276 notify->get_notify_type(notify) != AUTHENTICATION_FAILED)
277 {
278 DBG1(DBG_CFG, "no %N notify found, disabling AUTH pretending",
279 notify_type_names, AUTHENTICATION_FAILED);
280 enumerator->destroy(enumerator);
281 return;
282 }
283 message->remove_payload_at(message, enumerator);
284 payload->destroy(payload);
285 }
286 enumerator->destroy(enumerator);
287
288 if (!build_auth(this, ike_sa, message))
289 {
290 message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
291 return;
292 }
293 message->add_payload(message, (payload_t*)
294 id_payload_create_from_identification(ID_RESPONDER, this->id));
295 if (this->proposal)
296 {
297 message->add_payload(message, (payload_t*)
298 sa_payload_create_from_proposal_v2(this->proposal));
299 }
300 if (this->tsi)
301 {
302 message->add_payload(message, (payload_t*)
303 ts_payload_create_from_traffic_selectors(TRUE, this->tsi));
304 }
305 if (this->tsr)
306 {
307 message->add_payload(message, (payload_t*)
308 ts_payload_create_from_traffic_selectors(FALSE, this->tsr));
309 }
310 }
311
312 METHOD(listener_t, message, bool,
313 private_pretend_auth_t *this, ike_sa_t *ike_sa, message_t *message,
314 bool incoming)
315 {
316 if (incoming)
317 {
318 if (!message->get_request(message))
319 {
320 if (message->get_exchange_type(message) == IKE_SA_INIT)
321 {
322 process_init_response(this, ike_sa, message);
323 }
324 if (message->get_exchange_type(message) == IKE_AUTH &&
325 message->get_message_id(message) == 1)
326 {
327 process_auth_response(this, ike_sa, message);
328 }
329 }
330 }
331 else
332 {
333 if (message->get_request(message))
334 {
335 if (message->get_exchange_type(message) == IKE_SA_INIT)
336 {
337 process_init_request(this, ike_sa, message);
338 }
339 if (message->get_exchange_type(message) == IKE_AUTH &&
340 message->get_message_id(message) == 1)
341 {
342 process_auth_request(this, ike_sa, message);
343 }
344 }
345 }
346 return TRUE;
347 }
348
349 METHOD(hook_t, destroy, void,
350 private_pretend_auth_t *this)
351 {
352 if (this->tsi)
353 {
354 this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
355 }
356 if (this->tsr)
357 {
358 this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
359 }
360 DESTROY_IF(this->proposal);
361 this->id->destroy(this->id);
362 free(this->ike_init.ptr);
363 free(this->nonce.ptr);
364 free(this);
365 }
366
367 /**
368 * Create the IKE_AUTH fill hook
369 */
370 hook_t *pretend_auth_hook_create(char *name)
371 {
372 private_pretend_auth_t *this;
373
374 INIT(this,
375 .hook = {
376 .listener = {
377 .message = _message,
378 },
379 .destroy = _destroy,
380 },
381 .id = identification_create_from_string(
382 conftest->test->get_str(conftest->test,
383 "hooks.%s.peer", "%any", name)),
384 );
385
386 return &this->hook;
387 }