Removed len argument from proposal_get_token()
[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/ikev2/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(CERTIFICATE, cert);
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(CERTIFICATE, cert);
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 if (!keymat->get_auth_octets(keymat, TRUE, this->ike_init,
241 this->nonce, this->id, this->reserved, &octets))
242 {
243 private->destroy(private);
244 return FALSE;
245 }
246 if (!private->sign(private, scheme, octets, &auth_data))
247 {
248 chunk_free(&octets);
249 private->destroy(private);
250 return FALSE;
251 }
252 auth_payload = auth_payload_create();
253 auth_payload->set_auth_method(auth_payload, auth_method);
254 auth_payload->set_data(auth_payload, auth_data);
255 chunk_free(&auth_data);
256 chunk_free(&octets);
257 private->destroy(private);
258 message->add_payload(message, (payload_t*)auth_payload);
259 DBG1(DBG_CFG, "pretending AUTH payload for '%Y' with %N",
260 this->id, auth_method_names, auth_method);
261 return TRUE;
262 }
263
264 /**
265 * Process IKE_AUTH response message, incoming
266 */
267 static void process_auth_response(private_pretend_auth_t *this,
268 ike_sa_t *ike_sa, message_t *message)
269 {
270 enumerator_t *enumerator;
271 payload_t *payload;
272
273 /* check for, and remove AUTHENTICATION_FAILED notify */
274 enumerator = message->create_payload_enumerator(message);
275 while (enumerator->enumerate(enumerator, &payload))
276 {
277 notify_payload_t *notify = (notify_payload_t*)payload;
278
279 if (payload->get_type(payload) != NOTIFY ||
280 notify->get_notify_type(notify) != AUTHENTICATION_FAILED)
281 {
282 DBG1(DBG_CFG, "no %N notify found, disabling AUTH pretending",
283 notify_type_names, AUTHENTICATION_FAILED);
284 enumerator->destroy(enumerator);
285 return;
286 }
287 message->remove_payload_at(message, enumerator);
288 payload->destroy(payload);
289 }
290 enumerator->destroy(enumerator);
291
292 if (!build_auth(this, ike_sa, message))
293 {
294 message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
295 return;
296 }
297 message->add_payload(message, (payload_t*)
298 id_payload_create_from_identification(ID_RESPONDER, this->id));
299 if (this->proposal)
300 {
301 message->add_payload(message, (payload_t*)
302 sa_payload_create_from_proposal_v2(this->proposal));
303 }
304 if (this->tsi)
305 {
306 message->add_payload(message, (payload_t*)
307 ts_payload_create_from_traffic_selectors(TRUE, this->tsi));
308 }
309 if (this->tsr)
310 {
311 message->add_payload(message, (payload_t*)
312 ts_payload_create_from_traffic_selectors(FALSE, this->tsr));
313 }
314 }
315
316 METHOD(listener_t, message, bool,
317 private_pretend_auth_t *this, ike_sa_t *ike_sa, message_t *message,
318 bool incoming, bool plain)
319 {
320 if (plain)
321 {
322 if (incoming)
323 {
324 if (!message->get_request(message))
325 {
326 if (message->get_exchange_type(message) == IKE_SA_INIT)
327 {
328 process_init_response(this, ike_sa, message);
329 }
330 if (message->get_exchange_type(message) == IKE_AUTH &&
331 message->get_message_id(message) == 1)
332 {
333 process_auth_response(this, ike_sa, message);
334 }
335 }
336 }
337 else
338 {
339 if (message->get_request(message))
340 {
341 if (message->get_exchange_type(message) == IKE_SA_INIT)
342 {
343 process_init_request(this, ike_sa, message);
344 }
345 if (message->get_exchange_type(message) == IKE_AUTH &&
346 message->get_message_id(message) == 1)
347 {
348 process_auth_request(this, ike_sa, message);
349 }
350 }
351 }
352 }
353 return TRUE;
354 }
355
356 METHOD(hook_t, destroy, void,
357 private_pretend_auth_t *this)
358 {
359 if (this->tsi)
360 {
361 this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
362 }
363 if (this->tsr)
364 {
365 this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
366 }
367 DESTROY_IF(this->proposal);
368 this->id->destroy(this->id);
369 free(this->ike_init.ptr);
370 free(this->nonce.ptr);
371 free(this);
372 }
373
374 /**
375 * Create the IKE_AUTH fill hook
376 */
377 hook_t *pretend_auth_hook_create(char *name)
378 {
379 private_pretend_auth_t *this;
380
381 INIT(this,
382 .hook = {
383 .listener = {
384 .message = _message,
385 },
386 .destroy = _destroy,
387 },
388 .id = identification_create_from_string(
389 conftest->test->get_str(conftest->test,
390 "hooks.%s.peer", "%any", name)),
391 );
392
393 return &this->hook;
394 }