X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilcske%2Fsilcske.c;h=caf2579628bf9a1a426057a5179f2949dfa5d07e;hp=efb86c12b63b79ffbedd9eeeb54d2094e53375a8;hb=457becb724b71a6145d8c1ad2111b972ed67128d;hpb=b280ae52db9aedad40a04691d0a854febfe7b692 diff --git a/lib/silcske/silcske.c b/lib/silcske/silcske.c index efb86c12..caf25796 100644 --- a/lib/silcske/silcske.c +++ b/lib/silcske/silcske.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2000 - 2007 Pekka Riikonen + Copyright (C) 2000 - 2008 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -671,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); @@ -694,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) { @@ -736,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); @@ -1611,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 */ @@ -1630,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); } @@ -2025,15 +2026,9 @@ SILC_FSM_STATE(silc_ske_st_responder_phase2) silc_packet_free(ske->packet); ske->packet = NULL; - /* Verify the received public key and verify the signature if we are - doing mutual authentication. */ - if (ske->start_payload && - ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) { - - SILC_LOG_DEBUG(("We are doing mutual authentication")); - - if (!recv_payload->pk_data && (ske->callbacks->verify_key || - ske->repository)) { + /* Verify public key, except in rekey, when it is not sent */ + if (!ske->rekey) { + if (!recv_payload->pk_data) { /** Public key not provided */ SILC_LOG_ERROR(("Remote end did not send its public key (or " "certificate), even though we require it")); @@ -2043,8 +2038,7 @@ SILC_FSM_STATE(silc_ske_st_responder_phase2) } /* Decode the remote's public key */ - if (recv_payload->pk_data && - !silc_pkcs_public_key_alloc(recv_payload->pk_type, + if (!silc_pkcs_public_key_alloc(recv_payload->pk_type, recv_payload->pk_data, recv_payload->pk_len, &ske->prop->public_key)) { @@ -2055,39 +2049,36 @@ SILC_FSM_STATE(silc_ske_st_responder_phase2) return SILC_FSM_CONTINUE; } - if (ske->prop->public_key && (ske->callbacks->verify_key || - ske->repository)) { - SILC_LOG_DEBUG(("Verifying public key")); + SILC_LOG_DEBUG(("Verifying public key")); - /** Waiting public key verification */ - silc_fsm_next(fsm, silc_ske_st_responder_phase4); + /** Waiting public key verification */ + silc_fsm_next(fsm, silc_ske_st_responder_phase4); - /* If repository is provided, verify the key from there. */ - if (ske->repository) { - SilcSKRFind find; + /* If repository is provided, verify the key from there. */ + if (ske->repository) { + SilcSKRFind find; - find = silc_skr_find_alloc(); - if (!find) { - ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY; - silc_fsm_next(fsm, silc_ske_st_responder_error); - return SILC_FSM_CONTINUE; - } - silc_skr_find_set_pkcs_type(find, - silc_pkcs_get_type(ske->prop->public_key)); - silc_skr_find_set_public_key(find, ske->prop->public_key); - silc_skr_find_set_usage(find, SILC_SKR_USAGE_KEY_AGREEMENT); - - /* Find key from repository */ - SILC_FSM_CALL(silc_skr_find(ske->repository, - silc_fsm_get_schedule(fsm), find, - silc_ske_skr_callback, ske)); - } else { - /* Verify from application */ + find = silc_skr_find_alloc(); + if (!find) { + ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } + silc_skr_find_set_pkcs_type(find, + silc_pkcs_get_type(ske->prop->public_key)); + silc_skr_find_set_public_key(find, ske->prop->public_key); + silc_skr_find_set_usage(find, SILC_SKR_USAGE_KEY_AGREEMENT); + + /* Find key from repository */ + SILC_FSM_CALL(silc_skr_find(ske->repository, + silc_fsm_get_schedule(fsm), find, + silc_ske_skr_callback, ske)); + } else { + /* Verify from application */ + if (ske->callbacks->verify_key) SILC_FSM_CALL(ske->callbacks->verify_key(ske, ske->prop->public_key, ske->callbacks->context, silc_ske_pk_verified, NULL)); - } - /* NOT REACHED */ } } @@ -2128,7 +2119,7 @@ SILC_FSM_STATE(silc_ske_st_responder_phase4) unsigned char hash[SILC_HASH_MAXLEN]; SilcUInt32 hash_len; - SILC_LOG_DEBUG(("Public key is authentic")); + SILC_LOG_DEBUG(("We are doing mutual authentication")); /* Compute the hash value */ status = silc_ske_make_hash(ske, hash, &hash_len, TRUE); @@ -2223,22 +2214,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 */ @@ -2276,7 +2268,7 @@ SILC_FSM_STATE(silc_ske_st_responder_phase5) silc_buffer_free(payload_buf); - /* In case we are doing rekey move to finish it. */ + /* 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); @@ -2475,6 +2467,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 */ @@ -2520,13 +2519,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 */ @@ -2557,7 +2550,6 @@ 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, @@ -2674,8 +2666,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; @@ -2758,6 +2753,13 @@ SILC_FSM_STATE(silc_ske_st_rekey_responder_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_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 */ @@ -2794,13 +2796,7 @@ SILC_FSM_STATE(silc_ske_st_rekey_responder_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_responder_error); - return SILC_FSM_CONTINUE; - } + hash = ske->prop->hash; hash_len = silc_hash_len(hash); /* Process key material */ @@ -2831,7 +2827,6 @@ SILC_FSM_STATE(silc_ske_st_rekey_responder_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, @@ -3012,7 +3007,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 */ @@ -3051,8 +3046,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); @@ -3062,7 +3057,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)); @@ -3114,8 +3109,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); @@ -3125,7 +3120,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)); @@ -3201,8 +3196,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 */ @@ -3280,7 +3275,7 @@ SilcBool silc_ske_set_keys(SilcSKE ske, SilcHmac *ret_hmac_receive, SilcHash *ret_hash) { - unsigned char iv[32]; + unsigned char iv[SILC_HASH_MAXLEN]; SilcBool iv_included = (prop->flags & SILC_SKE_SP_FLAG_IV_INCLUDED); /* Allocate ciphers to be used in the communication */ @@ -3307,6 +3302,12 @@ SilcBool silc_ske_set_keys(SilcSKE ske, return FALSE; } + /* Allocate hash */ + if (ret_hash) { + if (!silc_hash_alloc(silc_hash_get_name(prop->hash), ret_hash)) + return FALSE; + } + /* Set key material */ memset(iv, 0, sizeof(iv)); if (ske->responder) { @@ -3315,10 +3316,24 @@ SilcBool silc_ske_set_keys(SilcSKE ske, keymat->enc_key_len, TRUE); if (silc_cipher_get_mode(*ret_send_key) == SILC_CIPHER_MODE_CTR) { - memcpy(iv, ske->hash, 4); - memcpy(iv + 4, keymat->receive_iv, iv_included ? 4 : 8); + /* Counter mode */ + if (!ske->rekeying) { + /* Set IV. */ + memcpy(iv, ske->hash, 4); + if (!iv_included) + memcpy(iv + 4, keymat->receive_iv, 8); + } else { + /* Rekey, recompute the truncated hash value. */ + silc_hash_make(prop->hash, keymat->receive_iv, 8, iv); + if (!iv_included) + memcpy(iv + 4, keymat->receive_iv, 8); + else + memset(iv + 4, 0, 12); + } + silc_cipher_set_iv(*ret_send_key, iv); } else { + /* Other modes */ silc_cipher_set_iv(*ret_send_key, keymat->receive_iv); } } @@ -3327,10 +3342,24 @@ SilcBool silc_ske_set_keys(SilcSKE ske, keymat->enc_key_len, FALSE); if (silc_cipher_get_mode(*ret_receive_key) == SILC_CIPHER_MODE_CTR) { - memcpy(iv, ske->hash, 4); - memcpy(iv + 4, keymat->send_iv, iv_included ? 4 : 8); + /* Counter mode */ + if (!ske->rekeying) { + /* Set IV. */ + memcpy(iv, ske->hash, 4); + if (!iv_included) + memcpy(iv + 4, keymat->send_iv, 8); + } else { + /* Rekey, recompute the truncated hash value. */ + silc_hash_make(prop->hash, keymat->send_iv, 8, iv); + if (!iv_included) + memcpy(iv + 4, keymat->send_iv, 8); + else + memset(iv + 4, 0, 12); + } + silc_cipher_set_iv(*ret_receive_key, iv); } else { + /* Other modes */ silc_cipher_set_iv(*ret_receive_key, keymat->send_iv); } } @@ -3346,10 +3375,24 @@ SilcBool silc_ske_set_keys(SilcSKE ske, keymat->enc_key_len, TRUE); if (silc_cipher_get_mode(*ret_send_key) == SILC_CIPHER_MODE_CTR) { - memcpy(iv, ske->hash, 4); - memcpy(iv + 4, keymat->send_iv, iv_included ? 4 : 8); + /* Counter mode */ + if (!ske->rekeying) { + /* Set IV. */ + memcpy(iv, ske->hash, 4); + if (!iv_included) + memcpy(iv + 4, keymat->send_iv, 8); + } else { + /* Rekey, recompute the truncated hash value. */ + silc_hash_make(prop->hash, keymat->send_iv, 8, iv); + if (!iv_included) + memcpy(iv + 4, keymat->send_iv, 8); + else + memset(iv + 4, 0, 12); + } + silc_cipher_set_iv(*ret_send_key, iv); } else { + /* Other modes */ silc_cipher_set_iv(*ret_send_key, keymat->send_iv); } } @@ -3358,10 +3401,25 @@ SilcBool silc_ske_set_keys(SilcSKE ske, keymat->enc_key_len, FALSE); if (silc_cipher_get_mode(*ret_receive_key) == SILC_CIPHER_MODE_CTR) { - memcpy(iv, ske->hash, 4); - memcpy(iv + 4, keymat->receive_iv, iv_included ? 4 : 8); + /* Counter mode */ + if (!ske->rekeying) { + /* Set IV. If IV Included flag was negotiated we only set the + truncated hash value. */ + memcpy(iv, ske->hash, 4); + if (!iv_included) + memcpy(iv + 4, keymat->receive_iv, 8); + } else { + /* Rekey, recompute the truncated hash value. */ + silc_hash_make(prop->hash, keymat->receive_iv, 8, iv); + if (!iv_included) + memcpy(iv + 4, keymat->receive_iv, 8); + else + memset(iv + 4, 0, 12); + } + silc_cipher_set_iv(*ret_receive_key, iv); } else { + /* Other modes */ silc_cipher_set_iv(*ret_receive_key, keymat->receive_iv); } } @@ -3373,12 +3431,6 @@ SilcBool silc_ske_set_keys(SilcSKE ske, keymat->hmac_key_len); } - /* Allocate hash */ - if (ret_hash) { - if (!silc_hash_alloc(silc_hash_get_name(prop->hash), ret_hash)) - return FALSE; - } - return TRUE; }