Merge branch 'ikev1-clean' into ikev1-master
[strongswan.git] / src / libcharon / sa / ikev2 / authenticators / pubkey_authenticator.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2005-2009 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "pubkey_authenticator.h"
19
20 #include <daemon.h>
21 #include <encoding/payloads/auth_payload.h>
22 #include <sa/ikev2/keymat_v2.h>
23
24 typedef struct private_pubkey_authenticator_t private_pubkey_authenticator_t;
25
26 /**
27 * Private data of an pubkey_authenticator_t object.
28 */
29 struct private_pubkey_authenticator_t {
30
31 /**
32 * Public authenticator_t interface.
33 */
34 pubkey_authenticator_t public;
35
36 /**
37 * Assigned IKE_SA
38 */
39 ike_sa_t *ike_sa;
40
41 /**
42 * nonce to include in AUTH calculation
43 */
44 chunk_t nonce;
45
46 /**
47 * IKE_SA_INIT message data to include in AUTH calculation
48 */
49 chunk_t ike_sa_init;
50
51 /**
52 * Reserved bytes of ID payload
53 */
54 char reserved[3];
55 };
56
57 METHOD(authenticator_t, build, status_t,
58 private_pubkey_authenticator_t *this, message_t *message)
59 {
60 chunk_t octets, auth_data;
61 status_t status = FAILED;
62 private_key_t *private;
63 identification_t *id;
64 auth_cfg_t *auth;
65 auth_payload_t *auth_payload;
66 auth_method_t auth_method;
67 signature_scheme_t scheme;
68 keymat_v2_t *keymat;
69
70 id = this->ike_sa->get_my_id(this->ike_sa);
71 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
72 private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, id, auth);
73 if (private == NULL)
74 {
75 DBG1(DBG_IKE, "no private key found for '%Y'", id);
76 return NOT_FOUND;
77 }
78
79 switch (private->get_type(private))
80 {
81 case KEY_RSA:
82 /* we currently use always SHA1 for signatures,
83 * TODO: support other hashes depending on configuration/auth */
84 scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
85 auth_method = AUTH_RSA;
86 break;
87 case KEY_ECDSA:
88 /* we try to deduct the signature scheme from the keysize */
89 switch (private->get_keysize(private))
90 {
91 case 256:
92 scheme = SIGN_ECDSA_256;
93 auth_method = AUTH_ECDSA_256;
94 break;
95 case 384:
96 scheme = SIGN_ECDSA_384;
97 auth_method = AUTH_ECDSA_384;
98 break;
99 case 521:
100 scheme = SIGN_ECDSA_521;
101 auth_method = AUTH_ECDSA_521;
102 break;
103 default:
104 DBG1(DBG_IKE, "%d bit ECDSA private key size not supported",
105 private->get_keysize(private));
106 return status;
107 }
108 break;
109 default:
110 DBG1(DBG_IKE, "private key of type %N not supported",
111 key_type_names, private->get_type(private));
112 return status;
113 }
114 keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
115 octets = keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init,
116 this->nonce, id, this->reserved);
117 if (private->sign(private, scheme, octets, &auth_data))
118 {
119 auth_payload = auth_payload_create();
120 auth_payload->set_auth_method(auth_payload, auth_method);
121 auth_payload->set_data(auth_payload, auth_data);
122 chunk_free(&auth_data);
123 message->add_payload(message, (payload_t*)auth_payload);
124 status = SUCCESS;
125 }
126 DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id,
127 auth_method_names, auth_method,
128 (status == SUCCESS)? "successful":"failed");
129 chunk_free(&octets);
130 private->destroy(private);
131
132 return status;
133 }
134
135 METHOD(authenticator_t, process, status_t,
136 private_pubkey_authenticator_t *this, message_t *message)
137 {
138 public_key_t *public;
139 auth_method_t auth_method;
140 auth_payload_t *auth_payload;
141 chunk_t auth_data, octets;
142 identification_t *id;
143 auth_cfg_t *auth, *current_auth;
144 enumerator_t *enumerator;
145 key_type_t key_type = KEY_ECDSA;
146 signature_scheme_t scheme;
147 status_t status = NOT_FOUND;
148 keymat_v2_t *keymat;
149
150 auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION);
151 if (!auth_payload)
152 {
153 return FAILED;
154 }
155 auth_method = auth_payload->get_auth_method(auth_payload);
156 switch (auth_method)
157 {
158 case AUTH_RSA:
159 /* We currently accept SHA1 signatures only
160 * TODO: allow other hash algorithms and note it in "auth" */
161 key_type = KEY_RSA;
162 scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
163 break;
164 case AUTH_ECDSA_256:
165 scheme = SIGN_ECDSA_256;
166 break;
167 case AUTH_ECDSA_384:
168 scheme = SIGN_ECDSA_384;
169 break;
170 case AUTH_ECDSA_521:
171 scheme = SIGN_ECDSA_521;
172 break;
173 default:
174 return INVALID_ARG;
175 }
176 auth_data = auth_payload->get_data(auth_payload);
177 id = this->ike_sa->get_other_id(this->ike_sa);
178 keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
179 octets = keymat->get_auth_octets(keymat, TRUE, this->ike_sa_init,
180 this->nonce, id, this->reserved);
181 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
182 enumerator = lib->credmgr->create_public_enumerator(lib->credmgr,
183 key_type, id, auth);
184 while (enumerator->enumerate(enumerator, &public, &current_auth))
185 {
186 if (public->verify(public, scheme, octets, auth_data))
187 {
188 DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
189 id, auth_method_names, auth_method);
190 status = SUCCESS;
191 auth->merge(auth, current_auth, FALSE);
192 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
193 break;
194 }
195 else
196 {
197 status = FAILED;
198 DBG1(DBG_IKE, "signature validation failed, looking for another key");
199 }
200 }
201 enumerator->destroy(enumerator);
202 chunk_free(&octets);
203 if (status == NOT_FOUND)
204 {
205 DBG1(DBG_IKE, "no trusted %N public key found for '%Y'",
206 key_type_names, key_type, id);
207 }
208 return status;
209 }
210
211 METHOD(authenticator_t, destroy, void,
212 private_pubkey_authenticator_t *this)
213 {
214 free(this);
215 }
216
217 /*
218 * Described in header.
219 */
220 pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa,
221 chunk_t received_nonce, chunk_t sent_init,
222 char reserved[3])
223 {
224 private_pubkey_authenticator_t *this;
225
226 INIT(this,
227 .public = {
228 .authenticator = {
229 .build = _build,
230 .process = (void*)return_failed,
231 .is_mutual = (void*)return_false,
232 .destroy = _destroy,
233 },
234 },
235 .ike_sa = ike_sa,
236 .ike_sa_init = sent_init,
237 .nonce = received_nonce,
238 );
239 memcpy(this->reserved, reserved, sizeof(this->reserved));
240
241 return &this->public;
242 }
243
244 /*
245 * Described in header.
246 */
247 pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa,
248 chunk_t sent_nonce, chunk_t received_init,
249 char reserved[3])
250 {
251 private_pubkey_authenticator_t *this;
252
253 INIT(this,
254 .public = {
255 .authenticator = {
256 .build = (void*)return_failed,
257 .process = _process,
258 .is_mutual = (void*)return_false,
259 .destroy = _destroy,
260 },
261 },
262 .ike_sa = ike_sa,
263 .ike_sa_init = received_init,
264 .nonce = sent_nonce,
265 );
266 memcpy(this->reserved, reserved, sizeof(this->reserved));
267
268 return &this->public;
269 }