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