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