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