46e0be4c0fdac18f7f808b76dad765a5089a2321
[strongswan.git] / src / charon / sa / authenticators / pubkey_authenticator.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2005-2006 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 <string.h>
21
22 #include "pubkey_authenticator.h"
23
24 #include <daemon.h>
25 #include <credentials/auth_info.h>
26
27
28 typedef struct private_pubkey_authenticator_t private_pubkey_authenticator_t;
29
30 /**
31 * Private data of an pubkey_authenticator_t object.
32 */
33 struct private_pubkey_authenticator_t {
34
35 /**
36 * Public authenticator_t interface.
37 */
38 pubkey_authenticator_t public;
39
40 /**
41 * Assigned IKE_SA
42 */
43 ike_sa_t *ike_sa;
44 };
45
46 /**
47 * Function implemented in psk_authenticator.c
48 */
49 extern chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce,
50 identification_t *id, prf_t *prf);
51
52 /**
53 * Implementation of authenticator_t.verify.
54 */
55 static status_t verify(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
56 chunk_t my_nonce, auth_payload_t *auth_payload)
57 {
58 public_key_t *public;
59 auth_method_t auth_method;
60 chunk_t auth_data, octets;
61 identification_t *other_id;
62 prf_t *prf;
63 auth_info_t *auth, *current_auth;
64 enumerator_t *enumerator;
65 key_type_t key_type = KEY_ECDSA;
66 signature_scheme_t scheme;
67 status_t status = FAILED;
68
69 other_id = this->ike_sa->get_other_id(this->ike_sa);
70 auth_method = auth_payload->get_auth_method(auth_payload);
71 switch (auth_method)
72 {
73 case AUTH_RSA:
74 /* We are currently fixed to SHA1 hashes.
75 * TODO: allow other hash algorithms and note it in "auth" */
76 key_type = KEY_RSA;
77 scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
78 break;
79 case AUTH_ECDSA_256:
80 scheme = SIGN_ECDSA_256;
81 break;
82 case AUTH_ECDSA_384:
83 scheme = SIGN_ECDSA_384;
84 break;
85 case AUTH_ECDSA_521:
86 scheme = SIGN_ECDSA_521;
87 break;
88 default:
89 return INVALID_ARG;
90 }
91 auth_data = auth_payload->get_data(auth_payload);
92 prf = this->ike_sa->get_prf(this->ike_sa);
93 prf->set_key(prf, this->ike_sa->get_skp_verify(this->ike_sa));
94 octets = build_tbs_octets(ike_sa_init, my_nonce, other_id, prf);
95
96 auth = this->ike_sa->get_other_auth(this->ike_sa);
97 enumerator = charon->credentials->create_public_enumerator(
98 charon->credentials, key_type, other_id, auth);
99 while (enumerator->enumerate(enumerator, &public, &current_auth))
100 {
101 if (public->verify(public, scheme, octets, auth_data))
102 {
103 DBG1(DBG_IKE, "authentication of '%D' with %N successful",
104 other_id, auth_method_names, auth_method);
105 status = SUCCESS;
106 auth->merge(auth, current_auth);
107 break;
108 }
109 else
110 {
111 DBG1(DBG_IKE, "signature validation failed, looking for another key");
112 }
113 }
114 enumerator->destroy(enumerator);
115 chunk_free(&octets);
116 return status;
117 }
118
119 /**
120 * Implementation of authenticator_t.build.
121 */
122 static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
123 chunk_t other_nonce, auth_payload_t **auth_payload)
124 {
125 chunk_t octets, auth_data;
126 status_t status = FAILED;
127 private_key_t *private;
128 identification_t *my_id;
129 prf_t *prf;
130 auth_info_t *auth;
131 auth_method_t auth_method;
132 signature_scheme_t scheme;
133
134 my_id = this->ike_sa->get_my_id(this->ike_sa);
135 auth = this->ike_sa->get_my_auth(this->ike_sa);
136 private = charon->credentials->get_private(charon->credentials, KEY_ANY,
137 my_id, auth);
138 if (private == NULL)
139 {
140 DBG1(DBG_IKE, "no private key found for '%D'", my_id);
141 return NOT_FOUND;
142 }
143
144 switch (private->get_type(private))
145 {
146 case KEY_RSA:
147 /* we currently use always SHA1 for signatures,
148 * TODO: support other hashes depending on configuration/auth */
149 scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
150 auth_method = AUTH_RSA;
151 break;
152 case KEY_ECDSA:
153 /* we try to deduct the signature scheme from the keysize */
154 switch (private->get_keysize(private))
155 {
156 case 32:
157 scheme = SIGN_ECDSA_256;
158 auth_method = AUTH_ECDSA_256;
159 break;
160 case 48:
161 scheme = SIGN_ECDSA_384;
162 auth_method = AUTH_ECDSA_384;
163 break;
164 case 66:
165 scheme = SIGN_ECDSA_521;
166 auth_method = AUTH_ECDSA_521;
167 break;
168 default:
169 DBG1(DBG_IKE, "%d bit ECDSA private key size not supported",
170 private->get_keysize(private));
171 return status;
172 }
173 break;
174 default:
175 DBG1(DBG_IKE, "private key of type %N not supported",
176 key_type_names, private->get_type(private));
177 return status;
178 }
179 prf = this->ike_sa->get_prf(this->ike_sa);
180 prf->set_key(prf, this->ike_sa->get_skp_build(this->ike_sa));
181 octets = build_tbs_octets(ike_sa_init, other_nonce, my_id, prf);
182
183 if (private->sign(private, scheme, octets, &auth_data))
184 {
185 auth_payload_t *payload = auth_payload_create();
186 payload->set_auth_method(payload, auth_method);
187 payload->set_data(payload, auth_data);
188 *auth_payload = payload;
189 chunk_free(&auth_data);
190 status = SUCCESS;
191 }
192 DBG1(DBG_IKE, "authentication of '%D' (myself) with %N %s", my_id,
193 auth_method_names, auth_method,
194 (status == SUCCESS)? "successful":"failed");
195 chunk_free(&octets);
196 private->destroy(private);
197
198 return status;
199 }
200
201 /**
202 * Implementation of authenticator_t.destroy.
203 */
204 static void destroy(private_pubkey_authenticator_t *this)
205 {
206 free(this);
207 }
208
209 /*
210 * Described in header.
211 */
212 pubkey_authenticator_t *pubkey_authenticator_create(ike_sa_t *ike_sa)
213 {
214 private_pubkey_authenticator_t *this = malloc_thing(private_pubkey_authenticator_t);
215
216 /* public functions */
217 this->public.authenticator_interface.verify = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t*))verify;
218 this->public.authenticator_interface.build = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t**))build;
219 this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy;
220
221 /* private data */
222 this->ike_sa = ike_sa;
223
224 return &this->public;
225 }