X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilcske%2Fsilcconnauth.c;h=d44e9faf35d7354fdb4632267f405ddd16cd2d4b;hp=ecd515f084363d3f097dcfa442e60fba27a19132;hb=805fddcf6431e784f9f77114782a90c9d12f9cbe;hpb=8fd8212bcd16f2b53fbedff2a9b9a4e8c15b9695 diff --git a/lib/silcske/silcconnauth.c b/lib/silcske/silcconnauth.c index ecd515f0..d44e9faf 100644 --- a/lib/silcske/silcconnauth.c +++ b/lib/silcske/silcconnauth.c @@ -22,6 +22,16 @@ /************************** Types and definitions ***************************/ +SILC_FSM_STATE(silc_connauth_st_initiator_start); +SILC_FSM_STATE(silc_connauth_st_initiator_auth_send); +SILC_FSM_STATE(silc_connauth_st_initiator_result); +SILC_FSM_STATE(silc_connauth_st_initiator_failure); +SILC_FSM_STATE(silc_connauth_st_responder_start); +SILC_FSM_STATE(silc_connauth_st_responder_authenticate); +SILC_FSM_STATE(silc_connauth_st_responder_authenticate_pk); +SILC_FSM_STATE(silc_connauth_st_responder_success); +SILC_FSM_STATE(silc_connauth_st_responder_failure); + static SilcBool silc_connauth_packet_receive(SilcPacketEngine engine, SilcPacketStream stream, SilcPacket packet, @@ -33,6 +43,7 @@ struct SilcConnAuthStruct { SilcSKE ske; SilcFSM fsm; SilcAsyncOperationStruct op; + SilcAsyncOperation key_op; SilcConnectionType conn_type; SilcAuthMethod auth_method; void *auth_data; @@ -76,19 +87,44 @@ static SilcBool silc_connauth_packet_receive(SilcPacketEngine engine, static void silc_connauth_abort(SilcAsyncOperation op, void *context) { SilcConnAuth connauth = context; + if (connauth->key_op) + silc_async_abort(connauth->key_op, NULL, NULL); connauth->aborted = TRUE; } +/* Signature callback */ + +static void silc_connauth_get_signature_cb(SilcBool success, + const unsigned char *signature, + SilcUInt32 signature_len, + void *context) +{ + SilcConnAuth connauth = context; + + connauth->key_op = NULL; + + if (!success) { + silc_fsm_next(connauth->fsm, silc_connauth_st_initiator_failure); + SILC_FSM_CALL_CONTINUE(connauth->fsm); + return; + } + + connauth->auth_data = silc_memdup(signature, signature_len); + connauth->auth_data_len = signature_len; + + SILC_FSM_CALL_CONTINUE(connauth->fsm); +} + /* Generates signature for public key based authentication */ -static SilcBool silc_connauth_get_signature(SilcConnAuth connauth, - unsigned char **auth_data, - SilcUInt32 *auth_data_len) +static SilcAsyncOperation +silc_connauth_get_signature(SilcConnAuth connauth) { - int len; + SilcAsyncOperation op; SilcSKE ske; SilcPrivateKey private_key; SilcBuffer auth; + int len; SILC_LOG_DEBUG(("Compute signature")); @@ -99,54 +135,73 @@ static SilcBool silc_connauth_get_signature(SilcConnAuth connauth, KE Start Payload. */ len = ske->hash_len + silc_buffer_len(ske->start_payload_copy); auth = silc_buffer_alloc_size(len); - if (!auth) - return FALSE; + if (!auth) { + silc_connauth_get_signature_cb(FALSE, NULL, 0, connauth); + return NULL; + } silc_buffer_format(auth, - SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len), - SILC_STR_UI_XNSTRING( - ske->start_payload_copy->data, - silc_buffer_len(ske->start_payload_copy)), + SILC_STR_DATA(ske->hash, ske->hash_len), + SILC_STR_DATA(ske->start_payload_copy->data, + silc_buffer_len(ske->start_payload_copy)), SILC_STR_END); - len = ((silc_pkcs_private_key_get_len(private_key) + 7) / 8) + 1; - *auth_data = silc_calloc(len, sizeof(**auth_data)); - if (*auth_data == NULL) { - silc_buffer_free(auth); - return FALSE; - } - /* Compute signature */ - if (!silc_pkcs_sign(private_key, auth->data, silc_buffer_len(auth), - *auth_data, len, auth_data_len, TRUE, ske->prop->hash)) { - silc_free(*auth_data); - silc_buffer_free(auth); - return FALSE; - } + op = silc_pkcs_sign_async(private_key, auth->data, silc_buffer_len(auth), + TRUE, ske->prop->hash, ske->rng, + silc_connauth_get_signature_cb, connauth); silc_buffer_free(auth); - return TRUE; + + return op; +} + +/* Verify callback */ + +static void silc_connauth_verify_signature_cb(SilcBool success, + void *context) +{ + SilcConnAuth connauth = context; + + connauth->key_op = NULL; + silc_free(connauth->auth_data); + + if (!success) { + SILC_LOG_DEBUG(("Invalid signature")); + silc_fsm_next(connauth->fsm, silc_connauth_st_responder_failure); + SILC_FSM_CALL_CONTINUE(connauth->fsm); + return; + } + + SILC_LOG_DEBUG(("Signature is Ok")); + SILC_FSM_CALL_CONTINUE(connauth->fsm); } /* Verifies digital signature */ -static SilcBool silc_connauth_verify_signature(SilcConnAuth connauth, - SilcPublicKey pub_key, - unsigned char *sign, - SilcUInt32 sign_len) +static SilcAsyncOperation +silc_connauth_verify_signature(SilcConnAuth connauth, + SilcPublicKey pub_key, + unsigned char *sign, + SilcUInt32 sign_len) { - int len; + SilcAsyncOperation op; SilcBuffer auth; SilcSKE ske = connauth->ske; + int len; - if (!pub_key || !sign) - return FALSE; + if (!pub_key || !sign) { + silc_connauth_verify_signature_cb(FALSE, connauth); + return NULL; + } /* Make the authentication data. Protocol says it is HASH plus KE Start Payload. */ len = ske->hash_len + silc_buffer_len(ske->start_payload_copy); auth = silc_buffer_alloc_size(len); - if (!auth) - return FALSE; + if (!auth) { + silc_connauth_verify_signature_cb(FALSE, connauth); + return NULL; + } silc_buffer_format(auth, SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len), SILC_STR_UI_XNSTRING( @@ -155,15 +210,13 @@ static SilcBool silc_connauth_verify_signature(SilcConnAuth connauth, SILC_STR_END); /* Verify signature */ - if (!silc_pkcs_verify(pub_key, sign, sign_len, auth->data, - silc_buffer_len(auth), ske->prop->hash)) { - silc_buffer_free(auth); - return FALSE; - } + op = silc_pkcs_verify_async(pub_key, sign, sign_len, auth->data, + silc_buffer_len(auth), TRUE, ske->prop->hash, + silc_connauth_verify_signature_cb, connauth); silc_buffer_free(auth); - return TRUE; + return op; } /* Timeout */ @@ -172,6 +225,8 @@ SILC_TASK_CALLBACK(silc_connauth_timeout) { SilcConnAuth connauth = context; SILC_LOG_DEBUG(("Protocol timeout")); + if (connauth->key_op) + silc_async_abort(connauth->key_op, NULL, NULL); connauth->aborted = TRUE; silc_fsm_continue_sync(connauth->fsm); } @@ -255,18 +310,9 @@ SilcSKE silc_connauth_get_ske(SilcConnAuth connauth) /******************************** Initiator *********************************/ -SILC_FSM_STATE(silc_connauth_st_initiator_start); -SILC_FSM_STATE(silc_connauth_st_initiator_result); -SILC_FSM_STATE(silc_connauth_st_initiator_failure); - SILC_FSM_STATE(silc_connauth_st_initiator_start) { SilcConnAuth connauth = fsm_context; - SilcBuffer packet; - int payload_len = 0; - unsigned char *auth_data = NULL; - SilcUInt32 auth_data_len = 0; - SilcPacketFlags flags = 0; SILC_LOG_DEBUG(("Start")); @@ -282,32 +328,45 @@ SILC_FSM_STATE(silc_connauth_st_initiator_start) silc_connauth_timeout, connauth, connauth->timeout_secs, 0); + /** Generate auth data */ + silc_fsm_next(fsm, silc_connauth_st_initiator_auth_send); + + /* Get authentication data */ switch (connauth->auth_method) { case SILC_AUTH_NONE: /* No authentication required */ + connauth->auth_data = NULL; + connauth->auth_data_len = 0; + return SILC_FSM_CONTINUE; break; case SILC_AUTH_PASSWORD: - auth_data = silc_memdup(connauth->auth_data, connauth->auth_data_len); - if (!auth_data) { - /** Out of memory */ - silc_fsm_next(fsm, silc_connauth_st_initiator_failure); - return SILC_FSM_CONTINUE; - } - auth_data_len = connauth->auth_data_len; - flags = SILC_PACKET_FLAG_LONG_PAD; + /* We have authentication data already */ + return SILC_FSM_CONTINUE; break; case SILC_AUTH_PUBLIC_KEY: - if (!silc_connauth_get_signature(connauth, &auth_data, &auth_data_len)) { - /** Error computing signature */ - silc_fsm_next(fsm, silc_connauth_st_initiator_failure); - return SILC_FSM_CONTINUE; - } + /* Compute signature */ + SILC_FSM_CALL(connauth->key_op = silc_connauth_get_signature(connauth)); + /* NOT REACHED */ break; } - payload_len = 4 + auth_data_len; + silc_fsm_next(fsm, silc_connauth_st_initiator_failure); + return SILC_FSM_CONTINUE; +} + +SILC_FSM_STATE(silc_connauth_st_initiator_auth_send) +{ + SilcConnAuth connauth = fsm_context; + SilcBuffer packet; + int payload_len ; + SilcPacketFlags flags = 0; + + if (connauth->auth_method == SILC_AUTH_PASSWORD) + flags |= SILC_PACKET_FLAG_LONG_PAD; + + payload_len = 4 + connauth->auth_data_len; packet = silc_buffer_alloc_size(payload_len); if (!packet) { /** Out of memory */ @@ -318,9 +377,12 @@ SILC_FSM_STATE(silc_connauth_st_initiator_start) silc_buffer_format(packet, SILC_STR_UI_SHORT(payload_len), SILC_STR_UI_SHORT(connauth->conn_type), - SILC_STR_UI_XNSTRING(auth_data, auth_data_len), + SILC_STR_DATA(connauth->auth_data, + connauth->auth_data_len), SILC_STR_END); + silc_free(connauth->auth_data); + /* Send the packet */ if (!silc_packet_send(connauth->ske->stream, SILC_PACKET_CONNECTION_AUTH, flags, packet->data, silc_buffer_len(packet))) { @@ -329,10 +391,6 @@ SILC_FSM_STATE(silc_connauth_st_initiator_start) return SILC_FSM_CONTINUE; } - if (auth_data) { - memset(auth_data, 0, auth_data_len); - silc_free(auth_data); - } silc_buffer_free(packet); /** Wait for responder */ @@ -357,7 +415,8 @@ SILC_FSM_STATE(silc_connauth_st_initiator_result) SILC_LOG_DEBUG(("Authentication successful")); connauth->success = TRUE; } else { - SILC_LOG_DEBUG(("Authentication failed")); + SILC_LOG_DEBUG(("Authentication failed, packet %s received", + silc_get_packet_name(connauth->packet->type))); connauth->success = FALSE; } silc_packet_free(connauth->packet); @@ -384,8 +443,13 @@ SILC_FSM_STATE(silc_connauth_st_initiator_failure) SILC_PUT32_MSB(SILC_AUTH_FAILED, error); silc_packet_send(connauth->ske->stream, SILC_PACKET_FAILURE, 0, error, 4); + silc_packet_stream_unlink(connauth->ske->stream, + &silc_connauth_stream_cbs, connauth); + silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth); + /* Call completion callback */ connauth->completion(connauth, FALSE, connauth->context); + return SILC_FSM_FINISH; } silc_packet_stream_unlink(connauth->ske->stream, @@ -417,10 +481,14 @@ silc_connauth_initiator(SilcConnAuth connauth, connauth->conn_type = conn_type; connauth->auth_method = auth_method; - connauth->auth_data = auth_data; - connauth->auth_data_len = auth_data_len; connauth->completion = completion; connauth->context = context; + connauth->auth_data = auth_data; + connauth->auth_data_len = auth_data_len; + + if (connauth->auth_method == SILC_AUTH_PASSWORD) + connauth->auth_data = silc_memdup(connauth->auth_data, + connauth->auth_data_len); /* Link to packet stream to get packets */ silc_packet_stream_link(connauth->ske->stream, @@ -438,12 +506,6 @@ silc_connauth_initiator(SilcConnAuth connauth, /******************************** Responder *********************************/ -SILC_FSM_STATE(silc_connauth_st_responder_start); -SILC_FSM_STATE(silc_connauth_st_responder_authenticate); -SILC_FSM_STATE(silc_connauth_st_responder_authenticate_pk); -SILC_FSM_STATE(silc_connauth_st_responder_success); -SILC_FSM_STATE(silc_connauth_st_responder_failure); - SILC_FSM_STATE(silc_connauth_st_responder_start) { SilcConnAuth connauth = fsm_context; @@ -481,7 +543,8 @@ SILC_FSM_STATE(silc_connauth_st_responder_authenticate) if (connauth->aborted) { /** Aborted */ - silc_packet_free(connauth->packet); + if (connauth->packet) + silc_packet_free(connauth->packet); silc_fsm_next(fsm, silc_connauth_st_responder_failure); return SILC_FSM_CONTINUE; } @@ -560,7 +623,8 @@ SILC_FSM_STATE(silc_connauth_st_responder_authenticate) /* Passphrase authentication */ if (passphrase && passphrase_len) { SILC_LOG_DEBUG(("Passphrase authentication")); - if (!memcmp(auth_data, passphrase, passphrase_len)) { + if (!auth_data || payload_len != passphrase_len || + memcmp(auth_data, passphrase, passphrase_len)) { /** Authentication failed */ silc_fsm_next(fsm, silc_connauth_st_responder_failure); return SILC_FSM_CONTINUE; @@ -571,26 +635,35 @@ SILC_FSM_STATE(silc_connauth_st_responder_authenticate) SILC_LOG_DEBUG(("Digital signature authentication")); + if (!auth_data) { + /** Authentication failed */ + silc_fsm_next(fsm, silc_connauth_st_responder_failure); + return SILC_FSM_CONTINUE; + } + connauth->auth_data = silc_memdup(auth_data, payload_len); connauth->auth_data_len = payload_len; /* Allocate search constraints for finding the key */ find = silc_skr_find_alloc(); - if (!find || !connauth->auth_data) { + if (!find || !connauth->auth_data || !connauth->ske->prop->public_key) { /** Out of memory */ silc_fsm_next(fsm, silc_connauth_st_responder_failure); return SILC_FSM_CONTINUE; } - silc_skr_find_set_pkcs_type(find, connauth->ske->pk_type); - silc_skr_find_set_public_key(find, connauth->ske->public_key); + silc_skr_find_set_pkcs_type( + find, silc_pkcs_get_type(connauth->ske->prop->public_key)); + silc_skr_find_set_public_key(find, connauth->ske->prop->public_key); silc_skr_find_set_usage(find, (SILC_SKR_USAGE_AUTH | SILC_SKR_USAGE_KEY_AGREEMENT)); /** Find public key */ silc_fsm_next(fsm, silc_connauth_st_responder_authenticate_pk); - SILC_FSM_CALL(silc_skr_find(repository, find, silc_connauth_skr_callback, + SILC_FSM_CALL(connauth->key_op = + silc_skr_find(repository, silc_fsm_get_schedule(fsm), + find, silc_connauth_skr_callback, connauth)); /* NOT REACHED */ } @@ -623,23 +696,16 @@ SILC_FSM_STATE(silc_connauth_st_responder_authenticate_pk) SILC_LOG_DEBUG(("Found %d public keys", silc_dlist_count(connauth->public_keys))); - /* Verify signature */ + /** Verify signature */ key = silc_dlist_get(connauth->public_keys); - if (!silc_connauth_verify_signature(connauth, key->key, - connauth->auth_data, - connauth->auth_data_len)) { - /** Invalid signature */ - SILC_LOG_DEBUG(("Invalid signature")); - silc_free(connauth->auth_data); - silc_fsm_next(fsm, silc_connauth_st_responder_failure); - return SILC_FSM_CONTINUE; - } - - silc_free(connauth->auth_data); - - /** Authentication successful */ silc_fsm_next(fsm, silc_connauth_st_responder_success); - return SILC_FSM_CONTINUE; + SILC_FSM_CALL(connauth->key_op = + silc_connauth_verify_signature(connauth, key->key, + connauth->auth_data, + connauth->auth_data_len)); + /* NOT REACHED */ + + SILC_LOG_DEBUG(("Signature is Ok")); } SILC_FSM_STATE(silc_connauth_st_responder_success) @@ -653,13 +719,13 @@ SILC_FSM_STATE(silc_connauth_st_responder_success) SILC_PUT32_MSB(SILC_AUTH_OK, tmp); silc_packet_send(connauth->ske->stream, SILC_PACKET_SUCCESS, 0, tmp, 4); - /* Call completion callback */ - connauth->completion(connauth, TRUE, connauth->context); - silc_packet_stream_unlink(connauth->ske->stream, &silc_connauth_stream_cbs, connauth); silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth); + /* Call completion callback */ + connauth->completion(connauth, TRUE, connauth->context); + return SILC_FSM_FINISH; } @@ -675,8 +741,14 @@ SILC_FSM_STATE(silc_connauth_st_responder_failure) SILC_PUT32_MSB(SILC_AUTH_FAILED, error); silc_packet_send(connauth->ske->stream, SILC_PACKET_FAILURE, 0, error, 4); + silc_packet_stream_unlink(connauth->ske->stream, + &silc_connauth_stream_cbs, connauth); + silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth); + /* Call completion callback */ connauth->completion(connauth, FALSE, connauth->context); + + return SILC_FSM_FINISH; } silc_packet_stream_unlink(connauth->ske->stream,