X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcske%2Fsilcske.c;h=4db209868986ccd79ca41180a0d734e9423479e4;hb=52e57c880aba9c5e89f59d962eb9af75670b76e0;hp=a726174339bde711d2108432905668a7fbc5fb37;hpb=fb1e58b1bc106212a845da866d0d4e9433c3ae22;p=silc.git diff --git a/lib/silcske/silcske.c b/lib/silcske/silcske.c index a7261743..4db20986 100644 --- a/lib/silcske/silcske.c +++ b/lib/silcske/silcske.c @@ -55,6 +55,10 @@ SILC_FSM_STATE(silc_ske_st_responder_error); SILC_FSM_STATE(silc_ske_st_rekey_initiator_start); SILC_FSM_STATE(silc_ske_st_rekey_initiator_done); SILC_FSM_STATE(silc_ske_st_rekey_initiator_end); +SILC_FSM_STATE(silc_ske_st_rekey_responder_wait); +SILC_FSM_STATE(silc_ske_st_rekey_responder_start); +SILC_FSM_STATE(silc_ske_st_rekey_responder_done); +SILC_FSM_STATE(silc_ske_st_rekey_responder_end); SILC_TASK_CALLBACK(silc_ske_packet_send_retry); SilcSKEKeyMaterial @@ -179,26 +183,16 @@ static void silc_ske_skr_callback(SilcSKR repository, static SilcSKEStatus silc_ske_check_version(SilcSKE ske) { SilcUInt32 r_software_version = 0; + char *r_software_string = NULL; if (!ske->remote_version || !ske->version) return SILC_SKE_STATUS_BAD_VERSION; if (!silc_parse_version_string(ske->remote_version, NULL, NULL, - &r_software_version, NULL, NULL)) + &r_software_version, + &r_software_string, NULL)) return SILC_SKE_STATUS_BAD_VERSION; - /* Backwards compatibility checks */ - - /* Old server versions requires "valid" looking Source ID in the SILC - packets during initial key exchange. All version before 1.1.0. */ - if (r_software_version < 110) { - SilcClientID id; - memset(&id, 0, sizeof(id)); - id.ip.data_len = 4; - SILC_LOG_DEBUG(("Remote is old version, add dummy Source ID to packets")); - silc_packet_set_ids(ske->stream, SILC_ID_CLIENT, &id, 0, NULL); - } - return SILC_SKE_STATUS_OK; } @@ -677,19 +671,23 @@ static SilcSKEStatus silc_ske_make_hash(SilcSKE ske, { SilcSKEStatus status = SILC_SKE_STATUS_OK; SilcBuffer buf; - unsigned char *e, *f, *KEY; - SilcUInt32 e_len, f_len, KEY_len; + unsigned char *e, *f, *KEY, *s_data; + SilcUInt32 e_len, f_len, KEY_len, s_len; int ret; SILC_LOG_DEBUG(("Start")); if (initiator == FALSE) { + s_data = (ske->start_payload_copy ? + silc_buffer_data(ske->start_payload_copy) : NULL); + s_len = (ske->start_payload_copy ? + silc_buffer_len(ske->start_payload_copy) : 0); e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len); f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len); KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len); /* Format the buffer used to compute the hash value */ - buf = silc_buffer_alloc_size(silc_buffer_len(ske->start_payload_copy) + + buf = silc_buffer_alloc_size(s_len + ske->ke2_payload->pk_len + ske->ke1_payload->pk_len + e_len + f_len + KEY_len); @@ -700,28 +698,24 @@ static SilcSKEStatus silc_ske_make_hash(SilcSKE ske, if (!ske->ke1_payload->pk_data) { ret = silc_buffer_format(buf, - SILC_STR_UI_XNSTRING( - ske->start_payload_copy->data, - silc_buffer_len(ske->start_payload_copy)), - SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data, - ske->ke2_payload->pk_len), - SILC_STR_UI_XNSTRING(e, e_len), - SILC_STR_UI_XNSTRING(f, f_len), - SILC_STR_UI_XNSTRING(KEY, KEY_len), + SILC_STR_DATA(s_data, s_len), + SILC_STR_DATA(ske->ke2_payload->pk_data, + ske->ke2_payload->pk_len), + SILC_STR_DATA(e, e_len), + SILC_STR_DATA(f, f_len), + SILC_STR_DATA(KEY, KEY_len), SILC_STR_END); } else { ret = silc_buffer_format(buf, - SILC_STR_UI_XNSTRING( - ske->start_payload_copy->data, - silc_buffer_len(ske->start_payload_copy)), - SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data, - ske->ke2_payload->pk_len), - SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data, - ske->ke1_payload->pk_len), - SILC_STR_UI_XNSTRING(e, e_len), - SILC_STR_UI_XNSTRING(f, f_len), - SILC_STR_UI_XNSTRING(KEY, KEY_len), + SILC_STR_DATA(s_data, s_len), + SILC_STR_DATA(ske->ke2_payload->pk_data, + ske->ke2_payload->pk_len), + SILC_STR_DATA(ske->ke1_payload->pk_data, + ske->ke1_payload->pk_len), + SILC_STR_DATA(e, e_len), + SILC_STR_DATA(f, f_len), + SILC_STR_DATA(KEY, KEY_len), SILC_STR_END); } if (ret == -1) { @@ -742,21 +736,23 @@ static SilcSKEStatus silc_ske_make_hash(SilcSKE ske, silc_free(f); silc_free(KEY); } else { + s_data = (ske->start_payload_copy ? + silc_buffer_data(ske->start_payload_copy) : NULL); + s_len = (ske->start_payload_copy ? + silc_buffer_len(ske->start_payload_copy) : 0); e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len); - buf = silc_buffer_alloc_size(silc_buffer_len(ske->start_payload_copy) + - ske->ke1_payload->pk_len + e_len); + buf = silc_buffer_alloc_size(s_len + ske->ke1_payload->pk_len + e_len); if (!buf) return SILC_SKE_STATUS_OUT_OF_MEMORY; /* Format the buffer used to compute the hash value */ ret = silc_buffer_format(buf, - SILC_STR_UI_XNSTRING(ske->start_payload_copy->data, - silc_buffer_len(ske->start_payload_copy)), - SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data, - ske->ke1_payload->pk_len), - SILC_STR_UI_XNSTRING(e, e_len), + SILC_STR_DATA(s_data, s_len), + SILC_STR_DATA(ske->ke1_payload->pk_data, + ske->ke1_payload->pk_len), + SILC_STR_DATA(e, e_len), SILC_STR_END); if (ret == -1) { silc_buffer_free(buf); @@ -1035,6 +1031,7 @@ SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule, ske->public_key = public_key; ske->private_key = private_key; ske->retry_timer = SILC_SKE_RETRY_MIN; + ske->refcnt = 1; return ske; } @@ -1064,6 +1061,10 @@ void silc_ske_free(SilcSKE ske) return; } + ske->refcnt--; + if (ske->refcnt > 0) + return; + /* Free start payload */ if (ske->start_payload) silc_ske_payload_start_free(ske->start_payload); @@ -1553,8 +1554,8 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase3) silc_skr_find_set_usage(find, SILC_SKR_USAGE_KEY_AGREEMENT); /* Find key from repository */ - SILC_FSM_CALL(silc_skr_find(ske->repository, find, - silc_ske_skr_callback, ske)); + SILC_FSM_CALL(silc_skr_find(ske->repository, silc_fsm_get_schedule(fsm), + find, silc_ske_skr_callback, ske)); } else { /* Verify from application */ SILC_FSM_CALL(ske->callbacks->verify_key(ske, ske->prop->public_key, @@ -1612,14 +1613,16 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase4) payload = ske->ke2_payload; + /* Compute the HASH value */ + SILC_LOG_DEBUG(("Computing HASH value")); + status = silc_ske_make_hash(ske, hash, &hash_len, FALSE); + if (status != SILC_SKE_STATUS_OK) + goto err; + ske->hash = silc_memdup(hash, hash_len); + ske->hash_len = hash_len; + if (ske->prop->public_key) { SILC_LOG_DEBUG(("Public key is authentic")); - - /* Compute the hash value */ - status = silc_ske_make_hash(ske, hash, &hash_len, FALSE); - if (status != SILC_SKE_STATUS_OK) - goto err; - SILC_LOG_DEBUG(("Verifying signature (HASH)")); /* Verify signature */ @@ -1631,9 +1634,6 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase4) } SILC_LOG_DEBUG(("Signature is Ok")); - - ske->hash = silc_memdup(hash, hash_len); - ske->hash_len = hash_len; memset(hash, 'F', hash_len); } @@ -1783,9 +1783,6 @@ SILC_FSM_STATE(silc_ske_st_initiator_failure) SilcSKE ske = fsm_context; SilcUInt32 error = SILC_SKE_STATUS_ERROR; - SILC_LOG_DEBUG(("Error %s (%d) received during key exchange", - silc_ske_map_status(ske->status), ske->status)); - if (ske->packet && silc_buffer_len(&ske->packet->buffer) == 4) { SILC_GET32_MSB(error, ske->packet->buffer.data); ske->status = error; @@ -1793,6 +1790,9 @@ SILC_FSM_STATE(silc_ske_st_initiator_failure) ske->packet = NULL; } + SILC_LOG_DEBUG(("Error %s (%d) received during key exchange", + silc_ske_map_status(ske->status), ske->status)); + silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske); silc_schedule_task_del_by_context(ske->schedule, ske); @@ -1885,6 +1885,7 @@ SILC_FSM_STATE(silc_ske_st_responder_phase1) SilcSKEStatus status; SilcSKEStartPayload remote_payload = NULL; SilcBuffer packet_buf = &ske->packet->buffer; + SilcID id; SILC_LOG_DEBUG(("Start")); @@ -1899,6 +1900,19 @@ SILC_FSM_STATE(silc_ske_st_responder_phase1) return SILC_FSM_CONTINUE; } + /* Get remote ID and set it to stream */ + if (ske->packet->src_id_len) { + silc_id_str2id(ske->packet->src_id, ske->packet->src_id_len, + ske->packet->src_id_type, + (ske->packet->src_id_type == SILC_ID_SERVER ? + (void *)&id.u.server_id : (void *)&id.u.client_id), + (ske->packet->src_id_type == SILC_ID_SERVER ? + sizeof(id.u.server_id) : sizeof(id.u.client_id))); + silc_packet_set_ids(ske->stream, 0, NULL, ske->packet->src_id_type, + (ske->packet->src_id_type == SILC_ID_SERVER ? + (void *)&id.u.server_id : (void *)&id.u.client_id)); + } + /* Take a copy of the payload buffer for future use. It is used to compute the HASH value. */ ske->start_payload_copy = silc_buffer_copy(packet_buf); @@ -2065,7 +2079,8 @@ SILC_FSM_STATE(silc_ske_st_responder_phase2) silc_skr_find_set_usage(find, SILC_SKR_USAGE_KEY_AGREEMENT); /* Find key from repository */ - SILC_FSM_CALL(silc_skr_find(ske->repository, find, + SILC_FSM_CALL(silc_skr_find(ske->repository, + silc_fsm_get_schedule(fsm), find, silc_ske_skr_callback, ske)); } else { /* Verify from application */ @@ -2209,22 +2224,23 @@ SILC_FSM_STATE(silc_ske_st_responder_phase5) } ske->ke2_payload->pk_data = pk; ske->ke2_payload->pk_len = pk_len; + } - SILC_LOG_DEBUG(("Computing HASH value")); - - /* Compute the hash value */ - memset(hash, 0, sizeof(hash)); - status = silc_ske_make_hash(ske, hash, &hash_len, FALSE); - if (status != SILC_SKE_STATUS_OK) { - /** Error computing hash */ - ske->status = status; - silc_fsm_next(fsm, silc_ske_st_responder_error); - return SILC_FSM_CONTINUE; - } + SILC_LOG_DEBUG(("Computing HASH value")); - ske->hash = silc_memdup(hash, hash_len); - ske->hash_len = hash_len; + /* Compute the hash value */ + memset(hash, 0, sizeof(hash)); + status = silc_ske_make_hash(ske, hash, &hash_len, FALSE); + if (status != SILC_SKE_STATUS_OK) { + /** Error computing hash */ + ske->status = status; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } + ske->hash = silc_memdup(hash, hash_len); + ske->hash_len = hash_len; + if (ske->public_key && ske->private_key) { SILC_LOG_DEBUG(("Signing HASH value")); /* Sign the hash value */ @@ -2262,6 +2278,13 @@ SILC_FSM_STATE(silc_ske_st_responder_phase5) silc_buffer_free(payload_buf); + /* In case we are doing rekey move to finish it. */ + if (ske->rekey) { + /** Finish rekey */ + silc_fsm_next(fsm, silc_ske_st_rekey_responder_done); + return SILC_FSM_CONTINUE; + } + /** Waiting completion */ silc_fsm_next(fsm, silc_ske_st_responder_end); return SILC_FSM_WAIT; @@ -2454,6 +2477,13 @@ SILC_FSM_STATE(silc_ske_st_rekey_initiator_start) return SILC_FSM_CONTINUE; } + if (!silc_hash_alloc(ske->rekey->hash, &ske->prop->hash)) { + /** Cannot allocate hash */ + ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; + } + /* Send REKEY packet to start rekey protocol */ if (!silc_ske_packet_send(ske, SILC_PACKET_REKEY, 0, NULL, 0)) { /** Error sending packet */ @@ -2499,13 +2529,7 @@ SILC_FSM_STATE(silc_ske_st_rekey_initiator_done) silc_packet_get_keys(ske->stream, &send_key, NULL, &hmac_send, NULL); key_len = silc_cipher_get_key_len(send_key); block_len = silc_cipher_get_block_len(send_key); - - if (!silc_hash_alloc(ske->rekey->hash, &hash)) { - /** Cannot allocate hash */ - ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY; - silc_fsm_next(fsm, silc_ske_st_initiator_error); - return SILC_FSM_CONTINUE; - } + hash = ske->prop->hash; hash_len = silc_hash_len(hash); /* Process key material */ @@ -2536,17 +2560,21 @@ SILC_FSM_STATE(silc_ske_st_rekey_initiator_done) ske->prop->cipher = send_key; ske->prop->hmac = hmac_send; - ske->prop->hash = hash; /* Get sending keys */ if (!silc_ske_set_keys(ske, ske->keymat, ske->prop, &send_key, NULL, &hmac_send, NULL, NULL)) { /** Cannot get keys */ ske->status = SILC_SKE_STATUS_ERROR; + ske->prop->cipher = NULL; + ske->prop->hmac = NULL; silc_fsm_next(fsm, silc_ske_st_initiator_error); return SILC_FSM_CONTINUE; } + ske->prop->cipher = NULL; + ske->prop->hmac = NULL; + /* Set the new keys into use. This will also send REKEY_DONE packet. Any packet sent after this call will be protected with the new keys. */ if (!silc_packet_set_keys(ske->stream, send_key, NULL, hmac_send, NULL, @@ -2554,6 +2582,8 @@ SILC_FSM_STATE(silc_ske_st_rekey_initiator_done) /** Cannot set keys */ SILC_LOG_DEBUG(("Cannot set new keys, error sending REKEY_DONE")); ske->status = SILC_SKE_STATUS_ERROR; + silc_cipher_free(send_key); + silc_hmac_free(hmac_send); silc_fsm_next(fsm, silc_ske_st_initiator_error); return SILC_FSM_CONTINUE; } @@ -2590,6 +2620,8 @@ SILC_FSM_STATE(silc_ske_st_rekey_initiator_end) NULL, &hmac_receive, NULL)) { /** Cannot get keys */ ske->status = SILC_SKE_STATUS_ERROR; + ske->prop->cipher = NULL; + ske->prop->hmac = NULL; silc_fsm_next(fsm, silc_ske_st_initiator_error); return SILC_FSM_CONTINUE; } @@ -2601,6 +2633,8 @@ SILC_FSM_STATE(silc_ske_st_rekey_initiator_end) /** Cannot set keys */ SILC_LOG_DEBUG(("Cannot set new keys")); ske->status = SILC_SKE_STATUS_ERROR; + silc_cipher_free(receive_key); + silc_hmac_free(hmac_receive); silc_fsm_next(fsm, silc_ske_st_initiator_error); return SILC_FSM_CONTINUE; } @@ -2612,6 +2646,8 @@ SILC_FSM_STATE(silc_ske_st_rekey_initiator_end) if (!rekey) { /** No memory */ ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY; + ske->prop->cipher = NULL; + ske->prop->hmac = NULL; silc_fsm_next(fsm, silc_ske_st_initiator_error); return SILC_FSM_CONTINUE; } @@ -2640,8 +2676,11 @@ silc_ske_rekey_initiator(SilcSKE ske, { SILC_LOG_DEBUG(("Start SKE rekey as initator")); - if (!ske || !stream || !rekey) + if (!ske || !stream || !rekey) { + SILC_LOG_ERROR(("Missing arguments to silc_ske_rekey_initiator")); + SILC_ASSERT(rekey); return NULL; + } if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske)) return NULL; @@ -2671,10 +2710,239 @@ silc_ske_rekey_initiator(SilcSKE ske, /***************************** Responder Rekey ******************************/ -SILC_FSM_STATE(silc_ske_st_rekey_responder_start); +/* Wait for initiator's packet */ + +SILC_FSM_STATE(silc_ske_st_rekey_responder_wait) +{ + SilcSKE ske = fsm_context; + + SILC_LOG_DEBUG(("Start rekey (%s)", ske->rekey->pfs ? "PFS" : "No PFS")); + + if (ske->aborted) { + /** Aborted */ + silc_fsm_next(fsm, silc_ske_st_responder_aborted); + return SILC_FSM_CONTINUE; + } + + /* Add rekey exchange timeout */ + silc_schedule_task_add_timeout(ske->schedule, silc_ske_timeout, + ske, 30, 0); + + silc_fsm_next(fsm, silc_ske_st_rekey_responder_start); + + /* If REKEY packet already received process it directly */ + if (ske->packet && ske->packet->type == SILC_PACKET_REKEY) + return SILC_FSM_CONTINUE; + + /* Wait for REKEY */ + return SILC_FSM_WAIT; +} + +/* Process initiator's REKEY packet */ SILC_FSM_STATE(silc_ske_st_rekey_responder_start) { + SilcSKE ske = fsm_context; + SilcSKEStatus status; + + SILC_LOG_DEBUG(("Start")); + + if (ske->packet->type != SILC_PACKET_REKEY) { + ske->status = SILC_SKE_STATUS_ERROR; + silc_packet_free(ske->packet); + ske->packet = NULL; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } + + ske->prop = silc_calloc(1, sizeof(*ske->prop)); + if (!ske->prop) { + /** No memory */ + ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } + + if (!silc_hash_alloc(ske->rekey->hash, &ske->prop->hash)) { + /** Cannot allocate hash */ + ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } + + /* If doing rekey without PFS, move directly to the end of the protocol. */ + if (!ske->rekey->pfs) { + /** Rekey without PFS */ + silc_fsm_next(fsm, silc_ske_st_rekey_responder_done); + return SILC_FSM_CONTINUE; + } + + status = silc_ske_group_get_by_number(ske->rekey->ske_group, + &ske->prop->group); + if (status != SILC_SKE_STATUS_OK) { + /** Unknown group */ + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } + + /** Rekey with PFS */ + silc_fsm_next(fsm, silc_ske_st_responder_phase2); + return SILC_FSM_WAIT; +} + +/* Sends REKEY_DONE packet to finish the protocol. */ + +SILC_FSM_STATE(silc_ske_st_rekey_responder_done) +{ + SilcSKE ske = fsm_context; + SilcCipher send_key; + SilcHmac hmac_send; + SilcHash hash; + SilcUInt32 key_len, block_len, hash_len, x_len; + unsigned char *pfsbuf; + + SILC_LOG_DEBUG(("Start")); + + silc_packet_get_keys(ske->stream, &send_key, NULL, &hmac_send, NULL); + key_len = silc_cipher_get_key_len(send_key); + block_len = silc_cipher_get_block_len(send_key); + hash = ske->prop->hash; + hash_len = silc_hash_len(hash); + + /* Process key material */ + if (ske->rekey->pfs) { + /* PFS */ + pfsbuf = silc_mp_mp2bin(ske->KEY, 0, &x_len); + if (pfsbuf) { + ske->keymat = silc_ske_process_key_material_data(pfsbuf, x_len, + block_len, key_len, + hash_len, hash); + memset(pfsbuf, 0, x_len); + silc_free(pfsbuf); + } + } else { + /* No PFS */ + ske->keymat = + silc_ske_process_key_material_data(ske->rekey->send_enc_key, + ske->rekey->enc_key_len / 8, + block_len, key_len, + hash_len, hash); + } + + if (!ske->keymat) { + SILC_LOG_ERROR(("Error processing key material")); + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } + + ske->prop->cipher = send_key; + ske->prop->hmac = hmac_send; + + /* Get sending keys */ + if (!silc_ske_set_keys(ske, ske->keymat, ske->prop, &send_key, NULL, + &hmac_send, NULL, NULL)) { + /** Cannot get keys */ + ske->status = SILC_SKE_STATUS_ERROR; + ske->prop->cipher = NULL; + ske->prop->hmac = NULL; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } + + ske->prop->cipher = NULL; + ske->prop->hmac = NULL; + + /* Set the new keys into use. This will also send REKEY_DONE packet. Any + packet sent after this call will be protected with the new keys. */ + if (!silc_packet_set_keys(ske->stream, send_key, NULL, hmac_send, NULL, + TRUE)) { + /** Cannot set keys */ + SILC_LOG_DEBUG(("Cannot set new keys, error sending REKEY_DONE")); + ske->status = SILC_SKE_STATUS_ERROR; + silc_cipher_free(send_key); + silc_hmac_free(hmac_send); + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } + + /** Wait for REKEY_DONE */ + silc_fsm_next(fsm, silc_ske_st_rekey_responder_end); + return SILC_FSM_WAIT; +} + +/* Rekey protocol end */ + +SILC_FSM_STATE(silc_ske_st_rekey_responder_end) +{ + SilcSKE ske = fsm_context; + SilcCipher receive_key; + SilcHmac hmac_receive; + SilcSKERekeyMaterial rekey; + + SILC_LOG_DEBUG(("Start")); + + if (ske->packet->type != SILC_PACKET_REKEY_DONE) { + SILC_LOG_DEBUG(("Remote retransmitted an old packet")); + silc_packet_free(ske->packet); + ske->packet = NULL; + return SILC_FSM_WAIT; + } + + silc_packet_get_keys(ske->stream, NULL, &receive_key, NULL, &hmac_receive); + ske->prop->cipher = receive_key; + ske->prop->hmac = hmac_receive; + + /* Get receiving keys */ + if (!silc_ske_set_keys(ske, ske->keymat, ske->prop, NULL, &receive_key, + NULL, &hmac_receive, NULL)) { + /** Cannot get keys */ + ske->status = SILC_SKE_STATUS_ERROR; + ske->prop->cipher = NULL; + ske->prop->hmac = NULL; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } + + /* Set new receiving keys into use. All packets received after this will + be decrypted with the new keys. */ + if (!silc_packet_set_keys(ske->stream, NULL, receive_key, NULL, + hmac_receive, FALSE)) { + /** Cannot set keys */ + SILC_LOG_DEBUG(("Cannot set new keys")); + ske->status = SILC_SKE_STATUS_ERROR; + ske->prop->cipher = NULL; + ske->prop->hmac = NULL; + silc_cipher_free(receive_key); + silc_hmac_free(hmac_receive); + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } + + SILC_LOG_DEBUG(("Rekey completed successfully")); + + /* Generate new rekey material */ + rekey = silc_ske_make_rekey_material(ske, ske->keymat); + if (!rekey) { + /** No memory */ + ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY; + ske->prop->cipher = NULL; + ske->prop->hmac = NULL; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } + rekey->pfs = ske->rekey->pfs; + ske->rekey = rekey; + + ske->prop->cipher = NULL; + ske->prop->hmac = NULL; + silc_packet_free(ske->packet); + ske->packet = NULL; + silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske); + silc_schedule_task_del_by_context(ske->schedule, ske); + + /* Call completion */ + silc_ske_completion(ske); + return SILC_FSM_FINISH; } @@ -2683,7 +2951,8 @@ SILC_FSM_STATE(silc_ske_st_rekey_responder_start) SilcAsyncOperation silc_ske_rekey_responder(SilcSKE ske, SilcPacketStream stream, - SilcSKERekeyMaterial rekey) + SilcSKERekeyMaterial rekey, + SilcPacket packet) { SILC_LOG_DEBUG(("Start SKE rekey as responder")); @@ -2700,6 +2969,7 @@ silc_ske_rekey_responder(SilcSKE ske, ske->responder = TRUE; ske->running = TRUE; ske->rekeying = TRUE; + ske->packet = packet; /* Link to packet stream to get key exchange packets */ ske->stream = stream; @@ -2711,7 +2981,7 @@ silc_ske_rekey_responder(SilcSKE ske, SILC_PACKET_FAILURE, -1); /* Start SKE rekey as responder */ - silc_fsm_start(&ske->fsm, silc_ske_st_rekey_responder_start); + silc_fsm_start_sync(&ske->fsm, silc_ske_st_rekey_responder_wait); return &ske->op; } @@ -2747,7 +3017,7 @@ silc_ske_process_key_material_data(unsigned char *data, return NULL; silc_buffer_format(buf, SILC_STR_UI_CHAR(0), - SILC_STR_UI_XNSTRING(data, data_len), + SILC_STR_DATA(data, data_len), SILC_STR_END); /* Take IVs */ @@ -2786,8 +3056,8 @@ silc_ske_process_key_material_data(unsigned char *data, if (!dist) return NULL; silc_buffer_format(dist, - SILC_STR_UI_XNSTRING(data, data_len), - SILC_STR_UI_XNSTRING(k1, hash_len), + SILC_STR_DATA(data, data_len), + SILC_STR_DATA(k1, hash_len), SILC_STR_END); memset(k2, 0, sizeof(k2)); silc_hash_make(hash, dist->data, silc_buffer_len(dist), k2); @@ -2797,7 +3067,7 @@ silc_ske_process_key_material_data(unsigned char *data, silc_buffer_pull_tail(dist, hash_len); silc_buffer_pull(dist, data_len + hash_len); silc_buffer_format(dist, - SILC_STR_UI_XNSTRING(k2, hash_len), + SILC_STR_DATA(k2, hash_len), SILC_STR_END); silc_buffer_push(dist, data_len + hash_len); memset(k3, 0, sizeof(k3)); @@ -2849,8 +3119,8 @@ silc_ske_process_key_material_data(unsigned char *data, if (!dist) return NULL; silc_buffer_format(dist, - SILC_STR_UI_XNSTRING(data, data_len), - SILC_STR_UI_XNSTRING(k1, hash_len), + SILC_STR_DATA(data, data_len), + SILC_STR_DATA(k1, hash_len), SILC_STR_END); memset(k2, 0, sizeof(k2)); silc_hash_make(hash, dist->data, silc_buffer_len(dist), k2); @@ -2860,7 +3130,7 @@ silc_ske_process_key_material_data(unsigned char *data, silc_buffer_pull_tail(dist, hash_len); silc_buffer_pull(dist, data_len + hash_len); silc_buffer_format(dist, - SILC_STR_UI_XNSTRING(k2, hash_len), + SILC_STR_DATA(k2, hash_len), SILC_STR_END); silc_buffer_push(dist, data_len + hash_len); memset(k3, 0, sizeof(k3)); @@ -2936,8 +3206,8 @@ silc_ske_process_key_material(SilcSKE ske, if (!buf) return NULL; silc_buffer_format(buf, - SILC_STR_UI_XNSTRING(tmpbuf, klen), - SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len), + SILC_STR_DATA(tmpbuf, klen), + SILC_STR_DATA(ske->hash, ske->hash_len), SILC_STR_END); /* Process the key material */ @@ -3121,7 +3391,7 @@ const char *silc_ske_status_string[] = { /* Official */ "Ok", - "Unkown error occurred", + "Unexpected error occurred", "Bad payload in packet", "Unsupported group", "Unsupported cipher",