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