5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2005 - 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcconnauth.h"
23 /************************** Types and definitions ***************************/
25 static SilcBool silc_connauth_packet_receive(SilcPacketEngine engine,
26 SilcPacketStream stream,
28 void *callback_context,
31 /* Connection authentication context */
32 struct SilcConnAuthStruct {
35 SilcConnectionType conn_type;
36 SilcAuthMethod auth_method;
38 SilcUInt32 auth_data_len;
39 SilcConnAuthCompletion completion;
40 SilcConnAuthGetAuthData get_auth_data;
42 SilcDList public_keys;
43 SilcSKRStatus skr_status;
44 SilcUInt32 timeout_secs;
46 unsigned int aborted : 1;
47 unsigned int success : 1;
50 /* Packet stream callbacks */
51 static SilcPacketCallbacks silc_connauth_stream_cbs =
53 silc_connauth_packet_receive, NULL, NULL
57 /************************ Static utility functions **************************/
61 static SilcBool silc_connauth_packet_receive(SilcPacketEngine engine,
62 SilcPacketStream stream,
64 void *callback_context,
67 SilcConnAuth connauth = callback_context;
68 connauth->packet = packet;
69 silc_fsm_continue(connauth->fsm);
73 /* Async operation abortion callback */
75 static void silc_connauth_abort(SilcAsyncOperation op, void *context)
77 SilcConnAuth connauth = context;
78 connauth->aborted = TRUE;
81 /* Generates signature for public key based authentication */
83 static SilcBool silc_connauth_get_signature(SilcConnAuth connauth,
84 unsigned char **auth_data,
85 SilcUInt32 *auth_data_len)
89 SilcPrivateKey private_key;
92 SILC_LOG_DEBUG(("Compute signature"));
95 private_key = connauth->auth_data;
97 /* Make the authentication data. Protocol says it is HASH plus
99 len = ske->hash_len + silc_buffer_len(ske->start_payload_copy);
100 auth = silc_buffer_alloc_size(len);
103 silc_buffer_format(auth,
104 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
105 SILC_STR_UI_XNSTRING(
106 ske->start_payload_copy->data,
107 silc_buffer_len(ske->start_payload_copy)),
110 len = ((silc_pkcs_private_key_get_len(private_key) + 7) / 8) + 1;
111 *auth_data = silc_calloc(len, sizeof(**auth_data));
112 if (*auth_data == NULL) {
113 silc_buffer_free(auth);
117 /* Compute signature */
118 if (!silc_pkcs_sign(private_key, auth->data, silc_buffer_len(auth),
119 *auth_data, len, auth_data_len, TRUE, ske->prop->hash)) {
120 silc_free(*auth_data);
121 silc_buffer_free(auth);
125 silc_buffer_free(auth);
129 /* Verifies digital signature */
131 static SilcBool silc_connauth_verify_signature(SilcConnAuth connauth,
132 SilcPublicKey pub_key,
138 SilcSKE ske = connauth->ske;
140 if (!pub_key || !sign)
143 /* Make the authentication data. Protocol says it is HASH plus
145 len = ske->hash_len + silc_buffer_len(ske->start_payload_copy);
146 auth = silc_buffer_alloc_size(len);
149 silc_buffer_format(auth,
150 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
151 SILC_STR_UI_XNSTRING(
152 ske->start_payload_copy->data,
153 silc_buffer_len(ske->start_payload_copy)),
156 /* Verify signature */
157 if (!silc_pkcs_verify(pub_key, sign, sign_len, auth->data,
158 silc_buffer_len(auth), ske->prop->hash)) {
159 silc_buffer_free(auth);
163 silc_buffer_free(auth);
170 SILC_TASK_CALLBACK(silc_connauth_timeout)
172 SilcConnAuth connauth = context;
173 SILC_LOG_DEBUG(("Protocol timeout"));
174 connauth->aborted = TRUE;
175 silc_fsm_continue_sync(connauth->fsm);
180 static void silc_connauth_skr_callback(SilcSKR skr, SilcSKRFind find,
181 SilcSKRStatus status,
182 SilcDList results, void *context)
184 SilcConnAuth connauth = context;
186 silc_skr_find_free(find);
188 connauth->public_keys = results;
189 connauth->skr_status = status;
191 SILC_FSM_CALL_CONTINUE(connauth->fsm);
196 static void silc_connauth_fsm_destructor(SilcFSM fsm, void *fsm_context,
197 void *destructor_context)
203 /******************************* Protocol API *******************************/
205 /* Allocate connection authentication context */
207 SilcConnAuth silc_connauth_alloc(SilcSchedule schedule,
209 SilcUInt32 timeout_secs)
211 SilcConnAuth connauth;
213 if (!schedule || !ske)
216 connauth = silc_calloc(1, sizeof(*connauth));
220 connauth->fsm = silc_fsm_alloc(connauth, silc_connauth_fsm_destructor,
222 if (!connauth->fsm) {
223 silc_connauth_free(connauth);
227 connauth->timeout_secs = timeout_secs;
233 /* Free connection authentication context */
235 void silc_connauth_free(SilcConnAuth connauth)
237 if (connauth->public_keys)
238 silc_dlist_uninit(connauth->public_keys);
242 /* Return associated SKE context */
244 SilcSKE silc_connauth_get_ske(SilcConnAuth connauth)
246 return connauth->ske;
250 /******************************** Initiator *********************************/
252 SILC_FSM_STATE(silc_connauth_st_initiator_start);
253 SILC_FSM_STATE(silc_connauth_st_initiator_result);
254 SILC_FSM_STATE(silc_connauth_st_initiator_failure);
256 SILC_FSM_STATE(silc_connauth_st_initiator_start)
258 SilcConnAuth connauth = fsm_context;
261 unsigned char *auth_data = NULL;
262 SilcUInt32 auth_data_len = 0;
263 SilcPacketFlags flags = 0;
265 SILC_LOG_DEBUG(("Start"));
267 if (connauth->aborted) {
269 silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
270 return SILC_FSM_CONTINUE;
274 if (connauth->timeout_secs)
275 silc_schedule_task_add_timeout(silc_fsm_get_schedule(fsm),
276 silc_connauth_timeout, connauth,
277 connauth->timeout_secs, 0);
279 switch (connauth->auth_method) {
281 /* No authentication required */
284 case SILC_AUTH_PASSWORD:
285 auth_data = silc_memdup(connauth->auth_data, connauth->auth_data_len);
288 silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
289 return SILC_FSM_CONTINUE;
291 auth_data_len = connauth->auth_data_len;
292 flags = SILC_PACKET_FLAG_LONG_PAD;
295 case SILC_AUTH_PUBLIC_KEY:
296 if (!silc_connauth_get_signature(connauth, &auth_data, &auth_data_len)) {
297 /** Error computing signature */
298 silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
299 return SILC_FSM_CONTINUE;
304 payload_len = 4 + auth_data_len;
305 packet = silc_buffer_alloc_size(payload_len);
308 silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
309 return SILC_FSM_CONTINUE;
312 silc_buffer_format(packet,
313 SILC_STR_UI_SHORT(payload_len),
314 SILC_STR_UI_SHORT(connauth->conn_type),
315 SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
318 /* Send the packet */
319 if (!silc_packet_send(connauth->ske->stream, SILC_PACKET_CONNECTION_AUTH,
320 flags, packet->data, silc_buffer_len(packet))) {
321 /** Error sending packet */
322 silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
323 return SILC_FSM_CONTINUE;
327 memset(auth_data, 0, auth_data_len);
328 silc_free(auth_data);
330 silc_buffer_free(packet);
332 /** Wait for responder */
333 silc_fsm_next(fsm, silc_connauth_st_initiator_result);
334 return SILC_FSM_WAIT;
337 SILC_FSM_STATE(silc_connauth_st_initiator_result)
339 SilcConnAuth connauth = fsm_context;
341 SILC_LOG_DEBUG(("Start"));
343 if (connauth->aborted) {
345 silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
346 return SILC_FSM_CONTINUE;
349 /* Check the status of authentication */
350 if (connauth->packet->type == SILC_PACKET_SUCCESS) {
351 SILC_LOG_DEBUG(("Authentication successful"));
352 connauth->success = TRUE;
354 SILC_LOG_DEBUG(("Authentication failed"));
355 connauth->success = FALSE;
357 silc_packet_free(connauth->packet);
359 silc_packet_stream_unlink(connauth->ske->stream,
360 &silc_connauth_stream_cbs, connauth);
361 silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
363 /* Call completion callback */
364 connauth->completion(connauth, connauth->success, connauth->context);
366 return SILC_FSM_FINISH;
369 SILC_FSM_STATE(silc_connauth_st_initiator_failure)
371 SilcConnAuth connauth = fsm_context;
372 unsigned char error[4];
374 SILC_LOG_DEBUG(("Start"));
376 /* Send FAILURE packet */
377 SILC_PUT32_MSB(SILC_AUTH_FAILED, error);
378 silc_packet_send(connauth->ske->stream, SILC_PACKET_FAILURE, 0, error, 4);
380 /* Call completion callback */
381 connauth->completion(connauth, FALSE, connauth->context);
383 silc_packet_stream_unlink(connauth->ske->stream,
384 &silc_connauth_stream_cbs, connauth);
385 silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
387 return SILC_FSM_FINISH;
391 silc_connauth_initiator(SilcConnAuth connauth,
392 SilcConnectionType conn_type,
393 SilcAuthMethod auth_method, void *auth_data,
394 SilcUInt32 auth_data_len,
395 SilcConnAuthCompletion completion,
398 SilcAsyncOperation op;
400 SILC_LOG_DEBUG(("Connection authentication as initiator"));
402 if (auth_method == SILC_AUTH_PASSWORD && !auth_data) {
403 completion(connauth, FALSE, context);
407 if (auth_method == SILC_AUTH_PUBLIC_KEY && !auth_data) {
408 completion(connauth, FALSE, context);
412 connauth->conn_type = conn_type;
413 connauth->auth_method = auth_method;
414 connauth->auth_data = auth_data;
415 connauth->auth_data_len = auth_data_len;
416 connauth->completion = completion;
417 connauth->context = context;
419 /* Link to packet stream to get packets */
420 silc_packet_stream_link(connauth->ske->stream,
421 &silc_connauth_stream_cbs, connauth, 1000000,
423 SILC_PACKET_FAILURE, -1);
425 /* Start the protocol */
426 op = silc_async_alloc(silc_connauth_abort, NULL, connauth);
427 silc_fsm_start(connauth->fsm, silc_connauth_st_initiator_start);
433 /******************************** Responder *********************************/
435 SILC_FSM_STATE(silc_connauth_st_responder_start);
436 SILC_FSM_STATE(silc_connauth_st_responder_authenticate);
437 SILC_FSM_STATE(silc_connauth_st_responder_authenticate_pk);
438 SILC_FSM_STATE(silc_connauth_st_responder_success);
439 SILC_FSM_STATE(silc_connauth_st_responder_failure);
441 SILC_FSM_STATE(silc_connauth_st_responder_start)
443 SilcConnAuth connauth = fsm_context;
445 SILC_LOG_DEBUG(("Start"));
447 if (connauth->aborted) {
449 silc_fsm_next(fsm, silc_connauth_st_responder_failure);
450 return SILC_FSM_CONTINUE;
454 if (connauth->timeout_secs)
455 silc_schedule_task_add_timeout(silc_fsm_get_schedule(fsm),
456 silc_connauth_timeout, connauth,
457 connauth->timeout_secs, 0);
459 /** Wait for initiator */
460 silc_fsm_next(fsm, silc_connauth_st_responder_authenticate);
461 return SILC_FSM_WAIT;
464 SILC_FSM_STATE(silc_connauth_st_responder_authenticate)
466 SilcConnAuth connauth = fsm_context;
467 SilcUInt16 payload_len;
468 SilcUInt16 conn_type;
469 unsigned char *auth_data = NULL, *passphrase = NULL;
470 SilcUInt32 passphrase_len;
471 SilcSKR repository = NULL;
474 SILC_LOG_DEBUG(("Start"));
476 if (connauth->aborted) {
478 silc_packet_free(connauth->packet);
479 silc_fsm_next(fsm, silc_connauth_st_responder_failure);
480 return SILC_FSM_CONTINUE;
483 if (connauth->packet->type != SILC_PACKET_CONNECTION_AUTH) {
484 /** Protocol failure */
485 silc_packet_free(connauth->packet);
486 silc_fsm_next(fsm, silc_connauth_st_responder_failure);
487 return SILC_FSM_CONTINUE;
490 /* Parse the received authentication data packet. The received
491 payload is Connection Auth Payload. */
492 ret = silc_buffer_unformat(&connauth->packet->buffer,
493 SILC_STR_UI_SHORT(&payload_len),
494 SILC_STR_UI_SHORT(&conn_type),
498 SILC_LOG_ERROR(("Bad payload in authentication packet"));
499 silc_packet_free(connauth->packet);
500 silc_fsm_next(fsm, silc_connauth_st_responder_failure);
501 return SILC_FSM_CONTINUE;
504 if (payload_len != silc_buffer_len(&connauth->packet->buffer)) {
505 /** Bad payload length */
506 SILC_LOG_ERROR(("Bad payload length in authentication packet"));
507 silc_packet_free(connauth->packet);
508 silc_fsm_next(fsm, silc_connauth_st_responder_failure);
509 return SILC_FSM_CONTINUE;
514 if (conn_type < SILC_CONN_CLIENT || conn_type > SILC_CONN_ROUTER) {
515 /** Bad connection type */
516 SILC_LOG_ERROR(("Bad connection type (%d) in authentication packet",
518 silc_packet_free(connauth->packet);
519 silc_fsm_next(fsm, silc_connauth_st_responder_failure);
520 return SILC_FSM_CONTINUE;
523 if (payload_len > 0) {
524 /* Get authentication data */
525 ret = silc_buffer_unformat(&connauth->packet->buffer,
527 SILC_STR_UI_XNSTRING(&auth_data,
532 SILC_LOG_DEBUG(("Bad payload in authentication payload"));
533 silc_packet_free(connauth->packet);
534 silc_fsm_next(fsm, silc_connauth_st_responder_failure);
535 return SILC_FSM_CONTINUE;
538 silc_packet_free(connauth->packet);
540 SILC_LOG_DEBUG(("Remote connection type %d", conn_type));
542 /* Get authentication data */
543 if (!connauth->get_auth_data(connauth, conn_type, &passphrase,
544 &passphrase_len, &repository,
545 connauth->context)) {
546 /** Connection not configured */
547 SILC_LOG_ERROR(("Remote connection not configured"));
548 silc_fsm_next(fsm, silc_connauth_st_responder_failure);
549 return SILC_FSM_CONTINUE;
554 /* Passphrase authentication */
555 if (passphrase && passphrase_len) {
556 SILC_LOG_DEBUG(("Passphrase authentication"));
557 if (!memcmp(auth_data, passphrase, passphrase_len)) {
558 /** Authentication failed */
559 silc_fsm_next(fsm, silc_connauth_st_responder_failure);
560 return SILC_FSM_CONTINUE;
562 } else if (repository) {
563 /* Digital signature */
566 SILC_LOG_DEBUG(("Digital signature authentication"));
568 connauth->auth_data = silc_memdup(auth_data, payload_len);
569 connauth->auth_data_len = payload_len;
571 /* Allocate search constraints for finding the key */
572 find = silc_skr_find_alloc();
574 if (!find || !connauth->auth_data) {
576 silc_fsm_next(fsm, silc_connauth_st_responder_failure);
577 return SILC_FSM_CONTINUE;
580 silc_skr_find_set_pkcs_type(find, connauth->ske->pk_type);
581 silc_skr_find_set_public_key(find, connauth->ske->public_key);
582 silc_skr_find_set_usage(find, (SILC_SKR_USAGE_AUTH |
583 SILC_SKR_USAGE_KEY_AGREEMENT));
585 /** Find public key */
586 silc_fsm_next(fsm, silc_connauth_st_responder_authenticate_pk);
587 SILC_FSM_CALL(silc_skr_find(repository, find, silc_connauth_skr_callback,
592 /* Passphrase auth Ok, or no authentication required */
594 /** Authentication successful */
595 silc_fsm_next(fsm, silc_connauth_st_responder_success);
596 return SILC_FSM_CONTINUE;
599 SILC_FSM_STATE(silc_connauth_st_responder_authenticate_pk)
601 SilcConnAuth connauth = fsm_context;
604 if (connauth->aborted) {
606 silc_fsm_next(fsm, silc_connauth_st_responder_failure);
607 return SILC_FSM_CONTINUE;
610 if (connauth->skr_status != SILC_SKR_OK) {
611 /** Public key not found */
612 SILC_LOG_DEBUG(("Public key not found, error %d", connauth->skr_status));
613 silc_fsm_next(fsm, silc_connauth_st_responder_failure);
614 return SILC_FSM_CONTINUE;
617 SILC_LOG_DEBUG(("Found %d public keys",
618 silc_dlist_count(connauth->public_keys)));
620 /* Verify signature */
621 key = silc_dlist_get(connauth->public_keys);
622 if (!silc_connauth_verify_signature(connauth, key->key,
624 connauth->auth_data_len)) {
625 /** Invalid signature */
626 SILC_LOG_DEBUG(("Invalid signature"));
627 silc_free(connauth->auth_data);
628 silc_fsm_next(fsm, silc_connauth_st_responder_failure);
629 return SILC_FSM_CONTINUE;
632 silc_free(connauth->auth_data);
634 /** Authentication successful */
635 silc_fsm_next(fsm, silc_connauth_st_responder_success);
636 return SILC_FSM_CONTINUE;
639 SILC_FSM_STATE(silc_connauth_st_responder_success)
641 SilcConnAuth connauth = fsm_context;
642 unsigned char tmp[4];
644 SILC_LOG_DEBUG(("Authentication successful"));
646 /* Send FAILURE packet */
647 SILC_PUT32_MSB(SILC_AUTH_OK, tmp);
648 silc_packet_send(connauth->ske->stream, SILC_PACKET_SUCCESS, 0, tmp, 4);
650 /* Call completion callback */
651 connauth->completion(connauth, TRUE, connauth->context);
653 silc_packet_stream_unlink(connauth->ske->stream,
654 &silc_connauth_stream_cbs, connauth);
655 silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
657 return SILC_FSM_FINISH;
660 SILC_FSM_STATE(silc_connauth_st_responder_failure)
662 SilcConnAuth connauth = fsm_context;
663 unsigned char error[4];
665 SILC_LOG_ERROR(("Authentication failed"));
667 /* Send FAILURE packet */
668 SILC_PUT32_MSB(SILC_AUTH_FAILED, error);
669 silc_packet_send(connauth->ske->stream, SILC_PACKET_FAILURE, 0, error, 4);
671 /* Call completion callback */
672 connauth->completion(connauth, FALSE, connauth->context);
674 silc_packet_stream_unlink(connauth->ske->stream,
675 &silc_connauth_stream_cbs, connauth);
676 silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
678 return SILC_FSM_FINISH;
682 silc_connauth_responder(SilcConnAuth connauth,
683 SilcConnAuthGetAuthData get_auth_data,
684 SilcConnAuthCompletion completion,
687 SilcAsyncOperation op;
689 SILC_LOG_DEBUG(("Connection authentication as responder"));
691 connauth->get_auth_data = get_auth_data;
692 connauth->completion = completion;
693 connauth->context = context;
695 /* Link to packet stream to get packets */
696 silc_packet_stream_link(connauth->ske->stream,
697 &silc_connauth_stream_cbs, connauth, 1000000,
698 SILC_PACKET_CONNECTION_AUTH,
699 SILC_PACKET_FAILURE, -1);
701 /* Start the protocol */
702 op = silc_async_alloc(silc_connauth_abort, NULL, connauth);
703 silc_fsm_start(connauth->fsm, silc_connauth_st_responder_start);