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