Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2000 - 2001 Pekka Riikonen
+ Copyright (C) 2000 - 2006 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
the Free Software Foundation; version 2 of the License.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/* Fixed and public Diffie Hellman Groups defined by the SKE
protocol. These are equivalent to the OAKLEY Key Determination
protocol groups (taken from RFC 2412). */
-const struct SilcSKEDiffieHellmanGroupDefStruct silc_ske_groups[] =
+const struct SilcSKEDiffieHellmanGroupDefStruct silc_ske_groups[] =
{
/* 1024 bits modulus (Mandatory group) */
{ 1, "diffie-hellman-group1",
silc_mp_set_str(&group->group, silc_ske_groups[i].group, 16);
silc_mp_set_str(&group->group_order, silc_ske_groups[i].group_order, 16);
silc_mp_set_str(&group->generator, silc_ske_groups[i].generator, 16);
-
+
*ret = group;
}
silc_mp_set_str(&group->group, silc_ske_groups[i].group, 16);
silc_mp_set_str(&group->group_order, silc_ske_groups[i].group_order, 16);
silc_mp_set_str(&group->generator, silc_ske_groups[i].generator, 16);
-
+
*ret = group;
}
len += strlen(silc_ske_groups[i].name);
list = silc_realloc(list, len + 1);
- memcpy(list + (len - strlen(silc_ske_groups[i].name)),
+ memcpy(list + (len - strlen(silc_ske_groups[i].name)),
silc_ske_groups[i].name, strlen(silc_ske_groups[i].name));
memcpy(list + len, ",", 1);
len++;
}
/* Save selected cipher to security properties */
- if (silc_cipher_alloc(payload->enc_alg_list,
- &(*prop)->cipher) == FALSE) {
+ if (silc_cipher_alloc(payload->enc_alg_list, &(*prop)->cipher) == FALSE) {
silc_free(payload->ke_grp_list);
silc_free(payload->pkcs_alg_list);
silc_free(payload);
}
/* Save selected hash algorithm to security properties */
- if (silc_hash_alloc(ske->start_payload->hash_alg_list,
- &(*prop)->hash) == FALSE) {
+ if (silc_hash_alloc(payload->hash_alg_list, &(*prop)->hash) == FALSE) {
silc_free(payload->ke_grp_list);
silc_free(payload->pkcs_alg_list);
silc_free(payload->enc_alg_list);
}
/* Save selected HMACc to security properties */
- if (silc_hmac_alloc(ske->start_payload->hmac_alg_list, NULL,
- &(*prop)->hmac) == FALSE) {
+ if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &(*prop)->hmac) == FALSE) {
silc_free(payload->ke_grp_list);
silc_free(payload->pkcs_alg_list);
silc_free(payload->enc_alg_list);
SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
- if (!rng || !schedule || !public_key)
+ if (!rng || !schedule)
return NULL;
+ if (!public_key) {
+ SILC_LOG_ERROR(("Public key must be given to silc_ske_alloc"));
+ return NULL;
+ }
+
ske = silc_calloc(1, sizeof(*ske));
if (!ske)
return NULL;
{
SILC_LOG_DEBUG(("Freeing Key Exchange object"));
- if (ske) {
- /* Free start payload */
- if (ske->start_payload)
- silc_ske_payload_start_free(ske->start_payload);
-
- /* Free KE payload */
- if (ske->ke1_payload)
- silc_ske_payload_ke_free(ske->ke1_payload);
- if (ske->ke2_payload)
- silc_ske_payload_ke_free(ske->ke2_payload);
- silc_free(ske->remote_version);
-
- /* Free rest */
- if (ske->prop) {
- if (ske->prop->group)
- silc_ske_group_free(ske->prop->group);
- if (ske->prop->cipher)
- silc_cipher_free(ske->prop->cipher);
- if (ske->prop->hash)
- silc_hash_free(ske->prop->hash);
- if (ske->prop->hmac)
- silc_hmac_free(ske->prop->hmac);
- silc_free(ske->prop);
- }
- if (ske->start_payload_copy)
- silc_buffer_free(ske->start_payload_copy);
- if (ske->x) {
- silc_mp_uninit(ske->x);
- silc_free(ske->x);
- }
- if (ske->KEY) {
- silc_mp_uninit(ske->KEY);
- silc_free(ske->KEY);
- }
- silc_free(ske->hash);
- silc_free(ske->callbacks);
+ if (!ske)
+ return;
+
+ if (ske->running) {
+ ske->freed = TRUE;
+ return;
+ }
- memset(ske, 'F', sizeof(*ske));
- silc_free(ske);
+ /* Free start payload */
+ if (ske->start_payload)
+ silc_ske_payload_start_free(ske->start_payload);
+
+ /* Free KE payload */
+ if (ske->ke1_payload)
+ silc_ske_payload_ke_free(ske->ke1_payload);
+ if (ske->ke2_payload)
+ silc_ske_payload_ke_free(ske->ke2_payload);
+ silc_free(ske->remote_version);
+
+ /* Free rest */
+ if (ske->prop) {
+ if (ske->prop->group)
+ silc_ske_group_free(ske->prop->group);
+ if (ske->prop->cipher)
+ silc_cipher_free(ske->prop->cipher);
+ if (ske->prop->hash)
+ silc_hash_free(ske->prop->hash);
+ if (ske->prop->hmac)
+ silc_hmac_free(ske->prop->hmac);
+ silc_free(ske->prop);
+ }
+ if (ske->start_payload_copy)
+ silc_buffer_free(ske->start_payload_copy);
+ if (ske->x) {
+ silc_mp_uninit(ske->x);
+ silc_free(ske->x);
+ }
+ if (ske->KEY) {
+ silc_mp_uninit(ske->KEY);
+ silc_free(ske->KEY);
}
+ silc_free(ske->hash);
+ silc_free(ske->callbacks);
+
+ memset(ske, 'F', sizeof(*ske));
+ silc_free(ske);
}
/* Return user context */
SilcSKEStatus status;
SilcSKEStartPayload payload;
SilcSKESecurityProperties prop;
- SilcSKEDiffieHellmanGroup group;
+ SilcSKEDiffieHellmanGroup group = NULL;
SilcBuffer packet_buf = &ske->packet->buffer;
SilcUInt16 remote_port = 0;
SilcID id;
err:
if (payload)
silc_ske_payload_start_free(payload);
-
- silc_ske_group_free(group);
-
+ if (group)
+ silc_ske_group_free(group);
if (prop->cipher)
silc_cipher_free(prop->cipher);
if (prop->hash)
ske->rekey, ske->callbacks->context);
silc_packet_free(ske->packet);
+ silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
return SILC_FSM_FINISH;
}
/* Send FAILURE packet */
SILC_PUT32_MSB(SILC_SKE_STATUS_ERROR, data);
silc_packet_send(ske->stream, SILC_PACKET_FAILURE, 0, data, 4);
+ silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
return SILC_FSM_FINISH;
}
ske->callbacks->completed(ske, ske->status, NULL, NULL, NULL,
ske->callbacks->context);
+ silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
+
return SILC_FSM_FINISH;
}
ske->callbacks->completed(ske, ske->status, NULL, NULL, NULL,
ske->callbacks->context);
+ silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
+
return SILC_FSM_FINISH;
}
void *destructor_context)
{
SilcSKE ske = fsm_context;
- silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
+
+ ske->running = FALSE;
+ if (ske->freed)
+ silc_ske_free(ske);
}
/* Starts the protocol as initiator */
ske->start_payload = start_payload;
ske->version = params->version;
+ ske->running = TRUE;
/* Link to packet stream to get key exchange packets */
ske->stream = stream;
ske->status = SILC_SKE_STATUS_BAD_PAYLOAD;
SILC_PUT32_MSB(ske->status, tmp);
silc_packet_send(ske->stream, SILC_PACKET_FAILURE, 0, tmp, 4);
-
silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
return SILC_FSM_FINISH;
static void silc_ske_responder_finished(SilcFSM fsm, void *fsm_context,
void *destructor_context)
{
+ SilcSKE ske = fsm_context;
+ ske->running = FALSE;
+ if (ske->freed)
+ silc_ske_free(ske);
}
/* Starts the protocol as responder. */
ske->version = strdup(params->version);
if (!ske->version)
return NULL;
+ ske->running = TRUE;
/* Link to packet stream to get key exchange packets */
ske->stream = stream;
{
return ske->prop;
}
+
+/* Get key material */
+
+SilcSKEKeyMaterial silc_ske_get_key_material(SilcSKE ske)
+{
+ return ske->keymat;
+}
SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH, /* Payload includes garbage */
SILC_SKE_STATUS_SIGNATURE_ERROR, /* Error computing signature */
SILC_SKE_STATUS_OUT_OF_MEMORY, /* System out of memory */
+ SILC_SKE_STATUS_TIMEOUT, /* Timeout */
} SilcSKEStatus;
/***/
* This context is returned after key exchange protocol to application
* in the completion callback. Application may save it and use it later
* to perform the rekey with silc_ske_rekey_initiator_start and/or
- * silc_ske_rekey_responder_start functions. If application does not
+ * silc_ske_rekey_responder functions. If application does not
* need the context, it may free it with silc_free function.
*
* Application may save application specific data to `user_context'.
SilcSKEParams params,
SilcSKEStartPayload start_payload);
-/****f* silcske/SilcSKEAPI/silc_ske_responder_start
+/****f* silcske/SilcSKEAPI/silc_ske_responder
*
* SYNOPSIS
*
***/
SilcSKESecurityProperties silc_ske_get_security_properties(SilcSKE ske);
+/****f* silcske/SilcSKEAPI/silc_ske_get_key_material
+ *
+ * SYNOPSIS
+ *
+ * SilcSKEKeyMaterial silc_ske_get_key_material(SilcSKE ske);
+ *
+ * DESCRIPTION
+ *
+ * Returns the negotiated key material from the `ske' or NULL if the
+ * key material does not exist. The caller must not free the returned
+ * pointer.
+ *
+ ***/
+SilcSKEKeyMaterial silc_ske_get_key_material(SilcSKE ske);
+
/****f* silcske/SilcSKEAPI/silc_ske_process_key_material_data
*
* SYNOPSIS