Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2000 - 2005 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
SILC_FSM_CALL_CONTINUE(&ske->fsm);
}
+/* SKR find callback */
+
+static void silc_ske_skr_callback(SilcSKR repository,
+ SilcSKRFind find,
+ SilcSKRStatus status,
+ SilcDList keys, void *context)
+{
+ SilcSKE ske = context;
+
+ silc_skr_find_free(find);
+
+ if (status != SILC_SKR_OK) {
+ if (ske->callbacks->verify_key) {
+ /* Verify from application */
+ ske->callbacks->verify_key(ske, ske->prop->public_key,
+ ske->callbacks->context,
+ silc_ske_pk_verified, NULL);
+ return;
+ }
+ }
+
+ if (keys)
+ silc_dlist_uninit(keys);
+
+ /* Continue */
+ ske->status = (status == SILC_SKR_OK ? SILC_SKE_STATUS_OK :
+ SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY);
+ SILC_FSM_CALL_CONTINUE(&ske->fsm);
+}
+
/* Checks remote and local versions */
static SilcSKEStatus silc_ske_check_version(SilcSKE ske)
payload->cookie_len = SILC_SKE_COOKIE_LEN;
memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
+ /* In case IV included flag and session port is set the first 16-bits of
+ cookie will include our session port. */
+ if (rp->flags & SILC_SKE_SP_FLAG_IV_INCLUDED && ske->session_port)
+ SILC_PUT16_MSB(ske->session_port, payload->cookie);
+
/* Put our version to our reply */
payload->version = strdup(ske->version);
if (!payload->version) {
return status;
}
+/* Assembles security properties */
+
+static SilcSKEStartPayload
+silc_ske_assemble_security_properties(SilcSKE ske,
+ SilcSKESecurityPropertyFlag flags,
+ const char *version)
+{
+ SilcSKEStartPayload rp;
+ int i;
+
+ SILC_LOG_DEBUG(("Assembling KE Start Payload"));
+
+ rp = silc_calloc(1, sizeof(*rp));
+
+ /* Set flags */
+ rp->flags = (unsigned char)flags;
+
+ /* Set random cookie */
+ rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
+ 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;
+
+ /* In case IV included flag and session port is set the first 16-bits of
+ cookie will include our session port. */
+ if (flags & SILC_SKE_SP_FLAG_IV_INCLUDED && ske->session_port)
+ SILC_PUT16_MSB(ske->session_port, rp->cookie);
+
+ /* Put version */
+ rp->version = strdup(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);
+
+ /* Get supported PKCS algorithms */
+ rp->pkcs_alg_list = silc_pkcs_get_supported();
+ 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);
+
+ /* Get supported hash algorithms */
+ rp->hash_alg_list = silc_hash_get_supported();
+ 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);
+
+ /* XXX */
+ /* Get supported compression algorithms */
+ rp->comp_alg_list = strdup("none");
+ rp->comp_alg_len = strlen("none");
+
+ rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
+ 2 + rp->version_len +
+ 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
+ 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
+ 2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
+
+ return rp;
+}
+
/******************************* Protocol API *******************************/
/* Allocates new SKE object. */
SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule,
- SilcPublicKey public_key, SilcPrivateKey private_key,
- void *context)
+ SilcSKR repository, SilcPublicKey public_key,
+ SilcPrivateKey private_key, void *context)
{
SilcSKE ske;
return NULL;
ske->status = SILC_SKE_STATUS_OK;
ske->rng = rng;
+ ske->repository = repository;
ske->user_data = context;
ske->schedule = schedule;
ske->public_key = public_key;
ske->private_key = private_key;
- ske->pk_type = SILC_SKE_PK_TYPE_SILC;
return ske;
}
SilcSKESecurityProperties prop;
SilcSKEDiffieHellmanGroup group;
SilcBuffer packet_buf = &ske->packet->buffer;
+ int coff = 0;
SILC_LOG_DEBUG(("Start"));
return SILC_FSM_CONTINUE;
}
- /* Check that the cookie is returned unmodified */
- if (memcmp(ske->start_payload->cookie, payload->cookie,
- ske->start_payload->cookie_len)) {
+ /* Check that the cookie is returned unmodified. In case IV included
+ flag and session port has been set, the first two bytes of cookie
+ are the session port and we ignore them in this check. */
+ if (payload->flags & SILC_SKE_SP_FLAG_IV_INCLUDED && ske->session_port)
+ coff = 2;
+ if (memcmp(ske->start_payload->cookie + coff, payload->cookie + coff,
+ SILC_SKE_COOKIE_LEN - coff)) {
/** Invalid cookie */
- SILC_LOG_ERROR(("Responder modified our cookie and it must not do it"));
+ SILC_LOG_ERROR(("Invalid cookie, modified or unsupported feature"));
ske->status = SILC_SKE_STATUS_INVALID_COOKIE;
silc_fsm_next(fsm, silc_ske_st_initiator_error);
return SILC_FSM_CONTINUE;
}
payload->pk_len = pk_len;
}
- payload->pk_type = ske->pk_type;
+ payload->pk_type = silc_pkcs_get_type(ske->public_key);
/* Compute signature data if we are doing mutual authentication */
if (ske->private_key &&
}
ske->ke2_payload = payload;
- if (!payload->pk_data && ske->callbacks->verify_key) {
+ if (!payload->pk_data && (ske->callbacks->verify_key || ske->repository)) {
SILC_LOG_DEBUG(("Remote end did not send its public key (or certificate), "
"even though we require it"));
ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
goto err;
}
- if (ske->prop->public_key && ske->callbacks->verify_key) {
+ if (ske->prop->public_key && (ske->callbacks->verify_key ||
+ ske->repository)) {
SILC_LOG_DEBUG(("Verifying public key"));
/** Waiting public key verification */
silc_fsm_next(fsm, silc_ske_st_initiator_phase4);
- SILC_FSM_CALL(ske->callbacks->verify_key(ske,
- payload->pk_type,
- ske->prop->public_key,
- ske->callbacks->context,
- silc_ske_pk_verified, NULL));
+
+ /* If repository is provided, verify the key from there. */
+ if (ske->repository) {
+ SilcSKRFind find;
+
+ find = silc_skr_find_alloc();
+ if (!find) {
+ status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+ goto err;
+ }
+ 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);
+
+ /* Find key from repository */
+ SILC_FSM_CALL(silc_skr_find(ske->repository, find,
+ silc_ske_skr_callback, ske));
+ } else {
+ /* Verify from application */
+ SILC_FSM_CALL(ske->callbacks->verify_key(ske, ske->prop->public_key,
+ ske->callbacks->context,
+ silc_ske_pk_verified, NULL));
+ }
/* NOT REACHED */
}
SilcAsyncOperation
silc_ske_initiator(SilcSKE ske,
SilcPacketStream stream,
+ SilcSKEParams params,
SilcSKEStartPayload start_payload)
{
SILC_LOG_DEBUG(("Start SKE as initiator"));
- if (!ske || !stream || !start_payload)
+ if (!ske || !stream || !params || !params->version)
return NULL;
if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
ske->schedule))
return NULL;
+ if (params->flags & SILC_SKE_SP_FLAG_IV_INCLUDED)
+ ske->session_port = params->session_port;
+
+ /* Generate security properties if not provided */
+ if (!start_payload) {
+ start_payload = silc_ske_assemble_security_properties(ske,
+ params->flags,
+ params->version);
+ if (!start_payload)
+ return NULL;
+ }
+
ske->start_payload = start_payload;
/* Link to packet stream to get key exchange packets */
SILC_LOG_DEBUG(("We are doing mutual authentication"));
- if (!recv_payload->pk_data && ske->callbacks->verify_key) {
+ if (!recv_payload->pk_data && (ske->callbacks->verify_key ||
+ ske->repository)) {
/** Public key not provided */
SILC_LOG_ERROR(("Remote end did not send its public key (or "
"certificate), even though we require it"));
return SILC_FSM_CONTINUE;
}
- if (ske->prop->public_key && ske->callbacks->verify_key) {
+ if (ske->prop->public_key && (ske->callbacks->verify_key ||
+ ske->repository)) {
SILC_LOG_DEBUG(("Verifying public key"));
/** Waiting public key verification */
silc_fsm_next(fsm, silc_ske_st_responder_phase4);
- SILC_FSM_CALL(ske->callbacks->verify_key(ske,
- recv_payload->pk_type,
- ske->prop->public_key,
- ske->callbacks->context,
- silc_ske_pk_verified, NULL));
+
+ /* 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);
+
+ /* Find key from repository */
+ SILC_FSM_CALL(silc_skr_find(ske->repository, find,
+ silc_ske_skr_callback, ske));
+ } else {
+ /* Verify from application */
+ SILC_FSM_CALL(ske->callbacks->verify_key(ske, ske->prop->public_key,
+ ske->callbacks->context,
+ silc_ske_pk_verified, NULL));
+ }
/* NOT REACHED */
}
}
ske->ke2_payload->sign_len = sign_len;
memset(sign, 0, sizeof(sign));
}
- ske->ke2_payload->pk_type = ske->pk_type;
+ ske->ke2_payload->pk_type = silc_pkcs_get_type(ske->public_key);
/* Encode the Key Exchange Payload */
status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
SilcAsyncOperation
silc_ske_responder(SilcSKE ske,
SilcPacketStream stream,
- const char *version,
- SilcSKESecurityPropertyFlag flags)
+ SilcSKEParams params)
{
SILC_LOG_DEBUG(("Start SKE as responder"));
- if (!ske || !stream || !version) {
+ if (!ske || !stream || !params || !params->version) {
return NULL;
}
ske->schedule))
return NULL;
- ske->flags = flags;
- ske->version = strdup(version);
+ ske->responder = TRUE;
+ ske->flags = params->flags;
+ if (ske->flags & SILC_SKE_SP_FLAG_IV_INCLUDED)
+ ske->session_port = params->session_port;
+ ske->version = strdup(params->version);
if (!ske->version)
return NULL;
- ske->responder = TRUE;
/* Link to packet stream to get key exchange packets */
ske->stream = stream;
return &ske->op;
}
-/* Assembles security properties */
-
-SilcSKEStartPayload
-silc_ske_assemble_security_properties(SilcSKE ske,
- SilcSKESecurityPropertyFlag flags,
- const char *version)
-{
- SilcSKEStartPayload rp;
- int i;
-
- SILC_LOG_DEBUG(("Assembling KE Start Payload"));
-
- rp = silc_calloc(1, sizeof(*rp));
-
- /* Set flags */
- rp->flags = (unsigned char)flags;
-
- /* Set random cookie */
- rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
- 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);
-
- /* Get supported Key Exhange groups */
- rp->ke_grp_list = silc_ske_get_supported_groups();
- 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);
-
- /* Get supported encryption algorithms */
- rp->enc_alg_list = silc_cipher_get_supported();
- 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);
-
- /* Get supported HMACs */
- rp->hmac_alg_list = silc_hmac_get_supported();
- rp->hmac_alg_len = strlen(rp->hmac_alg_list);
-
- /* XXX */
- /* Get supported compression algorithms */
- rp->comp_alg_list = strdup("none");
- rp->comp_alg_len = strlen("none");
-
- rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
- 2 + rp->version_len +
- 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
- 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
- 2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
-
- return rp;
-}
-
/* Processes the provided key material `data' as the SILC protocol
specification defines. */