Moving charon to libcharon.
[strongswan.git] / src / libcharon / sa / 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
23 typedef struct private_pubkey_authenticator_t private_pubkey_authenticator_t;
24
25 /**
26 * Private data of an pubkey_authenticator_t object.
27 */
28 struct private_pubkey_authenticator_t {
29
30 /**
31 * Public authenticator_t interface.
32 */
33 pubkey_authenticator_t public;
34
35 /**
36 * Assigned IKE_SA
37 */
38 ike_sa_t *ike_sa;
39
40 /**
41 * nonce to include in AUTH calculation
42 */
43 chunk_t nonce;
44
45 /**
46 * IKE_SA_INIT message data to include in AUTH calculation
47 */
48 chunk_t ike_sa_init;
49 };
50
51 /**
52 * Implementation of authenticator_t.build for builder
53 */
54 static status_t build(private_pubkey_authenticator_t *this, message_t *message)
55 {
56 chunk_t octets, auth_data;
57 status_t status = FAILED;
58 private_key_t *private;
59 identification_t *id;
60 auth_cfg_t *auth;
61 auth_payload_t *auth_payload;
62 auth_method_t auth_method;
63 signature_scheme_t scheme;
64 keymat_t *keymat;
65
66 id = this->ike_sa->get_my_id(this->ike_sa);
67 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
68 private = charon->credentials->get_private(charon->credentials, KEY_ANY,
69 id, auth);
70 if (private == NULL)
71 {
72 DBG1(DBG_IKE, "no private key found for '%Y'", id);
73 return NOT_FOUND;
74 }
75
76 switch (private->get_type(private))
77 {
78 case KEY_RSA:
79 /* we currently use always SHA1 for signatures,
80 * TODO: support other hashes depending on configuration/auth */
81 scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
82 auth_method = AUTH_RSA;
83 break;
84 case KEY_ECDSA:
85 /* we try to deduct the signature scheme from the keysize */
86 switch (private->get_keysize(private))
87 {
88 case 32:
89 scheme = SIGN_ECDSA_256;
90 auth_method = AUTH_ECDSA_256;
91 break;
92 case 48:
93 scheme = SIGN_ECDSA_384;
94 auth_method = AUTH_ECDSA_384;
95 break;
96 case 66:
97 scheme = SIGN_ECDSA_521;
98 auth_method = AUTH_ECDSA_521;
99 break;
100 default:
101 DBG1(DBG_IKE, "%d bit ECDSA private key size not supported",
102 private->get_keysize(private));
103 return status;
104 }
105 break;
106 default:
107 DBG1(DBG_IKE, "private key of type %N not supported",
108 key_type_names, private->get_type(private));
109 return status;
110 }
111 keymat = this->ike_sa->get_keymat(this->ike_sa);
112 octets = keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init,
113 this->nonce, id);
114 if (private->sign(private, scheme, octets, &auth_data))
115 {
116 auth_payload = auth_payload_create();
117 auth_payload->set_auth_method(auth_payload, auth_method);
118 auth_payload->set_data(auth_payload, auth_data);
119 chunk_free(&auth_data);
120 message->add_payload(message, (payload_t*)auth_payload);
121 status = SUCCESS;
122 }
123 DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id,
124 auth_method_names, auth_method,
125 (status == SUCCESS)? "successful":"failed");
126 chunk_free(&octets);
127 private->destroy(private);
128
129 return status;
130 }
131
132 /**
133 * Implementation of authenticator_t.process for verifier
134 */
135 static status_t process(private_pubkey_authenticator_t *this, message_t *message)
136 {
137 public_key_t *public;
138 auth_method_t auth_method;
139 auth_payload_t *auth_payload;
140 chunk_t auth_data, octets;
141 identification_t *id;
142 auth_cfg_t *auth, *current_auth;
143 enumerator_t *enumerator;
144 key_type_t key_type = KEY_ECDSA;
145 signature_scheme_t scheme;
146 status_t status = NOT_FOUND;
147 keymat_t *keymat;
148
149 auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION);
150 if (!auth_payload)
151 {
152 return FAILED;
153 }
154 auth_method = auth_payload->get_auth_method(auth_payload);
155 switch (auth_method)
156 {
157 case AUTH_RSA:
158 /* We currently accept SHA1 signatures only
159 * TODO: allow other hash algorithms and note it in "auth" */
160 key_type = KEY_RSA;
161 scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
162 break;
163 case AUTH_ECDSA_256:
164 scheme = SIGN_ECDSA_256;
165 break;
166 case AUTH_ECDSA_384:
167 scheme = SIGN_ECDSA_384;
168 break;
169 case AUTH_ECDSA_521:
170 scheme = SIGN_ECDSA_521;
171 break;
172 default:
173 return INVALID_ARG;
174 }
175 auth_data = auth_payload->get_data(auth_payload);
176 id = this->ike_sa->get_other_id(this->ike_sa);
177 keymat = this->ike_sa->get_keymat(this->ike_sa);
178 octets = keymat->get_auth_octets(keymat, TRUE, this->ike_sa_init,
179 this->nonce, id);
180 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
181 enumerator = charon->credentials->create_public_enumerator(
182 charon->credentials, key_type, id, auth);
183 while (enumerator->enumerate(enumerator, &public, &current_auth))
184 {
185 if (public->verify(public, scheme, octets, auth_data))
186 {
187 DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
188 id, auth_method_names, auth_method);
189 status = SUCCESS;
190 auth->merge(auth, current_auth, FALSE);
191 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
192 break;
193 }
194 else
195 {
196 status = FAILED;
197 DBG1(DBG_IKE, "signature validation failed, looking for another key");
198 }
199 }
200 enumerator->destroy(enumerator);
201 chunk_free(&octets);
202 if (status == NOT_FOUND)
203 {
204 DBG1(DBG_IKE, "no trusted %N public key found for '%Y'",
205 key_type_names, key_type, id);
206 }
207 return status;
208 }
209
210 /**
211 * Implementation of authenticator_t.process for builder
212 * Implementation of authenticator_t.build for verifier
213 */
214 static status_t return_failed()
215 {
216 return FAILED;
217 }
218
219 /**
220 * Implementation of authenticator_t.destroy.
221 */
222 static void destroy(private_pubkey_authenticator_t *this)
223 {
224 free(this);
225 }
226
227 /*
228 * Described in header.
229 */
230 pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa,
231 chunk_t received_nonce, chunk_t sent_init)
232 {
233 private_pubkey_authenticator_t *this = malloc_thing(private_pubkey_authenticator_t);
234
235 this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))build;
236 this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))return_failed;
237 this->public.authenticator.is_mutual = (bool(*)(authenticator_t*))return_false;
238 this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy;
239
240 this->ike_sa = ike_sa;
241 this->ike_sa_init = sent_init;
242 this->nonce = received_nonce;
243
244 return &this->public;
245 }
246
247 /*
248 * Described in header.
249 */
250 pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa,
251 chunk_t sent_nonce, chunk_t received_init)
252 {
253 private_pubkey_authenticator_t *this = malloc_thing(private_pubkey_authenticator_t);
254
255 this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))return_failed;
256 this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process;
257 this->public.authenticator.is_mutual = (bool(*)(authenticator_t*))return_false;
258 this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy;
259
260 this->ike_sa = ike_sa;
261 this->ike_sa_init = received_init;
262 this->nonce = sent_nonce;
263
264 return &this->public;
265 }