Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2000 - 2007 Pekka Riikonen
+ Copyright (C) 2000 - 2014 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
const unsigned char *data,
SilcUInt32 data_len);
+/*
+ * Notify the owner of the ske that we failed. Ensures that we don't make the
+ * same callout twice, as the notification callback routines are not designed
+ * to handle that case.
+ */
+static void silc_ske_notify_failure(SilcSKE ske)
+{
+ SILC_LOG_DEBUG(("Notifying SKE %p owner of failure (failure_notified = %d)",
+ ske, ske->failure_notified));
+
+ /*
+ * First, check if we have already made a failure callout. If so, then we
+ * will stop here.
+ */
+ if (ske->failure_notified)
+ return;
+
+ /*
+ * Mark ourselves as having already sent the failure notification here and
+ * now.
+ */
+ ske->failure_notified = TRUE;
+
+ SILC_LOG_DEBUG(("Deliver failure notification for SKE %p (%s)",
+ ske, ske->responder ? "responder" : "initiator"));
+
+ /*
+ * Finally, make the call to the owner's registered failure callback.
+ */
+ if (ske->responder)
+ silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
+ else
+ silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
+}
+
/* Packet callback */
static SilcBool silc_ske_packet_receive(SilcPacketEngine engine,
}
/* See if received failure from remote */
- if (packet->type == SILC_PACKET_FAILURE) {
- if (ske->responder)
- silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
- else
- silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
- }
+ if (packet->type == SILC_PACKET_FAILURE)
+ silc_ske_notify_failure(ske);
/* Handle rekey and SUCCESS packets synchronously. After SUCCESS packets
they keys are taken into use immediately, hence the synchronous
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,
- &r_software_string, NULL))
+ NULL, NULL, NULL))
return SILC_SKE_STATUS_BAD_VERSION;
return SILC_SKE_STATUS_OK;
SILC_LOG_DEBUG(("Parsing KE Start Payload"));
rp = remote_payload;
+ if (!rp)
+ return SILC_SKE_STATUS_BAD_VERSION;
/* Check for mandatory fields */
if (!rp->ke_grp_len) {
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);
+ if (!e)
+ return SILC_SKE_STATUS_OUT_OF_MEMORY;
f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
+ if (!f)
+ return SILC_SKE_STATUS_OUT_OF_MEMORY;
KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
+ if (!KEY)
+ return SILC_SKE_STATUS_OUT_OF_MEMORY;
/* Format the buffer used to compute the hash value */
buf = silc_buffer_alloc_size(s_len +
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);
+ if (!e)
+ return SILC_SKE_STATUS_OUT_OF_MEMORY;
buf = silc_buffer_alloc_size(s_len + ske->ke1_payload->pk_len + e_len);
if (!buf)
SilcSKERekeyMaterial rekey;
const char *hash;
+ if (!keymat)
+ return NULL;
+
/* Create rekey material */
rekey = silc_calloc(1, sizeof(*rekey));
if (!rekey)
SILC_LOG_DEBUG(("Assembling KE Start Payload"));
rp = silc_calloc(1, sizeof(*rp));
+ if (!rp)
+ return NULL;
/* Set flags */
rp->flags = (unsigned char)flags;
/* Set random cookie */
rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
+ if (!rp->cookie) {
+ silc_free(rp);
+ return NULL;
+ }
for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
rp->cookie[i] = silc_rng_get_byte_fast(ske->rng);
rp->cookie_len = SILC_SKE_COOKIE_LEN;
/* Put version */
rp->version = strdup(version);
- rp->version_len = strlen(version);
+ if (rp->version)
+ rp->version_len = strlen(version);
/* Get supported Key Exhange groups */
rp->ke_grp_list = silc_ske_get_supported_groups();
- rp->ke_grp_len = strlen(rp->ke_grp_list);
+ if (rp->ke_grp_list)
+ rp->ke_grp_len = strlen(rp->ke_grp_list);
/* Get supported PKCS algorithms */
rp->pkcs_alg_list = silc_pkcs_get_supported();
- rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
+ if (rp->pkcs_alg_list)
+ rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
/* Get supported encryption algorithms */
rp->enc_alg_list = silc_cipher_get_supported();
- rp->enc_alg_len = strlen(rp->enc_alg_list);
+ if (rp->enc_alg_list)
+ rp->enc_alg_len = strlen(rp->enc_alg_list);
/* Get supported hash algorithms */
rp->hash_alg_list = silc_hash_get_supported();
- rp->hash_alg_len = strlen(rp->hash_alg_list);
+ if (rp->hash_alg_list)
+ rp->hash_alg_len = strlen(rp->hash_alg_list);
/* Get supported HMACs */
rp->hmac_alg_list = silc_hmac_get_supported();
- rp->hmac_alg_len = strlen(rp->hmac_alg_list);
+ if (rp->hmac_alg_list)
+ rp->hmac_alg_len = strlen(rp->hmac_alg_list);
/* XXX */
/* Get supported compression algorithms */
silc_free(ske->retrans.data);
ske->retrans.data = NULL;
ske->status = SILC_SKE_STATUS_TIMEOUT;
- if (ske->responder)
- silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
- else
- silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
+ silc_ske_notify_failure(ske);
silc_fsm_continue_sync(&ske->fsm);
return;
}
ske->retrans.type = type;
ske->retrans.flags = flags;
ske->retrans.data = silc_memdup(data, data_len);
- ske->retrans.data_len = data_len;
- silc_ske_install_retransmission(ske);
+ if (ske->retrans.data) {
+ ske->retrans.data_len = data_len;
+ silc_ske_install_retransmission(ske);
+ }
}
return ret;
static void silc_ske_completion(SilcSKE ske)
{
/* Call the completion callback */
- if (!ske->freed && !ske->aborted && ske->callbacks->completed) {
+ if (!ske->aborted && ske->callbacks->completed) {
if (ske->status != SILC_SKE_STATUS_OK)
ske->callbacks->completed(ske, ske->status, NULL, NULL, NULL,
ske->callbacks->context);
void *destructor_context)
{
SilcSKE ske = fsm_context;
- ske->running = FALSE;
- if (ske->freed)
- silc_ske_free(ske);
+ silc_ske_free(ske);
}
/* Key exchange timeout task callback */
ske->packet = NULL;
ske->status = SILC_SKE_STATUS_TIMEOUT;
- if (ske->responder)
- silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
- else
- silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
+ silc_ske_notify_failure(ske);
silc_fsm_continue_sync(&ske->fsm);
}
void silc_ske_free(SilcSKE ske)
{
- SILC_LOG_DEBUG(("Freeing Key Exchange object"));
-
if (!ske)
return;
- if (ske->running) {
- ske->freed = TRUE;
+ SILC_LOG_DEBUG(("Freeing Key Exchange object %p: aborted=%u refcount=%hu",
+ ske, ske->aborted, ske->refcnt));
- if (ske->aborted) {
- /* If already aborted, destroy the session immediately */
- ske->packet = NULL;
- ske->status = SILC_SKE_STATUS_ERROR;
- if (ske->responder)
- silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
- else
- silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
+ if (ske->aborted) {
+ /*
+ * If already aborted, destroy the session immediately. Only do the
+ * notification work if we have not already though, as doing so twice
+ * results in memory corruption. We may have silc_ske_free called
+ * twice, once when the abort is requested, and then again when the
+ * FSM finish routine is called. We have to be prepared to handle
+ * that case.
+ */
+ ske->packet = NULL;
+ ske->status = SILC_SKE_STATUS_ERROR;
+
+ silc_ske_notify_failure(ske);
+
+ if (silc_fsm_is_started(&ske->fsm))
silc_fsm_continue_sync(&ske->fsm);
- }
- return;
+ else
+ SILC_LOG_DEBUG(("Not continuing FSM as it's finished for SKE %p", ske));
}
ske->refcnt--;
silc_free(ske->hash);
silc_free(ske->callbacks);
- memset(ske, 'F', sizeof(*ske));
+ memset(ske, 0xdd, sizeof(*ske));
silc_free(ske);
}
silc_ske_payload_start_free(payload);
if (group)
silc_ske_group_free(group);
- if (prop->cipher)
- silc_cipher_free(prop->cipher);
- if (prop->hash)
- silc_hash_free(prop->hash);
- if (prop->hmac)
- silc_hmac_free(prop->hmac);
- silc_free(prop);
+ if (prop) {
+ if (prop->cipher)
+ silc_cipher_free(prop->cipher);
+ if (prop->hash)
+ silc_hash_free(prop->hash);
+ if (prop->hmac)
+ silc_hmac_free(prop->hmac);
+ silc_free(prop);
+ }
ske->prop = NULL;
if (status == SILC_SKE_STATUS_OK)
/* Create the random number x, 1 < x < q. */
x = silc_calloc(1, sizeof(*x));
- if (!x){
+ if (!x) {
/** Out of memory */
ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
silc_fsm_next(fsm, silc_ske_st_initiator_error);
/* Compute signature data if we are doing mutual authentication */
if (ske->private_key && ske->prop->flags & SILC_SKE_SP_FLAG_MUTUAL) {
- unsigned char hash[SILC_HASH_MAXLEN], sign[2048 + 1];
+ unsigned char hash[SILC_HASH_MAXLEN], sign[65536 + 1];
SilcUInt32 hash_len, sign_len;
SILC_LOG_DEBUG(("We are doing mutual authentication"));
/* Compute the hash value */
memset(hash, 0, sizeof(hash));
- silc_ske_make_hash(ske, hash, &hash_len, TRUE);
+ if (silc_ske_make_hash(ske, hash, &hash_len, TRUE) != SILC_SKE_STATUS_OK)
+ {
+ /** Error computing hash */
+ silc_mp_uninit(x);
+ silc_free(x);
+ silc_mp_uninit(&payload->x);
+ silc_free(payload->pk_data);
+ silc_free(payload);
+ ske->ke1_payload = NULL;
+ ske->status = SILC_SKE_STATUS_SIGNATURE_ERROR;
+ silc_fsm_next(fsm, silc_ske_st_initiator_error);
+ return SILC_FSM_CONTINUE;
+ }
SILC_LOG_DEBUG(("Signing HASH_i value"));
/* Compute the shared secret key */
KEY = silc_calloc(1, sizeof(*KEY));
+ if (!KEY) {
+ ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+ goto err;
+ }
silc_mp_init(KEY);
silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group);
ske->KEY = KEY;
if (status != SILC_SKE_STATUS_OK)
goto err;
ske->hash = silc_memdup(hash, hash_len);
+ if (!ske->hash) {
+ status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+ goto err;
+ }
ske->hash_len = hash_len;
if (ske->prop->public_key) {
if (ske->packet && silc_buffer_len(&ske->packet->buffer) == 4) {
SILC_GET32_MSB(error, ske->packet->buffer.data);
- ske->status = error;
silc_packet_free(ske->packet);
ske->packet = NULL;
}
+ ske->status = error;
SILC_LOG_DEBUG(("Error %s (%d) received during key exchange",
silc_ske_map_status(ske->status), ske->status));
SilcSKEParams params,
SilcSKEStartPayload start_payload)
{
- SILC_LOG_DEBUG(("Start SKE as initiator"));
+ SILC_LOG_DEBUG(("Start SKE %p as initiator; stream=%p; params=%p; "
+ "start_payload=%p", ske, stream, params, start_payload));
if (!ske || !stream || !params || !params->version)
return NULL;
ske->timeout = params->timeout_secs ? params->timeout_secs : 30;
ske->start_payload = start_payload;
ske->version = params->version;
- ske->running = TRUE;
+ ++ske->refcnt;
/* Link to packet stream to get key exchange packets */
ske->stream = stream;
/* 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);
+ if (!ske->start_payload_copy) {
+ silc_packet_free(ske->packet);
+ ske->packet = NULL;
+ ske->status = status;
+ silc_fsm_next(fsm, silc_ske_st_responder_error);
+ return SILC_FSM_CONTINUE;
+ }
silc_packet_free(ske->packet);
ske->packet = NULL;
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"));
}
/* 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)) {
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 = 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 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 */
}
}
{
SilcSKE ske = fsm_context;
SilcSKEStatus status;
- SilcSKEKEPayload recv_payload, send_payload;
- SilcMPInt *x, *KEY;
+ SilcSKEKEPayload recv_payload, send_payload = NULL;
+ SilcMPInt *x = NULL, *KEY;
if (ske->aborted) {
/** Aborted */
if (ske->status != SILC_SKE_STATUS_OK) {
/** Public key not verified */
SILC_LOG_DEBUG(("Public key verification failed"));
- silc_fsm_next(fsm, silc_ske_st_initiator_error);
- return SILC_FSM_CONTINUE;
+ goto err;
}
recv_payload = ske->ke1_payload;
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);
if (status != SILC_SKE_STATUS_OK) {
/** Error computing hash */
+ SILC_LOG_DEBUG(("Error computing hash"));
ske->status = status;
- silc_fsm_next(fsm, silc_ske_st_responder_error);
- return SILC_FSM_CONTINUE;
+ goto err;
}
SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
/** Incorrect signature */
SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
- silc_fsm_next(fsm, silc_ske_st_responder_error);
- return SILC_FSM_CONTINUE;
+ goto err;
}
SILC_LOG_DEBUG(("Signature is Ok"));
/* Create the random number x, 1 < x < q. */
x = silc_calloc(1, sizeof(*x));
+ if (!x) {
+ ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+ goto err;
+ }
silc_mp_init(x);
status =
silc_ske_create_rnd(ske, &ske->prop->group->group_order,
x);
if (status != SILC_SKE_STATUS_OK) {
/** Error generating random number */
- silc_mp_uninit(x);
- silc_free(x);
ske->status = status;
- silc_fsm_next(fsm, silc_ske_st_responder_error);
- return SILC_FSM_CONTINUE;
+ goto err;
}
/* Save the results for later processing */
send_payload = silc_calloc(1, sizeof(*send_payload));
+ if (!send_payload) {
+ ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+ goto err;
+ }
ske->x = x;
ske->ke2_payload = send_payload;
/* Compute the shared secret key */
KEY = silc_calloc(1, sizeof(*KEY));
+ if (!KEY) {
+ ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+ goto err;
+ }
silc_mp_init(KEY);
silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x,
&ske->prop->group->group);
/** Send KE2 payload */
silc_fsm_next(fsm, silc_ske_st_responder_phase5);
return SILC_FSM_CONTINUE;
+
+ err:
+ silc_mp_uninit(x);
+ silc_free(x);
+ ske->x = NULL;
+ silc_free(send_payload);
+ ske->ke2_payload = NULL;
+
+ silc_fsm_next(fsm, silc_ske_st_responder_error);
+ return SILC_FSM_CONTINUE;
}
/* Phase-5. Send KE2 payload */
SilcSKE ske = fsm_context;
SilcSKEStatus status;
SilcBuffer payload_buf;
- unsigned char hash[SILC_HASH_MAXLEN], sign[2048 + 1], *pk;
+ unsigned char hash[SILC_HASH_MAXLEN], sign[65536 + 1], *pk;
SilcUInt32 hash_len, sign_len, pk_len;
SILC_LOG_DEBUG(("Start"));
pk = silc_pkcs_public_key_encode(ske->public_key, &pk_len);
if (!pk) {
/** Error encoding public key */
- status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+ ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
silc_fsm_next(fsm, silc_ske_st_responder_error);
return SILC_FSM_CONTINUE;
}
return SILC_FSM_CONTINUE;
}
ske->hash = silc_memdup(hash, hash_len);
+ if (!ske->hash) {
+ /** Error computing hash */
+ ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+ silc_fsm_next(fsm, silc_ske_st_responder_error);
+ return SILC_FSM_CONTINUE;
+ }
ske->hash_len = hash_len;
if (ske->public_key && ske->private_key) {
if (!silc_pkcs_sign(ske->private_key, hash, hash_len, sign,
sizeof(sign) - 1, &sign_len, FALSE, ske->prop->hash)) {
/** Error computing signature */
- status = SILC_SKE_STATUS_SIGNATURE_ERROR;
+ ske->status = SILC_SKE_STATUS_SIGNATURE_ERROR;
silc_fsm_next(fsm, silc_ske_st_responder_error);
return SILC_FSM_CONTINUE;
}
ske->ke2_payload->sign_data = silc_memdup(sign, sign_len);
+ if (!ske->ke2_payload->sign_data) {
+ /** Error computing hash */
+ ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+ silc_fsm_next(fsm, silc_ske_st_responder_error);
+ return SILC_FSM_CONTINUE;
+ }
ske->ke2_payload->sign_len = sign_len;
memset(sign, 0, sizeof(sign));
}
if (ske->packet && silc_buffer_len(&ske->packet->buffer) == 4) {
SILC_GET32_MSB(error, ske->packet->buffer.data);
- ske->status = error;
silc_packet_free(ske->packet);
ske->packet = NULL;
}
+ ske->status = error;
+ if (ske->status == SILC_SKE_STATUS_OK)
+ ske->status = SILC_SKE_STATUS_ERROR;
silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
silc_schedule_task_del_by_context(ske->schedule, ske);
ske->status, silc_ske_map_status(ske->status)));
/* Send FAILURE packet */
- if (ske->status > SILC_SKE_STATUS_INVALID_COOKIE)
+ if (ske->status == SILC_SKE_STATUS_OUT_OF_MEMORY)
+ ske->status = SILC_SKE_STATUS_ERROR;
+ else if (ske->status > SILC_SKE_STATUS_INVALID_COOKIE)
ske->status = SILC_SKE_STATUS_BAD_PAYLOAD;
SILC_PUT32_MSB(ske->status, tmp);
silc_ske_packet_send(ske, SILC_PACKET_FAILURE, 0, tmp, 4);
ske->timeout = params->timeout_secs ? params->timeout_secs : 30;
if (ske->flags & SILC_SKE_SP_FLAG_IV_INCLUDED)
ske->session_port = params->session_port;
- ske->version = strdup(params->version);
+ ske->version = params->version;
if (!ske->version)
return NULL;
- ske->running = TRUE;
+ ++ske->refcnt;
/* Link to packet stream to get key exchange packets */
ske->stream = stream;
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);
+ if (!pfsbuf) {
+ SILC_LOG_ERROR(("Error processing key material"));
+ silc_fsm_next(fsm, silc_ske_st_initiator_error);
+ return SILC_FSM_CONTINUE;
}
+ 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 =
ske->rekey = rekey;
ske->responder = FALSE;
- ske->running = TRUE;
ske->rekeying = TRUE;
+ ++ske->refcnt;
/* Link to packet stream to get key exchange packets */
ske->stream = stream;
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);
+ if (!pfsbuf) {
+ SILC_LOG_ERROR(("Error processing key material"));
+ silc_fsm_next(fsm, silc_ske_st_responder_error);
+ return SILC_FSM_CONTINUE;
}
+ 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 =
ske->rekey = rekey;
ske->responder = TRUE;
- ske->running = TRUE;
ske->rekeying = TRUE;
ske->packet = packet;
+ ++ske->refcnt;
/* Link to packet stream to get key exchange packets */
ske->stream = stream;
buf->data[0] = 0;
silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
+ if (!key->send_iv) {
+ silc_buffer_clear(buf);
+ silc_buffer_free(buf);
+ silc_free(key);
+ return NULL;
+ }
memcpy(key->send_iv, hashd, req_iv_len);
memset(hashd, 0, sizeof(hashd));
buf->data[0] = 1;
silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
+ if (!key->receive_iv) {
+ silc_buffer_clear(buf);
+ silc_buffer_free(buf);
+ silc_free(key);
+ return NULL;
+ }
memcpy(key->receive_iv, hashd, req_iv_len);
key->iv_len = req_iv_len;
/* Then, save the keys */
dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
+ if (!dtmp) {
+ silc_buffer_clear(buf);
+ silc_buffer_free(buf);
+ silc_free(key);
+ return NULL;
+ }
memcpy(dtmp, k1, hash_len);
memcpy(dtmp + hash_len, k2, hash_len);
memcpy(dtmp + hash_len + hash_len, k3, hash_len);
key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
+ if (!key->send_enc_key) {
+ silc_buffer_clear(buf);
+ silc_buffer_free(buf);
+ silc_free(key);
+ silc_free(dtmp);
+ return NULL;
+ }
memcpy(key->send_enc_key, dtmp, enc_key_len);
key->enc_key_len = req_enc_key_len;
memset(hashd, 0, sizeof(hashd));
silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
+ if (!key->send_enc_key) {
+ silc_buffer_clear(buf);
+ silc_buffer_free(buf);
+ silc_free(key);
+ return NULL;
+ }
memcpy(key->send_enc_key, hashd, enc_key_len);
key->enc_key_len = req_enc_key_len;
}
/* Then, save the keys */
dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
+ if (!dtmp) {
+ silc_buffer_clear(buf);
+ silc_buffer_free(buf);
+ silc_free(key);
+ return NULL;
+ }
memcpy(dtmp, k1, hash_len);
memcpy(dtmp + hash_len, k2, hash_len);
memcpy(dtmp + hash_len + hash_len, k3, hash_len);
key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
+ if (!key->receive_enc_key) {
+ silc_buffer_clear(buf);
+ silc_buffer_free(buf);
+ silc_free(key);
+ silc_free(dtmp);
+ return NULL;
+ }
memcpy(key->receive_enc_key, dtmp, enc_key_len);
key->enc_key_len = req_enc_key_len;
memset(hashd, 0, sizeof(hashd));
silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
+ if (!key->receive_enc_key) {
+ silc_buffer_clear(buf);
+ silc_buffer_free(buf);
+ silc_free(key);
+ return NULL;
+ }
memcpy(key->receive_enc_key, hashd, enc_key_len);
key->enc_key_len = req_enc_key_len;
}
buf->data[0] = 4;
silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
key->send_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
+ if (!key->send_hmac_key) {
+ silc_buffer_clear(buf);
+ silc_buffer_free(buf);
+ silc_free(key);
+ return NULL;
+ }
memcpy(key->send_hmac_key, hashd, req_hmac_key_len);
memset(hashd, 0, sizeof(hashd));
buf->data[0] = 5;
silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd);
key->receive_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
+ if (!key->receive_hmac_key) {
+ silc_buffer_clear(buf);
+ silc_buffer_free(buf);
+ silc_free(key);
+ return NULL;
+ }
memcpy(key->receive_hmac_key, hashd, req_hmac_key_len);
key->hmac_key_len = req_hmac_key_len;
memset(hashd, 0, sizeof(hashd));
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 */
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) {
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);
}
}
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);
}
}
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);
}
}
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);
}
}
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;
}