]>
Commit | Line | Data |
---|---|---|
ebae15f0 JH |
1 | /** |
2 | * @file authenticator.c | |
3 | * | |
39b2903f | 4 | * @brief Implementation of authenticator_t. |
ebae15f0 JH |
5 | * |
6 | */ | |
7 | ||
8 | /* | |
9 | * Copyright (C) 2005 Jan Hutter, Martin Willi | |
10 | * Hochschule fuer Technik Rapperswil | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or modify it | |
13 | * under the terms of the GNU General Public License as published by the | |
14 | * Free Software Foundation; either version 2 of the License, or (at your | |
15 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, but | |
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
19 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
20 | * for more details. | |
21 | */ | |
22 | ||
5113680f MW |
23 | #include <string.h> |
24 | ||
ebae15f0 JH |
25 | #include "authenticator.h" |
26 | ||
aebb38a0 JH |
27 | #include <daemon.h> |
28 | ||
29 | /** | |
30 | * Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE. | |
31 | */ | |
16b9a73c | 32 | #define IKEV2_KEY_PAD "Key Pad for IKEv2" |
ebae15f0 | 33 | |
39b2903f | 34 | |
ebae15f0 JH |
35 | typedef struct private_authenticator_t private_authenticator_t; |
36 | ||
37 | /** | |
38 | * Private data of an authenticator_t object. | |
39 | */ | |
40 | struct private_authenticator_t { | |
41 | ||
42 | /** | |
813ed1cd | 43 | * Public authenticator_t interface. |
ebae15f0 JH |
44 | */ |
45 | authenticator_t public; | |
46 | ||
47 | /** | |
16b9a73c | 48 | * Assigned IKE_SA. Needed to get objects of type prf_t and logger_t. |
ebae15f0 JH |
49 | */ |
50 | protected_ike_sa_t *ike_sa; | |
aebb38a0 JH |
51 | |
52 | /** | |
813ed1cd | 53 | * PRF taken from the IKE_SA. |
aebb38a0 JH |
54 | */ |
55 | prf_t *prf; | |
ebae15f0 JH |
56 | |
57 | /** | |
58 | * A logger for. | |
59 | * | |
60 | * Using logger of IKE_SA. | |
61 | */ | |
62 | logger_t *logger; | |
63 | ||
64 | /** | |
39b2903f | 65 | * @brief Creates the octets which are signed (RSA) or MACed (shared secret) as described in section |
8a491129 | 66 | * 2.15 of RFC. |
813ed1cd JH |
67 | * |
68 | * @param this calling object | |
69 | * @param last_message the last message to include in created octets | |
70 | * (either binary form of IKE_SA_INIT request or IKE_SA_INIT response) | |
71 | * @param other_nonce Nonce data received from other peer | |
72 | * @param my_id id_payload_t object representing an ID payload | |
73 | * @param initiator Type of peer. TRUE, if it is original initiator, FALSE otherwise | |
74 | * @return octets as described in section 2.15. Memory gets allocated and has to get | |
75 | * destroyed by caller. | |
ebae15f0 | 76 | */ |
39b2903f JH |
77 | chunk_t (*allocate_octets) (private_authenticator_t *this, |
78 | chunk_t last_message, | |
79 | chunk_t other_nonce, | |
80 | id_payload_t *my_id, | |
81 | bool initiator); | |
ebae15f0 | 82 | |
813ed1cd | 83 | /** |
39b2903f | 84 | * @brief Creates the AUTH data using auth method SHARED_KEY_MESSAGE_INTEGRITY_CODE. |
813ed1cd JH |
85 | * |
86 | * @param this calling object | |
87 | * @param last_message the last message | |
88 | * (either binary form of IKE_SA_INIT request or IKE_SA_INIT response) | |
89 | * @param nonce Nonce data to include in auth data compution | |
90 | * @param id_payload id_payload_t object representing an ID payload | |
91 | * @param initiator Type of peer. TRUE, if it is original initiator, FALSE otherwise | |
39b2903f JH |
92 | * @param shared_secret shared secret as chunk_t. If shared secret is a string, |
93 | * the NULL termination is not included. | |
94 | * @return AUTH data as dscribed in section 2.15 for | |
95 | * AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE. | |
813ed1cd JH |
96 | * Memory gets allocated and has to get destroyed by caller. |
97 | */ | |
16b9a73c MW |
98 | chunk_t (*build_preshared_secret_signature) (private_authenticator_t *this, |
99 | chunk_t last_message, | |
100 | chunk_t nonce, | |
101 | id_payload_t *id_payload, | |
102 | bool initiator, | |
103 | chunk_t preshared_secret); | |
ebae15f0 JH |
104 | }; |
105 | ||
106 | /** | |
813ed1cd | 107 | * Implementation of private_authenticator_t.allocate_octets. |
ebae15f0 | 108 | */ |
39b2903f JH |
109 | static chunk_t allocate_octets(private_authenticator_t *this, |
110 | chunk_t last_message, | |
111 | chunk_t other_nonce, | |
112 | id_payload_t *my_id, | |
113 | bool initiator) | |
ebae15f0 | 114 | { |
ce461bbd | 115 | prf_t *prf; |
8d68033e | 116 | chunk_t id_chunk = my_id->get_data(my_id); |
ebae15f0 | 117 | u_int8_t id_with_header[4 + id_chunk.len]; |
f6ba78c3 | 118 | /* |
a36a745a JH |
119 | * IKEv2 for linux (http://sf.net/projects/ikev2/) |
120 | * is not compatible with IKEv2 Draft and so not compatible with this | |
f6ba78c3 JH |
121 | * implementation, cause AUTH data are computed without |
122 | * ID type and the three reserved bytes. | |
123 | */ | |
124 | chunk_t id_with_header_chunk = {ptr:id_with_header, len: sizeof(id_with_header)}; | |
ebae15f0 | 125 | u_int8_t *current_pos; |
aebb38a0 | 126 | chunk_t octets; |
ebae15f0 | 127 | |
8d68033e | 128 | id_with_header[0] = my_id->get_id_type(my_id); |
ebae15f0 JH |
129 | id_with_header[1] = 0x00; |
130 | id_with_header[2] = 0x00; | |
131 | id_with_header[3] = 0x00; | |
132 | memcpy(id_with_header + 4,id_chunk.ptr,id_chunk.len); | |
ebae15f0 | 133 | |
aebb38a0 JH |
134 | if (initiator) |
135 | { | |
ce461bbd | 136 | prf = this->ike_sa->get_prf_auth_i(this->ike_sa); |
aebb38a0 JH |
137 | } |
138 | else | |
139 | { | |
ce461bbd | 140 | prf = this->ike_sa->get_prf_auth_r(this->ike_sa); |
aebb38a0 | 141 | } |
ebae15f0 JH |
142 | |
143 | /* 4 bytes are id type and reserved fields of id payload */ | |
ce461bbd | 144 | octets.len = last_message.len + other_nonce.len + prf->get_block_size(prf); |
5113680f | 145 | octets.ptr = malloc(octets.len); |
ebae15f0 JH |
146 | current_pos = octets.ptr; |
147 | memcpy(current_pos,last_message.ptr,last_message.len); | |
148 | current_pos += last_message.len; | |
149 | memcpy(current_pos,other_nonce.ptr,other_nonce.len); | |
150 | current_pos += other_nonce.len; | |
ce461bbd | 151 | prf->get_bytes(prf, id_with_header_chunk, current_pos); |
ebae15f0 | 152 | |
16b9a73c | 153 | this->logger->log_chunk(this->logger,RAW | LEVEL2, "Octets (Mesage + Nonce + prf(Sk_px,Idx)",octets); |
ebae15f0 JH |
154 | return octets; |
155 | } | |
156 | ||
157 | /** | |
16b9a73c | 158 | * Implementation of private_authenticator_t.build_preshared_secret_signature. |
ebae15f0 | 159 | */ |
16b9a73c | 160 | static chunk_t build_preshared_secret_signature(private_authenticator_t *this, |
39b2903f JH |
161 | chunk_t last_message, |
162 | chunk_t nonce, | |
163 | id_payload_t *id_payload, | |
164 | bool initiator, | |
165 | chunk_t preshared_secret) | |
ebae15f0 | 166 | { |
16b9a73c | 167 | chunk_t key_pad = {ptr: IKEV2_KEY_PAD, len:strlen(IKEV2_KEY_PAD)}; |
aebb38a0 JH |
168 | u_int8_t key_buffer[this->prf->get_block_size(this->prf)]; |
169 | chunk_t key = {ptr: key_buffer, len: sizeof(key_buffer)}; | |
170 | chunk_t auth_data; | |
171 | ||
172 | chunk_t octets = this->allocate_octets(this,last_message,nonce,id_payload,initiator); | |
ebae15f0 | 173 | |
16b9a73c MW |
174 | /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */ |
175 | this->prf->set_key(this->prf, preshared_secret); | |
176 | this->prf->get_bytes(this->prf, key_pad, key_buffer); | |
177 | this->prf->set_key(this->prf, key); | |
178 | this->prf->allocate_bytes(this->prf, octets, &auth_data); | |
5113680f | 179 | chunk_free(&octets); |
16b9a73c | 180 | this->logger->log_chunk(this->logger,RAW | LEVEL2, "Authenticated data",auth_data); |
aebb38a0 | 181 | |
ebae15f0 JH |
182 | return auth_data; |
183 | } | |
184 | ||
ebae15f0 | 185 | /** |
813ed1cd | 186 | * Implementation of authenticator_t.verify_auth_data. |
ebae15f0 | 187 | */ |
39b2903f JH |
188 | static status_t verify_auth_data (private_authenticator_t *this, |
189 | auth_payload_t *auth_payload, | |
190 | chunk_t last_received_packet, | |
191 | chunk_t my_nonce, | |
192 | id_payload_t *other_id_payload, | |
193 | bool initiator) | |
ebae15f0 | 194 | { |
8d68033e | 195 | switch(auth_payload->get_auth_method(auth_payload)) |
ebae15f0 JH |
196 | { |
197 | case SHARED_KEY_MESSAGE_INTEGRITY_CODE: | |
198 | { | |
8ff8c33d | 199 | identification_t *other_id = other_id_payload->get_identification(other_id_payload); |
aebb38a0 JH |
200 | chunk_t auth_data = auth_payload->get_data(auth_payload); |
201 | chunk_t preshared_secret; | |
202 | status_t status; | |
203 | ||
16b9a73c MW |
204 | status = charon->credentials->get_shared_secret(charon->credentials, |
205 | other_id, | |
206 | &preshared_secret); | |
aebb38a0 JH |
207 | if (status != SUCCESS) |
208 | { | |
efadbf79 MW |
209 | this->logger->log(this->logger, ERROR|LEVEL1, "No shared secret found for %s", |
210 | other_id->get_string(other_id)); | |
87a217f9 | 211 | other_id->destroy(other_id); |
aebb38a0 JH |
212 | return status; |
213 | } | |
ebae15f0 | 214 | |
16b9a73c | 215 | chunk_t my_auth_data = this->build_preshared_secret_signature(this, |
dec59822 MW |
216 | last_received_packet, |
217 | my_nonce, | |
218 | other_id_payload, | |
219 | initiator, | |
220 | preshared_secret); | |
5113680f | 221 | chunk_free(&preshared_secret); |
8d68033e | 222 | |
ebae15f0 JH |
223 | if (auth_data.len != my_auth_data.len) |
224 | { | |
5113680f | 225 | chunk_free(&my_auth_data); |
87a217f9 | 226 | status = FAILED; |
ebae15f0 | 227 | } |
87a217f9 | 228 | else if (memcmp(auth_data.ptr,my_auth_data.ptr, my_auth_data.len) == 0) |
ebae15f0 | 229 | { |
87a217f9 MW |
230 | this->logger->log(this->logger, CONTROL, "Authentication of %s with preshared secret successful", |
231 | other_id->get_string(other_id)); | |
f6ba78c3 | 232 | status = SUCCESS; |
ebae15f0 JH |
233 | } |
234 | else | |
235 | { | |
87a217f9 MW |
236 | this->logger->log(this->logger, CONTROL, "Authentication of %s with preshared secret failed", |
237 | other_id->get_string(other_id)); | |
f6ba78c3 | 238 | status = FAILED; |
ebae15f0 | 239 | } |
87a217f9 | 240 | other_id->destroy(other_id); |
5113680f | 241 | chunk_free(&my_auth_data); |
f6ba78c3 | 242 | return status; |
ebae15f0 | 243 | } |
8ff8c33d MW |
244 | case RSA_DIGITAL_SIGNATURE: |
245 | { | |
246 | identification_t *other_id = other_id_payload->get_identification(other_id_payload); | |
247 | rsa_public_key_t *public_key; | |
248 | status_t status; | |
249 | chunk_t octets, auth_data; | |
250 | ||
251 | auth_data = auth_payload->get_data(auth_payload); | |
252 | ||
13e4a62f MW |
253 | public_key = charon->credentials->get_rsa_public_key(charon->credentials, |
254 | other_id); | |
255 | if (public_key == NULL) | |
8ff8c33d | 256 | { |
efadbf79 MW |
257 | this->logger->log(this->logger, ERROR|LEVEL1, "No RSA public key found for %s", |
258 | other_id->get_string(other_id)); | |
87a217f9 | 259 | other_id->destroy(other_id); |
13e4a62f | 260 | return NOT_FOUND; |
8ff8c33d MW |
261 | } |
262 | ||
16b9a73c | 263 | octets = this->allocate_octets(this,last_received_packet, my_nonce,other_id_payload, initiator); |
8ff8c33d MW |
264 | |
265 | status = public_key->verify_emsa_pkcs1_signature(public_key, octets, auth_data); | |
87a217f9 MW |
266 | if (status == SUCCESS) |
267 | { | |
268 | this->logger->log(this->logger, CONTROL, "Authentication of %s with RSA successful", | |
269 | other_id->get_string(other_id)); | |
270 | } | |
271 | else | |
272 | { | |
273 | this->logger->log(this->logger, CONTROL, "Authentication of %s with RSA failed", | |
274 | other_id->get_string(other_id)); | |
275 | } | |
8ff8c33d | 276 | |
87a217f9 MW |
277 | public_key->destroy(public_key); |
278 | other_id->destroy(other_id); | |
5113680f | 279 | chunk_free(&octets); |
8ff8c33d MW |
280 | return status; |
281 | } | |
ebae15f0 JH |
282 | default: |
283 | { | |
284 | return NOT_SUPPORTED; | |
285 | } | |
286 | } | |
287 | } | |
288 | ||
289 | /** | |
8d68033e | 290 | * Implementation of authenticator_t.compute_auth_data. |
ebae15f0 | 291 | */ |
39b2903f JH |
292 | static status_t compute_auth_data (private_authenticator_t *this, |
293 | auth_payload_t **auth_payload, | |
294 | chunk_t last_sent_packet, | |
295 | chunk_t other_nonce, | |
296 | id_payload_t *my_id_payload, | |
297 | bool initiator) | |
ebae15f0 | 298 | { |
16b9a73c | 299 | connection_t *connection = this->ike_sa->get_connection(this->ike_sa); |
aebb38a0 | 300 | |
16b9a73c | 301 | switch(connection->get_auth_method(connection)) |
ebae15f0 JH |
302 | { |
303 | case SHARED_KEY_MESSAGE_INTEGRITY_CODE: | |
aebb38a0 | 304 | { |
16b9a73c | 305 | identification_t *my_id = my_id_payload->get_identification(my_id_payload); |
ebae15f0 | 306 | chunk_t preshared_secret; |
16b9a73c MW |
307 | status_t status; |
308 | chunk_t auth_data; | |
8d68033e | 309 | |
16b9a73c MW |
310 | status = charon->credentials->get_shared_secret(charon->credentials, |
311 | my_id, | |
312 | &preshared_secret); | |
aebb38a0 | 313 | |
aebb38a0 JH |
314 | if (status != SUCCESS) |
315 | { | |
efadbf79 MW |
316 | this->logger->log(this->logger, ERROR|LEVEL1, "No shared secret found for %s", |
317 | my_id->get_string(my_id)); | |
318 | my_id->destroy(my_id); | |
aebb38a0 JH |
319 | return status; |
320 | } | |
efadbf79 | 321 | my_id->destroy(my_id); |
aebb38a0 | 322 | |
16b9a73c MW |
323 | auth_data = this->build_preshared_secret_signature(this, last_sent_packet, other_nonce, |
324 | my_id_payload, initiator, preshared_secret); | |
5113680f | 325 | chunk_free(&preshared_secret); |
8d68033e | 326 | *auth_payload = auth_payload_create(); |
16b9a73c MW |
327 | (*auth_payload)->set_auth_method(*auth_payload, SHARED_KEY_MESSAGE_INTEGRITY_CODE); |
328 | (*auth_payload)->set_data(*auth_payload, auth_data); | |
8d68033e | 329 | |
5113680f | 330 | chunk_free(&auth_data); |
ebae15f0 | 331 | return SUCCESS; |
aebb38a0 | 332 | } |
8ff8c33d MW |
333 | case RSA_DIGITAL_SIGNATURE: |
334 | { | |
335 | identification_t *my_id = my_id_payload->get_identification(my_id_payload); | |
336 | rsa_private_key_t *private_key; | |
337 | status_t status; | |
338 | chunk_t octets, auth_data; | |
339 | ||
13e4a62f MW |
340 | private_key = charon->credentials->get_rsa_private_key(charon->credentials, my_id); |
341 | if (private_key == NULL) | |
8ff8c33d | 342 | { |
efadbf79 MW |
343 | this->logger->log(this->logger, ERROR|LEVEL1, "No RSA private key found for %s", |
344 | my_id->get_string(my_id)); | |
345 | my_id->destroy(my_id); | |
13e4a62f | 346 | return NOT_FOUND; |
8ff8c33d | 347 | } |
efadbf79 | 348 | my_id->destroy(my_id); |
8ff8c33d MW |
349 | |
350 | octets = this->allocate_octets(this,last_sent_packet,other_nonce,my_id_payload,initiator); | |
351 | ||
352 | status = private_key->build_emsa_pkcs1_signature(private_key, HASH_SHA1, octets, &auth_data); | |
5113680f | 353 | chunk_free(&octets); |
8ff8c33d MW |
354 | if (status != SUCCESS) |
355 | { | |
f2ee13a7 MW |
356 | private_key->destroy(private_key); |
357 | return status; | |
8ff8c33d MW |
358 | } |
359 | ||
360 | *auth_payload = auth_payload_create(); | |
16b9a73c MW |
361 | (*auth_payload)->set_auth_method(*auth_payload, RSA_DIGITAL_SIGNATURE); |
362 | (*auth_payload)->set_data(*auth_payload, auth_data); | |
8ff8c33d | 363 | |
87a217f9 | 364 | private_key->destroy(private_key); |
5113680f | 365 | chunk_free(&auth_data); |
8ff8c33d MW |
366 | return SUCCESS; |
367 | } | |
ebae15f0 JH |
368 | default: |
369 | { | |
370 | return NOT_SUPPORTED; | |
371 | } | |
aebb38a0 | 372 | } |
ebae15f0 JH |
373 | } |
374 | ||
375 | /** | |
376 | * Implementation of authenticator_t.destroy. | |
377 | */ | |
378 | static void destroy (private_authenticator_t *this) | |
379 | { | |
5113680f | 380 | free(this); |
ebae15f0 JH |
381 | } |
382 | ||
383 | /* | |
384 | * Described in header. | |
385 | */ | |
386 | authenticator_t *authenticator_create(protected_ike_sa_t *ike_sa) | |
387 | { | |
5113680f | 388 | private_authenticator_t *this = malloc_thing(private_authenticator_t); |
ebae15f0 JH |
389 | |
390 | /* Public functions */ | |
391 | this->public.destroy = (void(*)(authenticator_t*))destroy; | |
f6ba78c3 | 392 | this->public.verify_auth_data = (status_t (*) (authenticator_t *,auth_payload_t *, chunk_t ,chunk_t ,id_payload_t *,bool)) verify_auth_data; |
aebb38a0 | 393 | this->public.compute_auth_data = (status_t (*) (authenticator_t *,auth_payload_t **, chunk_t ,chunk_t ,id_payload_t *,bool)) compute_auth_data; |
ebae15f0 JH |
394 | |
395 | /* private functions */ | |
396 | this->allocate_octets = allocate_octets; | |
16b9a73c | 397 | this->build_preshared_secret_signature = build_preshared_secret_signature; |
ebae15f0 JH |
398 | |
399 | /* private data */ | |
400 | this->ike_sa = ike_sa; | |
aebb38a0 | 401 | this->prf = this->ike_sa->get_prf(this->ike_sa); |
5113680f | 402 | this->logger = logger_manager->get_logger(logger_manager, IKE_SA); |
ebae15f0 | 403 | |
dec59822 | 404 | return &(this->public); |
ebae15f0 | 405 | } |