Generate payload to rebuild_auth, works with injected unknown payloads
[strongswan.git] / src / conftest / hooks / rebuild_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 <encoding/generator.h>
19 #include <encoding/payloads/nonce_payload.h>
20 #include <encoding/payloads/auth_payload.h>
21 #include <encoding/payloads/id_payload.h>
22
23 typedef struct private_rebuild_auth_t private_rebuild_auth_t;
24
25 /**
26 * Private data of an rebuild_auth_t object.
27 */
28 struct private_rebuild_auth_t {
29
30 /**
31 * Implements the hook_t interface.
32 */
33 hook_t hook;
34
35 /**
36 * Our IKE_SA_INIT data, required to rebuild AUTH
37 */
38 chunk_t ike_init;
39
40 /**
41 * Received NONCE, required to rebuild AUTH
42 */
43 chunk_t nonce;
44 };
45
46 /**
47 * Rebuild our AUTH data
48 */
49 static bool rebuild_auth(private_rebuild_auth_t *this, ike_sa_t *ike_sa,
50 message_t *message)
51 {
52 enumerator_t *enumerator;
53 chunk_t octets, auth_data;
54 private_key_t *private;
55 auth_cfg_t *auth;
56 payload_t *payload;
57 auth_payload_t *auth_payload;
58 auth_method_t auth_method;
59 signature_scheme_t scheme;
60 keymat_t *keymat;
61 identification_t *id;
62 char reserved[3];
63 generator_t *generator;
64 chunk_t data;
65 u_int32_t *lenpos;
66
67 payload = message->get_payload(message,
68 message->get_request(message) ? ID_INITIATOR : ID_RESPONDER);
69 if (!payload)
70 {
71 DBG1(DBG_CFG, "ID payload not found to rebuild AUTH");
72 return FALSE;
73 }
74
75 generator = generator_create();
76 generator->generate_payload(generator, payload);
77 data = generator->get_chunk(generator, &lenpos);
78 if (data.len < 8)
79 {
80 DBG1(DBG_CFG, "ID payload invalid to rebuild AUTH");
81 generator->destroy(generator);
82 return FALSE;
83 }
84 memcpy(reserved, data.ptr + 5, 3);
85 id = identification_create_from_encoding(data.ptr[4], chunk_skip(data, 8));
86 generator->destroy(generator);
87
88 auth = auth_cfg_create();
89 private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, id, auth);
90 auth->destroy(auth);
91 if (private == NULL)
92 {
93 DBG1(DBG_CFG, "no private key found for '%Y' to rebuild AUTH", id);
94 id->destroy(id);
95 return FALSE;
96 }
97
98 switch (private->get_type(private))
99 {
100 case KEY_RSA:
101 scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
102 auth_method = AUTH_RSA;
103 break;
104 case KEY_ECDSA:
105 /* we try to deduct the signature scheme from the keysize */
106 switch (private->get_keysize(private))
107 {
108 case 256:
109 scheme = SIGN_ECDSA_256;
110 auth_method = AUTH_ECDSA_256;
111 break;
112 case 384:
113 scheme = SIGN_ECDSA_384;
114 auth_method = AUTH_ECDSA_384;
115 break;
116 case 521:
117 scheme = SIGN_ECDSA_521;
118 auth_method = AUTH_ECDSA_521;
119 break;
120 default:
121 DBG1(DBG_CFG, "%d bit ECDSA private key size not supported",
122 private->get_keysize(private));
123 id->destroy(id);
124 return FALSE;
125 }
126 break;
127 default:
128 DBG1(DBG_CFG, "private key of type %N not supported",
129 key_type_names, private->get_type(private));
130 id->destroy(id);
131 return FALSE;
132 }
133 keymat = ike_sa->get_keymat(ike_sa);
134 octets = keymat->get_auth_octets(keymat, FALSE, this->ike_init,
135 this->nonce, id, reserved);
136 if (!private->sign(private, scheme, octets, &auth_data))
137 {
138 chunk_free(&octets);
139 private->destroy(private);
140 id->destroy(id);
141 return FALSE;
142 }
143 auth_payload = auth_payload_create();
144 auth_payload->set_auth_method(auth_payload, auth_method);
145 auth_payload->set_data(auth_payload, auth_data);
146 chunk_free(&auth_data);
147 chunk_free(&octets);
148 private->destroy(private);
149
150 enumerator = message->create_payload_enumerator(message);
151 while (enumerator->enumerate(enumerator, &payload))
152 {
153 if (payload->get_type(payload) == AUTHENTICATION)
154 {
155 message->remove_payload_at(message, enumerator);
156 payload->destroy(payload);
157 }
158 }
159 enumerator->destroy(enumerator);
160
161 message->add_payload(message, (payload_t*)auth_payload);
162 DBG1(DBG_CFG, "rebuilding AUTH payload for '%Y' with %N",
163 id, auth_method_names, auth_method);
164 id->destroy(id);
165 return TRUE;
166 }
167
168 METHOD(listener_t, message, bool,
169 private_rebuild_auth_t *this, ike_sa_t *ike_sa, message_t *message,
170 bool incoming)
171 {
172 if (!incoming && message->get_message_id(message) == 1)
173 {
174 rebuild_auth(this, ike_sa, message);
175 }
176 if (message->get_exchange_type(message) == IKE_SA_INIT)
177 {
178 if (incoming)
179 {
180 nonce_payload_t *nonce;
181
182 nonce = (nonce_payload_t*)message->get_payload(message, NONCE);
183 if (nonce)
184 {
185 free(this->nonce.ptr);
186 this->nonce = nonce->get_nonce(nonce);
187 }
188 }
189 else
190 {
191 packet_t *packet;
192
193 if (message->generate(message, NULL, &packet) == SUCCESS)
194 {
195 free(this->ike_init.ptr);
196 this->ike_init = chunk_clone(packet->get_data(packet));
197 packet->destroy(packet);
198 }
199 }
200 }
201 return TRUE;
202 }
203
204 METHOD(hook_t, destroy, void,
205 private_rebuild_auth_t *this)
206 {
207 free(this->ike_init.ptr);
208 free(this->nonce.ptr);
209 free(this);
210 }
211
212 /**
213 * Create the IKE_AUTH fill hook
214 */
215 hook_t *rebuild_auth_hook_create(char *name)
216 {
217 private_rebuild_auth_t *this;
218
219 INIT(this,
220 .hook = {
221 .listener = {
222 .message = _message,
223 },
224 .destroy = _destroy,
225 },
226 );
227
228 return &this->hook;
229 }