From: Pekka Riikonen Date: Sat, 26 Nov 2005 13:26:41 +0000 (+0000) Subject: FSM based SKE protocol. Simpler interface. X-Git-Tag: silc.client.1.1.beta1~338 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=0f26cf62f47f8f882c942f947aec6588c7f6ba3d FSM based SKE protocol. Simpler interface. --- diff --git a/lib/silcske/payload.c b/lib/silcske/payload.c index d7fb301d..be670e46 100644 --- a/lib/silcske/payload.c +++ b/lib/silcske/payload.c @@ -1,10 +1,10 @@ /* - payload.c + payload.c Author: Pekka Riikonen - Copyright (C) 2000 - 2002 Pekka Riikonen + Copyright (C) 2000 - 2005 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 @@ -24,7 +24,7 @@ to the other end. */ SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske, - SilcSKEStartPayload *payload, + SilcSKEStartPayload payload, SilcBuffer *return_buffer) { SilcBuffer buf; @@ -44,10 +44,10 @@ SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske, SILC_STR_UI_CHAR(0), /* RESERVED field */ SILC_STR_UI_CHAR(payload->flags), SILC_STR_UI_SHORT(payload->len), - SILC_STR_UI_XNSTRING(payload->cookie, + SILC_STR_UI_XNSTRING(payload->cookie, payload->cookie_len), SILC_STR_UI_SHORT(payload->version_len), - SILC_STR_UI_XNSTRING(payload->version, + SILC_STR_UI_XNSTRING(payload->version, payload->version_len), SILC_STR_UI_SHORT(payload->ke_grp_len), SILC_STR_UI_XNSTRING(payload->ke_grp_list, @@ -76,7 +76,7 @@ SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske, /* Return the encoded buffer */ *return_buffer = buf; - SILC_LOG_HEXDUMP(("KE Start Payload"), buf->data, buf->len); + SILC_LOG_HEXDUMP(("KE Start Payload"), buf->data, silc_buffer_len(buf)); return SILC_SKE_STATUS_OK; } @@ -84,19 +84,20 @@ SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske, /* Parses the Key Exchange Start Payload. Parsed data is returned to allocated payload structure. */ -SilcSKEStatus +SilcSKEStatus silc_ske_payload_start_decode(SilcSKE ske, SilcBuffer buffer, - SilcSKEStartPayload **return_payload) + SilcSKEStartPayload *return_payload) { - SilcSKEStartPayload *payload; + SilcSKEStartPayload payload; SilcSKEStatus status = SILC_SKE_STATUS_ERROR; unsigned char tmp; int ret; SILC_LOG_DEBUG(("Decoding Key Exchange Start Payload")); - SILC_LOG_HEXDUMP(("KE Start Payload"), buffer->data, buffer->len); + SILC_LOG_HEXDUMP(("KE Start Payload"), buffer->data, + silc_buffer_len(buffer)); payload = silc_calloc(1, sizeof(*payload)); if (!payload) @@ -104,12 +105,12 @@ silc_ske_payload_start_decode(SilcSKE ske, payload->cookie_len = SILC_SKE_COOKIE_LEN; /* Parse start of the payload */ - ret = + ret = silc_buffer_unformat(buffer, SILC_STR_UI_CHAR(&tmp), /* RESERVED Field */ SILC_STR_UI_CHAR(&payload->flags), SILC_STR_UI_SHORT(&payload->len), - SILC_STR_UI_XNSTRING_ALLOC(&payload->cookie, + SILC_STR_UI_XNSTRING_ALLOC(&payload->cookie, payload->cookie_len), SILC_STR_UI16_NSTRING_ALLOC(&payload->version, &payload->version_len), @@ -138,7 +139,7 @@ silc_ske_payload_start_decode(SilcSKE ske, goto err; } - if (payload->len != buffer->len) { + if (payload->len != silc_buffer_len(buffer)) { SILC_LOG_ERROR(("Garbage after KE Start Payload")); status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH; goto err; @@ -168,7 +169,7 @@ silc_ske_payload_start_decode(SilcSKE ske, /* Free's Start Payload */ -void silc_ske_payload_start_free(SilcSKEStartPayload *payload) +void silc_ske_payload_start_free(SilcSKEStartPayload payload) { if (payload) { silc_free(payload->cookie); @@ -187,7 +188,7 @@ void silc_ske_payload_start_free(SilcSKEStartPayload *payload) end. */ SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske, - SilcSKEKEPayload *payload, + SilcSKEKEPayload payload, SilcBuffer *return_buffer) { SilcBuffer buf; @@ -200,7 +201,7 @@ SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske, if (!payload) return SILC_SKE_STATUS_ERROR; - if (ske->start_payload && + if (ske->start_payload && ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL && !payload->sign_data) { SILC_LOG_DEBUG(("Signature data is missing")); @@ -212,21 +213,21 @@ SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske, /* Allocate channel payload buffer. The length of the buffer is 4 + public key + 2 + x + 2 + signature. */ - buf = silc_buffer_alloc_size(4 + payload->pk_len + 2 + x_len + + buf = silc_buffer_alloc_size(4 + payload->pk_len + 2 + x_len + 2 + payload->sign_len); if (!buf) return SILC_SKE_STATUS_OUT_OF_MEMORY; /* Encode the payload */ - ret = silc_buffer_format(buf, + ret = silc_buffer_format(buf, SILC_STR_UI_SHORT(payload->pk_len), SILC_STR_UI_SHORT(payload->pk_type), - SILC_STR_UI_XNSTRING(payload->pk_data, + SILC_STR_UI_XNSTRING(payload->pk_data, payload->pk_len), SILC_STR_UI_SHORT(x_len), SILC_STR_UI_XNSTRING(x_str, x_len), SILC_STR_UI_SHORT(payload->sign_len), - SILC_STR_UI_XNSTRING(payload->sign_data, + SILC_STR_UI_XNSTRING(payload->sign_data, payload->sign_len), SILC_STR_END); if (ret == -1) { @@ -239,7 +240,7 @@ SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske, /* Return encoded buffer */ *return_buffer = buf; - SILC_LOG_HEXDUMP(("KE Payload"), buf->data, buf->len); + SILC_LOG_HEXDUMP(("KE Payload"), buf->data, silc_buffer_len(buf)); memset(x_str, 'F', x_len); silc_free(x_str); @@ -252,10 +253,10 @@ SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske, SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske, SilcBuffer buffer, - SilcSKEKEPayload **return_payload) + SilcSKEKEPayload *return_payload) { SilcSKEStatus status = SILC_SKE_STATUS_ERROR; - SilcSKEKEPayload *payload; + SilcSKEKEPayload payload; unsigned char *x = NULL; SilcUInt16 x_len; SilcUInt32 tot_len = 0, len2; @@ -263,13 +264,13 @@ SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske, SILC_LOG_DEBUG(("Decoding Key Exchange Payload")); - SILC_LOG_HEXDUMP(("KE Payload"), buffer->data, buffer->len); + SILC_LOG_HEXDUMP(("KE Payload"), buffer->data, silc_buffer_len(buffer)); payload = silc_calloc(1, sizeof(*payload)); if (!payload) return SILC_SKE_STATUS_OUT_OF_MEMORY; - len2 = buffer->len; + len2 = silc_buffer_len(buffer); /* Parse start of the payload */ ret = silc_buffer_unformat(buffer, @@ -283,7 +284,7 @@ SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske, } if (ske->start_payload && - ((payload->pk_type < SILC_SKE_PK_TYPE_SILC || + ((payload->pk_type < SILC_SKE_PK_TYPE_SILC || payload->pk_type > SILC_SKE_PK_TYPE_SPKI) || !payload->pk_len)) { SILC_LOG_ERROR(("Malformed public key in KE payload")); status = SILC_SKE_STATUS_BAD_PAYLOAD; @@ -298,7 +299,7 @@ SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske, SILC_STR_UI_XNSTRING_ALLOC(&payload->pk_data, payload->pk_len), SILC_STR_UI16_NSTRING_ALLOC(&x, &x_len), - SILC_STR_UI16_NSTRING_ALLOC(&payload->sign_data, + SILC_STR_UI16_NSTRING_ALLOC(&payload->sign_data, &payload->sign_len), SILC_STR_END); if (ret == -1) { @@ -316,7 +317,7 @@ SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske, goto err; } - if (ske->start_payload && + if (ske->start_payload && (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) && (payload->sign_len < 3 || !payload->sign_data)) { SILC_LOG_ERROR(("The signature data is missing - both parties are " @@ -330,7 +331,7 @@ SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske, status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH; goto err; } - + /* Decode the binary data to integer */ silc_mp_init(&payload->x); silc_mp_bin2mp(x, x_len, &payload->x); @@ -353,7 +354,7 @@ SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske, /* Free's KE Payload */ -void silc_ske_payload_ke_free(SilcSKEKEPayload *payload) +void silc_ske_payload_ke_free(SilcSKEKEPayload payload) { if (payload) { silc_free(payload->pk_data); diff --git a/lib/silcske/silcske.c b/lib/silcske/silcske.c index 26690f7a..7c04aa1f 100644 --- a/lib/silcske/silcske.c +++ b/lib/silcske/silcske.c @@ -30,31 +30,72 @@ static SilcSKEStatus silc_ske_make_hash(SilcSKE ske, unsigned char *return_hash, SilcUInt32 *return_hash_len, int initiator); +static SilcSKEStatus +silc_ske_select_security_properties(SilcSKE ske, + const char *version, + SilcSKEStartPayload payload, + SilcSKEStartPayload remote_payload); +SilcSKEKeyMaterial +silc_ske_process_key_material_data(unsigned char *data, + SilcUInt32 data_len, + SilcUInt32 req_iv_len, + SilcUInt32 req_enc_key_len, + SilcUInt32 req_hmac_key_len, + SilcHash hash); +SilcSKEKeyMaterial +silc_ske_process_key_material(SilcSKE ske, + SilcUInt32 req_iv_len, + SilcUInt32 req_enc_key_len, + SilcUInt32 req_hmac_key_len); +static void silc_ske_packet_receive(SilcPacketEngine engine, + SilcPacketStream stream, + SilcPacket packet, + void *callback_context, + void *app_context); +static void silc_ske_packet_eos(SilcPacketEngine engine, + SilcPacketStream stream, + void *callback_context, + void *app_context); +static void silc_ske_packet_error(SilcPacketEngine engine, + SilcPacketStream stream, + SilcPacketError error, + void *callback_context, + void *app_context); /* Structure to hold all SKE callbacks. */ struct SilcSKECallbacksStruct { - SilcSKESendPacketCb send_packet; - SilcSKECb payload_receive; SilcSKEVerifyCb verify_key; - SilcSKECb proto_continue; - SilcSKECheckVersion check_version; + SilcSKECheckVersionCb check_version; + SilcSKECompletionCb completed; void *context; }; +/* Packet stream callbacks */ +static SilcPacketCallbacks silc_ske_stream_cbs = +{ + silc_ske_packet_receive, + silc_ske_packet_eos, + silc_ske_packet_error +}; + /* Allocates new SKE object. */ -SilcSKE silc_ske_alloc(SilcRng rng, void *context) +SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule, void *context) { SilcSKE ske; SILC_LOG_DEBUG(("Allocating new Key Exchange object")); + if (!rng || !schedule) + return NULL; + ske = silc_calloc(1, sizeof(*ske)); if (!ske) return NULL; ske->status = SILC_SKE_STATUS_OK; ske->rng = rng; ske->user_data = context; + ske->schedule = schedule; ske->users = 1; return ske; @@ -117,45 +158,19 @@ void silc_ske_free(SilcSKE ske) } } -/* Sets the callback functions for the SKE session. - - The `send_packet' callback is a function that sends the packet to - network. The SKE library will call it at any time packet needs to - be sent to the remote host. - - The `payload_receive' callback is called when the remote host's Key - Exchange Start Payload has been processed. The payload is saved - to ske->start_payload if the application would need it. The application - must also provide the payload to the next state of the SKE. +/* Return user context */ - The `verify_key' callback is called to verify the received public key - or certificate. The verification process is most likely asynchronous. - That is why the application must call the completion callback when the - verification process has been completed. The library then calls the user - callback (`proto_continue'), if it is provided to indicate that the SKE - protocol may continue. - - The `proto_continue' callback is called to indicate that it is - safe to continue the execution of the SKE protocol after executing - an asynchronous operation, such as calling the `verify_key' callback - function, which is asynchronous. The application should check the - ske->status in this function to check whether it is Ok to continue - the execution of the protocol. - - The `check_version' callback is called to verify the remote host's - version. The application may check its own version against the remote - host's version and determine whether supporting the remote host - is possible. +void *silc_ske_get_context(SilcSKE ske) +{ + return ske->user_data; +} - The `context' is passed as argument to all of the above callback - functions. */ +/* Sets protocol callbacks */ void silc_ske_set_callbacks(SilcSKE ske, - SilcSKESendPacketCb send_packet, - SilcSKECb payload_receive, SilcSKEVerifyCb verify_key, - SilcSKECb proto_continue, - SilcSKECheckVersion check_version, + SilcSKECheckVersionCb check_version, + SilcSKECompletionCb completed, void *context) { if (ske->callbacks) @@ -163,87 +178,112 @@ void silc_ske_set_callbacks(SilcSKE ske, ske->callbacks = silc_calloc(1, sizeof(*ske->callbacks)); if (!ske->callbacks) return; - ske->callbacks->send_packet = send_packet; - ske->callbacks->payload_receive = payload_receive; ske->callbacks->verify_key = verify_key; - ske->callbacks->proto_continue = proto_continue; ske->callbacks->check_version = check_version; + ske->callbacks->completed = completed; ske->callbacks->context = context; } -/* Starts the SILC Key Exchange protocol for initiator. The connection - to the remote end must be established before calling this function - and the connecting socket must be sent as argument. This function - creates the Key Exchange Start Payload which includes all our - configured security properties. This payload is then sent to the - remote end for further processing. This payload must be sent as - argument to the function, however, it must not be encoded - already, it is done by this function. The caller must not free - the `start_payload' since the SKE library will save it. - - The packet sending is done by calling a callback function. Caller - must provide a routine to send the packet. */ - -SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng, - SilcSocketConnection sock, - SilcSKEStartPayload *start_payload) +/* Aborts SKE protocol */ + +static void silc_ske_abort(SilcAsyncOperation op, void *context) { - SilcSKEStatus status = SILC_SKE_STATUS_OK; + SilcSKE ske = context; + ske->aborted = TRUE; +} + +/* Public key verification completion callback */ + +static void silc_ske_pk_verified(SilcSKE ske, SilcSKEStatus status, + void *completion_context) +{ + SILC_FSM_CALL_CONTINUE(&ske->fsm); +} + +/* Initiator state machine */ +SILC_FSM_STATE(silc_ske_st_initiator_start); +SILC_FSM_STATE(silc_ske_st_initiator_phase1); +SILC_FSM_STATE(silc_ske_st_initiator_phase2); +SILC_FSM_STATE(silc_ske_st_initiator_phase3); +SILC_FSM_STATE(silc_ske_st_initiator_phase4); +SILC_FSM_STATE(silc_ske_st_initiator_end); +SILC_FSM_STATE(silc_ske_st_initiator_aborted); +SILC_FSM_STATE(silc_ske_st_initiator_error); + +/* Start protocol. Send our proposal */ + +SILC_FSM_STATE(silc_ske_st_initiator_start) +{ + SilcSKE ske = fsm_context; SilcBuffer payload_buf; + SilcStatus status; SILC_LOG_DEBUG(("Start")); - ske->sock = sock; - ske->rng = rng; + if (ske->aborted) { + /** Aborted */ + silc_fsm_next(fsm, silc_ske_st_initiator_aborted); + return SILC_FSM_CONTINUE; + } /* Encode the payload */ - status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf); - if (status != SILC_SKE_STATUS_OK) - return status; - - /* Send the packet. */ - if (ske->callbacks->send_packet) - (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, - ske->callbacks->context); + status = silc_ske_payload_start_encode(ske, ske->start_payload, + &payload_buf); + if (status != SILC_SKE_STATUS_OK) { + /** Error encoding Start Payload */ + ske->status = status; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; + } /* Save the the payload buffer for future use. It is later used to compute the HASH value. */ ske->start_payload_copy = payload_buf; - ske->start_payload = start_payload; - return status; + /* Send the packet */ + /* XXX */ + + /** Wait for responder proposal */ + SILC_LOG_DEBUG(("Waiting for reponder proposal")); + silc_fsm_next(ske, silc_ske_st_initiator_phase1); + return SILC_FSM_WAIT; } -/* Function called after ske_initiator_start fuction. This receives - the remote ends Key Exchange Start payload which includes the - security properties selected by the responder from our payload - sent in the silc_ske_initiator_start function. */ +/* Phase-1. Receives responder's proposal */ -SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, - SilcBuffer start_payload) +SILC_FSM_STATE(silc_ske_st_initiator_phase1) { - SilcSKEStatus status = SILC_SKE_STATUS_OK; - SilcSKEStartPayload *payload; + SilcSKE ske = fsm_context; + SilcSKEStatus status; + SilcSKEStartPayload payload; SilcSKESecurityProperties prop; SilcSKEDiffieHellmanGroup group; SILC_LOG_DEBUG(("Start")); + if (ske->aborted) { + /** Aborted */ + silc_fsm_next(fsm, silc_ske_st_initiator_aborted); + return SILC_FSM_CONTINUE; + } + /* Decode the payload */ - status = silc_ske_payload_start_decode(ske, start_payload, &payload); + status = silc_ske_payload_start_decode(ske, ske->packet_buf, &payload); if (status != SILC_SKE_STATUS_OK) { + /** Error decoding Start Payload */ ske->status = status; - silc_ske_payload_start_free(ske->start_payload); - return status; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; } /* Check that the cookie is returned unmodified */ if (memcmp(ske->start_payload->cookie, payload->cookie, ske->start_payload->cookie_len)) { + /** Invalid cookie */ SILC_LOG_ERROR(("Responder modified our cookie and it must not do it")); ske->status = SILC_SKE_STATUS_INVALID_COOKIE; - silc_ske_payload_start_free(ske->start_payload); - return status; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; } /* Check version string */ @@ -252,19 +292,20 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, payload->version_len, ske->callbacks->context); if (status != SILC_SKE_STATUS_OK) { + /** Version mismatch */ ske->status = status; - silc_ske_payload_start_free(ske->start_payload); - return status; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; } } /* Free our KE Start Payload context, we don't need it anymore. */ silc_ske_payload_start_free(ske->start_payload); + ske->start_payload = NULL; /* Take the selected security properties into use while doing - the key exchange. This is used only while doing the key - exchange. The same data is returned to upper levels by calling - the callback function. */ + the key exchange. This is used only while doing the key + exchange. */ ske->prop = prop = silc_calloc(1, sizeof(*prop)); if (!ske->prop) goto err; @@ -279,17 +320,14 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, status = SILC_SKE_STATUS_UNKNOWN_PKCS; goto err; } - if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) { status = SILC_SKE_STATUS_UNKNOWN_CIPHER; goto err; } - if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) { status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION; goto err; } - if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) { status = SILC_SKE_STATUS_UNKNOWN_HMAC; goto err; @@ -298,11 +336,9 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, /* Save remote's KE Start Payload */ ske->start_payload = payload; - /* Return the received payload by calling the callback function. */ - if (ske->callbacks->payload_receive) - (*ske->callbacks->payload_receive)(ske, ske->callbacks->context); - - return status; + /** Send KE Payload */ + silc_fsm_next(fsm, silc_ske_st_initiator_phase2); + return SILC_FSM_CONTINUE; err: if (payload) @@ -322,25 +358,23 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, ske->prop = NULL; if (status == SILC_SKE_STATUS_OK) - return SILC_SKE_STATUS_ERROR; + status = SILC_SKE_STATUS_ERROR; + /** Error */ ske->status = status; - return status; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; } -/* This function creates random number x, such that 1 < x < q and - computes e = g ^ x mod p and sends the result to the remote end in - Key Exchange Payload. */ +/* Phase-2. Send KE payload */ -SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, - SilcPublicKey public_key, - SilcPrivateKey private_key, - SilcSKEPKType pk_type) +SILC_FSM_STATE(silc_ske_st_initiator_phase2) { - SilcSKEStatus status = SILC_SKE_STATUS_OK; + SilcSKE ske = fsm_context; + SilcSKEStatus status; SilcBuffer payload_buf; SilcMPInt *x; - SilcSKEKEPayload *payload; + SilcSKEKEPayload payload; SilcUInt32 pk_len; SILC_LOG_DEBUG(("Start")); @@ -348,8 +382,10 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, /* Create the random number x, 1 < x < q. */ x = silc_calloc(1, sizeof(*x)); if (!x){ + /** Out of memory */ ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY; - return ske->status; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; } silc_mp_init(x); status = @@ -357,20 +393,24 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, silc_mp_sizeinbase(&ske->prop->group->group_order, 2), x); if (status != SILC_SKE_STATUS_OK) { + /** Error generating random number */ silc_mp_uninit(x); silc_free(x); ske->status = status; - return status; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; } /* Encode the result to Key Exchange Payload. */ payload = silc_calloc(1, sizeof(*payload)); if (!payload) { + /** Out of memory */ silc_mp_uninit(x); silc_free(x); ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY; - return ske->status; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; } ske->ke1_payload = payload; @@ -382,23 +422,26 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, &ske->prop->group->group); /* Get public key */ - if (public_key) { - payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len); + if (ske->public_key) { + payload->pk_data = silc_pkcs_public_key_encode(ske->public_key, &pk_len); if (!payload->pk_data) { + /** Error encoding public key */ silc_mp_uninit(x); silc_free(x); silc_mp_uninit(&payload->x); silc_free(payload); ske->ke1_payload = NULL; - ske->status = SILC_SKE_STATUS_OK; - return ske->status; + ske->status = SILC_SKE_STATUS_ERROR; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; } payload->pk_len = pk_len; } - payload->pk_type = pk_type; + payload->pk_type = ske->pk_type; /* Compute signature data if we are doing mutual authentication */ - if (private_key && ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) { + if (ske->private_key && + ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) { unsigned char hash[SILC_HASH_MAXLEN], sign[2048 + 1]; SilcUInt32 hash_len, sign_len; @@ -412,10 +455,11 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, SILC_LOG_DEBUG(("Signing HASH_i value")); /* Sign the hash value */ - silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, - private_key->prv_len); + silc_pkcs_private_key_data_set(ske->prop->pkcs, ske->private_key->prv, + ske->private_key->prv_len); if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 || !silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) { + /** Error computing signature */ silc_mp_uninit(x); silc_free(x); silc_mp_uninit(&payload->x); @@ -423,7 +467,8 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, silc_free(payload); ske->ke1_payload = NULL; ske->status = SILC_SKE_STATUS_SIGNATURE_ERROR; - return ske->status; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; } payload->sign_data = silc_memdup(sign, sign_len); payload->sign_len = sign_len; @@ -432,6 +477,7 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, status = silc_ske_payload_ke_encode(ske, payload, &payload_buf); if (status != SILC_SKE_STATUS_OK) { + /** Error encoding KE payload */ silc_mp_uninit(x); silc_free(x); silc_mp_uninit(&payload->x); @@ -440,68 +486,133 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, silc_free(payload); ske->ke1_payload = NULL; ske->status = status; - return status; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; } ske->x = x; /* Send the packet. */ - if (ske->callbacks->send_packet) - (*ske->callbacks->send_packet)(ske, payload_buf, - SILC_PACKET_KEY_EXCHANGE_1, - ske->callbacks->context); + /* XXX */ silc_buffer_free(payload_buf); - return status; + /** Waiting responder's KE payload */ + silc_fsm_next(fsm, silc_ske_st_initiator_phase3); + return SILC_FSM_WAIT; } -/* An initiator finish final callback that is called to indicate that - the SKE protocol may continue. */ +/* Phase-3. Process responder's KE payload */ -static void silc_ske_initiator_finish_final(SilcSKE ske, - SilcSKEStatus status, - void *context) +SILC_FSM_STATE(silc_ske_st_initiator_phase3) { - SilcSKEKEPayload *payload; + SilcSKE ske = fsm_context; + SilcSKEStatus status; + SilcSKEKEPayload payload; + SilcMPInt *KEY; + + SILC_LOG_DEBUG(("Start")); + + if (ske->aborted) { + /** Aborted */ + silc_fsm_next(fsm, silc_ske_st_initiator_aborted); + return SILC_FSM_CONTINUE; + } + + /* Decode the payload */ + status = silc_ske_payload_ke_decode(ske, ske->packet_buf, &payload); + if (status != SILC_SKE_STATUS_OK) { + /** Error decoding KE payload */ + ske->status = status; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; + } + ske->ke2_payload = payload; + + if (!payload->pk_data && ske->callbacks->verify_key) { + 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; + } + + SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p")); + + /* Compute the shared secret key */ + KEY = silc_calloc(1, sizeof(*KEY)); + silc_mp_init(KEY); + silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group); + ske->KEY = KEY; + + if (payload->pk_data && ske->callbacks->verify_key) { + 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_data, + payload->pk_len, + payload->pk_type, + ske->callbacks->context, + silc_ske_pk_verified, NULL)); + /* NOT REACHED */ + } + + /** Process key material */ + silc_fsm_next(fsm, silc_ske_st_initiator_phase4); + return SILC_FSM_CONTINUE; + + err: + silc_ske_payload_ke_free(payload); + ske->ke2_payload = NULL; + + silc_mp_uninit(ske->KEY); + silc_free(ske->KEY); + ske->KEY = NULL; + + if (status == SILC_SKE_STATUS_OK) + return SILC_SKE_STATUS_ERROR; + + /** Error */ + ske->status = status; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; +} + +/* Process key material */ + +SILC_FSM_STATE(silc_ske_st_initiator_phase4) +{ + SilcSKE ske = fsm_context; + SilcSKEStatus status; + SilcSKEKEPayload payload; unsigned char hash[SILC_HASH_MAXLEN]; SilcUInt32 hash_len; SilcPublicKey public_key = NULL; + int key_len, block_len; - /* If the SKE was freed during the async call then free it really now, - otherwise just decrement the reference counter. */ - if (ske->status == SILC_SKE_STATUS_FREED) { - silc_ske_free(ske); - return; + if (ske->aborted) { + /** Aborted */ + silc_fsm_next(fsm, silc_ske_st_initiator_aborted); + return SILC_FSM_CONTINUE; } - /* If the caller returns PENDING status SKE library will assume that - the caller will re-call this callback when it is not anymore in - PENDING status. */ - if (status == SILC_SKE_STATUS_PENDING) - return; + /* Check result of public key verification */ + 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; + } - ske->users--; payload = ske->ke2_payload; - /* If the status is an error then the public key that was verified - by the caller is not authentic. */ - if (status != SILC_SKE_STATUS_OK) { - ske->status = status; - if (ske->callbacks->proto_continue) - ske->callbacks->proto_continue(ske, ske->callbacks->context); - return; - } - if (payload->pk_data) { /* Decode the public key */ if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len, &public_key)) { - status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY; SILC_LOG_ERROR(("Unsupported/malformed public key received")); - if (ske->callbacks->proto_continue) - ske->callbacks->proto_continue(ske, ske->callbacks->context); - return; + status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY; + goto err; } SILC_LOG_DEBUG(("Public key is authentic")); @@ -533,11 +644,24 @@ static void silc_ske_initiator_finish_final(SilcSKE ske, ske->status = SILC_SKE_STATUS_OK; - /* Call the callback. The caller may now continue the SKE protocol. */ - if (ske->callbacks->proto_continue) - ske->callbacks->proto_continue(ske, ske->callbacks->context); + /* Process key material */ + key_len = silc_cipher_get_key_len(ske->prop->cipher); + block_len = silc_cipher_get_key_len(ske->prop->cipher); + hash_len = silc_hash_len(ske->prop->hash); + ske->keymat = silc_ske_process_key_material(ske, block_len, + key_len, hash_len); + if (!ske->keymat) { + SILC_LOG_ERROR(("Error processing key material")); + status = SILC_SKE_STATUS_ERROR; + goto err; + } - return; + /* Send SUCCESS packet */ + /* XXX */ + + /** Waiting completion */ + silc_fsm_next(fsm, silc_ske_st_initiator_end); + return SILC_FSM_WAIT; err: memset(hash, 'F', sizeof(hash)); @@ -558,185 +682,176 @@ static void silc_ske_initiator_finish_final(SilcSKE ske, } if (status == SILC_SKE_STATUS_OK) - ske->status = SILC_SKE_STATUS_ERROR; + status = SILC_SKE_STATUS_ERROR; + /** Error */ ske->status = status; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; +} + +/* Protocol completed */ + +SILC_FSM_STATE(silc_ske_st_initiator_end) +{ + SilcSKE ske = fsm_context; + + if (ske->aborted) { + /** Aborted */ + silc_fsm_next(fsm, silc_ske_st_initiator_aborted); + return SILC_FSM_CONTINUE; + } + + /* Call the completion callback */ + if (ske->callbacks->completed) + ske->callbacks->completed(ske, ske->status, NULL, NULL, NULL, NULL); - /* Call the callback. */ - if (ske->callbacks->proto_continue) - ske->callbacks->proto_continue(ske, ske->callbacks->context); + return SILC_FSM_FINISH; } -/* Receives Key Exchange Payload from responder consisting responders - public key, f, and signature. This function verifies the public key, - computes the secret shared key and verifies the signature. - - The `proto_continue' will be called to indicate that the caller may - continue with the SKE protocol. The caller must not continue - before the SKE libary has called that callback. If this function - returns an error the callback will not be called. It is called - if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING. - However, note that when the library calls the callback the ske->status - may be error. - - This calls the `verify_key' callback to verify the received public - key or certificate. If the `verify_key' is provided then the remote - must send public key and it is considered to be an error if remote - does not send its public key. If caller is performing a re-key with - SKE then the `verify_key' is usually not provided when it is not also - required for the remote to send its public key. */ - -SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske, - SilcBuffer ke_payload) +/* Aborted by application */ + +SILC_FSM_STATE(silc_ske_st_initiator_aborted) { - SilcSKEStatus status = SILC_SKE_STATUS_OK; - SilcSKEKEPayload *payload; - SilcMPInt *KEY; - SILC_LOG_DEBUG(("Start")); + return SILC_FSM_FINISH; +} - /* Decode the payload */ - status = silc_ske_payload_ke_decode(ske, ke_payload, &payload); - if (status != SILC_SKE_STATUS_OK) { - ske->status = status; - return status; - } - ske->ke2_payload = payload; +/* Error occurred */ - if (!payload->pk_data && ske->callbacks->verify_key) { - 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; - } +SILC_FSM_STATE(silc_ske_st_initiator_error) +{ - SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p")); + return SILC_FSM_FINISH; +} - /* Compute the shared secret key */ - KEY = silc_calloc(1, sizeof(*KEY)); - silc_mp_init(KEY); - silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group); - ske->KEY = KEY; - if (payload->pk_data && ske->callbacks->verify_key) { - SILC_LOG_DEBUG(("Verifying public key")); +static void silc_ske_initiator_finished(SilcFSM fsm, void *fsm_context, + void *destructor_context) +{ - ske->users++; - (*ske->callbacks->verify_key)(ske, payload->pk_data, payload->pk_len, - payload->pk_type, ske->callbacks->context, - silc_ske_initiator_finish_final, NULL); +} - /* We will continue to the final state after the public key has - been verified by the caller. */ - return SILC_SKE_STATUS_PENDING; - } +/* Starts the protocol as initiator */ - /* Continue to final state */ - ske->users++; - silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, NULL); +SilcAsyncOperation +silc_ske_initiator_start(SilcSKE ske, + SilcPacketStream stream, + SilcSKEStartPayload start_payload) +{ + SILC_LOG_DEBUG(("Start SKE as initiator")); - return SILC_SKE_STATUS_OK; + if (!ske || !stream || !start_payload) + return NULL; - err: - silc_ske_payload_ke_free(payload); - ske->ke2_payload = NULL; + if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske)) + return NULL; - silc_mp_uninit(ske->KEY); - silc_free(ske->KEY); - ske->KEY = NULL; + if (!silc_fsm_init(&ske->fsm, ske, silc_ske_initiator_finished, ske, + ske->schedule)) + return NULL; - if (status == SILC_SKE_STATUS_OK) - return SILC_SKE_STATUS_ERROR; + ske->start_payload = start_payload; - ske->status = status; - return status; + /* Link to packet stream to get key exchange packets */ + ske->stream = stream; + silc_packet_stream_ref(ske->stream); + silc_packet_stream_callbacks(ske->stream, &silc_ske_stream_cbs, ske); + + /* Start SKE as initiator */ + silc_fsm_start(&ske->fsm, silc_ske_st_initiator_start); + + return &ske->op; } -/* Starts Key Exchange protocol for responder. Responder receives - Key Exchange Start Payload from initiator consisting of all the - security properties the initiator supports. This function decodes - the payload and parses the payload further and selects the right - security properties. */ - -SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng, - SilcSocketConnection sock, - const char *version, - SilcBuffer start_payload, - SilcSKESecurityPropertyFlag flags) +/* Responder state machine */ +SILC_FSM_STATE(silc_ske_st_responder_start); +SILC_FSM_STATE(silc_ske_st_responder_phase1); +SILC_FSM_STATE(silc_ske_st_responder_phase2); +SILC_FSM_STATE(silc_ske_st_responder_phase3); +SILC_FSM_STATE(silc_ske_st_responder_phase4); +SILC_FSM_STATE(silc_ske_st_responder_end); +SILC_FSM_STATE(silc_ske_st_responder_aborted); +SILC_FSM_STATE(silc_ske_st_responder_error); + +/* Start protocol as responder. Decode initiator's start payload */ + +SILC_FSM_STATE(silc_ske_st_responder_start) { - SilcSKEStatus status = SILC_SKE_STATUS_OK; - SilcSKEStartPayload *remote_payload = NULL, *payload = NULL; + SilcSKE ske = fsm_context; + SilcSKEStatus status; + SilcSKEStartPayload remote_payload = NULL, payload = NULL; SILC_LOG_DEBUG(("Start")); - ske->sock = sock; - ske->rng = rng; + if (ske->aborted) { + /** Aborted */ + silc_fsm_next(fsm, silc_ske_st_responder_aborted); + return SILC_FSM_CONTINUE; + } /* Decode the payload */ - status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload); + status = silc_ske_payload_start_decode(ske, ske->packet_buf, + &remote_payload); if (status != SILC_SKE_STATUS_OK) { + /** Error decoding Start Payload */ ske->status = status; - return status; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; } /* 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(start_payload); + ske->start_payload_copy = silc_buffer_copy(ske->packet_buf); /* Force the mutual authentication flag if we want to do it. */ - if (flags & SILC_SKE_SP_FLAG_MUTUAL) { + if (ske->flags & SILC_SKE_SP_FLAG_MUTUAL) { SILC_LOG_DEBUG(("Force mutual authentication")); remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL; } /* Force PFS flag if we require it */ - if (flags & SILC_SKE_SP_FLAG_PFS) { + if (ske->flags & SILC_SKE_SP_FLAG_PFS) { SILC_LOG_DEBUG(("Force PFS")); remote_payload->flags |= SILC_SKE_SP_FLAG_PFS; } /* Disable IV Included flag if requested */ if (remote_payload->flags & SILC_SKE_SP_FLAG_IV_INCLUDED && - !(flags & SILC_SKE_SP_FLAG_IV_INCLUDED)) { + !(ske->flags & SILC_SKE_SP_FLAG_IV_INCLUDED)) { SILC_LOG_DEBUG(("We do not support IV Included flag")); remote_payload->flags &= ~SILC_SKE_SP_FLAG_IV_INCLUDED; } /* Parse and select the security properties from the payload */ payload = silc_calloc(1, sizeof(*payload)); - status = silc_ske_select_security_properties(ske, version, + status = silc_ske_select_security_properties(ske, ske->version, payload, remote_payload); - if (status != SILC_SKE_STATUS_OK) - goto err; + if (status != SILC_SKE_STATUS_OK) { + /** Error selecting proposal */ + if (remote_payload) + silc_ske_payload_start_free(remote_payload); + silc_free(payload); + ske->status = status; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } ske->start_payload = payload; - /* Call the callback function. */ - if (ske->callbacks->payload_receive) - (*ske->callbacks->payload_receive)(ske, ske->callbacks->context); - silc_ske_payload_start_free(remote_payload); - return status; - - err: - if (remote_payload) - silc_ske_payload_start_free(remote_payload); - silc_free(payload); - - if (status == SILC_SKE_STATUS_OK) - return SILC_SKE_STATUS_ERROR; - - ske->status = status; - return status; + /** Send proposal to initiator */ + silc_fsm_next(fsm, silc_ske_st_responder_phase1); + return SILC_FSM_CONTINUE; } -/* The selected security properties from the initiator payload is now - encoded into Key Exchange Start Payload and sent to the initiator. */ +/* Phase-1. Send Start Payload */ -SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske) +SILC_FSM_STATE(silc_ske_st_responder_phase1) { - SilcSKEStatus status = SILC_SKE_STATUS_OK; + SilcSKE ske = fsm_context; + SilcSKEStatus status; SilcBuffer payload_buf; SilcSKESecurityProperties prop; SilcSKEDiffieHellmanGroup group = NULL; @@ -758,19 +873,16 @@ SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske) status = SILC_SKE_STATUS_UNKNOWN_PKCS; goto err; } - if (silc_cipher_alloc(ske->start_payload->enc_alg_list, &prop->cipher) == FALSE) { status = SILC_SKE_STATUS_UNKNOWN_CIPHER; goto err; } - if (silc_hash_alloc(ske->start_payload->hash_alg_list, &prop->hash) == FALSE) { status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION; goto err; } - if (silc_hmac_alloc(ske->start_payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) { status = SILC_SKE_STATUS_UNKNOWN_HMAC; @@ -784,13 +896,13 @@ SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske) goto err; /* Send the packet. */ - if (ske->callbacks->send_packet) - (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, - ske->callbacks->context); + /* XXX */ silc_buffer_free(payload_buf); - return status; + /** Waiting initiator's KE payload */ + silc_fsm_next(fsm, silc_ske_st_responder_phase2); + return SILC_FSM_WAIT; err: if (group) @@ -808,47 +920,101 @@ SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske) ske->prop = NULL; if (status == SILC_SKE_STATUS_OK) - return SILC_SKE_STATUS_ERROR; + status = SILC_SKE_STATUS_ERROR; + /** Error */ ske->status = status; - return status; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; } -/* An responder phase 2 final callback that is called to indicate that - the SKE protocol may continue. */ +/* Phase-2. Decode initiator's KE payload */ -static void silc_ske_responder_phase2_final(SilcSKE ske, - SilcSKEStatus status, - void *context) +SILC_FSM_STATE(silc_ske_st_responder_phase2) { - SilcSKEKEPayload *recv_payload, *send_payload; - SilcMPInt *x; - - /* If the SKE was freed during the async call then free it really now, - otherwise just decrement the reference counter. */ - if (ske->status == SILC_SKE_STATUS_FREED) { - silc_ske_free(ske); - return; - } + SilcSKE ske = fsm_context; + SilcSKEStatus status; + SilcSKEKEPayload recv_payload; - /* If the caller returns PENDING status SKE library will assume that - the caller will re-call this callback when it is not anymore in - PENDING status. */ - if (status == SILC_SKE_STATUS_PENDING) - return; + SILC_LOG_DEBUG(("Start")); - ske->users--; - recv_payload = ske->ke1_payload; + if (ske->aborted) { + /** Aborted */ + silc_fsm_next(fsm, silc_ske_st_responder_aborted); + return SILC_FSM_CONTINUE; + } - /* If the status is an error then the public key that was verified - by the caller is not authentic. */ + /* Decode Key Exchange Payload */ + status = silc_ske_payload_ke_decode(ske, ske->packet_buf, &recv_payload); if (status != SILC_SKE_STATUS_OK) { + /** Error decoding KE payload */ ske->status = status; - if (ske->callbacks->proto_continue) - ske->callbacks->proto_continue(ske, ske->callbacks->context); - return; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; } + ske->ke1_payload = recv_payload; + + /* 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) { + /** Public key not provided */ + SILC_LOG_ERROR(("Remote end did not send its public key (or " + "certificate), even though we require it")); + ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } + + if (recv_payload->pk_data && ske->callbacks->verify_key) { + SILC_LOG_DEBUG(("Verifying public key")); + + /** Waiting public key verification */ + silc_fsm_next(fsm, silc_ske_st_responder_phase3); + SILC_FSM_CALL(ske->callbacks->verify_key(ske, recv_payload->pk_data, + recv_payload->pk_len, + recv_payload->pk_type, + ske->callbacks->context, + silc_ske_pk_verified, NULL)); + /* NOT REACHED */ + } + } + + /** Generate KE2 payload */ + silc_fsm_next(fsm, silc_ske_st_responder_phase3); + return SILC_FSM_CONTINUE; +} + +/* Phase-3. Generate KE2 payload */ + +SILC_FSM_STATE(silc_ske_st_responder_phase3) +{ + SilcSKE ske = fsm_context; + SilcSKEStatus status; + SilcSKEKEPayload recv_payload, send_payload; + SilcMPInt *x, *KEY; + + if (ske->aborted) { + /** Aborted */ + silc_fsm_next(fsm, silc_ske_st_responder_aborted); + return SILC_FSM_CONTINUE; + } + + /* Check result of public key verification */ + 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; + } + + recv_payload = ske->ke1_payload; + /* The public key verification was performed only if the Mutual Authentication flag is set. */ if (ske->start_payload && @@ -861,11 +1027,11 @@ static void silc_ske_responder_phase2_final(SilcSKE ske, if (!silc_pkcs_public_key_decode(recv_payload->pk_data, recv_payload->pk_len, &public_key)) { - ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY; + /** Error decoding public key */ SILC_LOG_ERROR(("Unsupported/malformed public key received")); - if (ske->callbacks->proto_continue) - ske->callbacks->proto_continue(ske, ske->callbacks->context); - return; + ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; } SILC_LOG_DEBUG(("Public key is authentic")); @@ -873,10 +1039,10 @@ static void silc_ske_responder_phase2_final(SilcSKE ske, /* Compute the hash value */ status = silc_ske_make_hash(ske, hash, &hash_len, TRUE); if (status != SILC_SKE_STATUS_OK) { + /** Error computing hash */ ske->status = status; - if (ske->callbacks->proto_continue) - ske->callbacks->proto_continue(ske, ske->callbacks->context); - return; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; } SILC_LOG_DEBUG(("Verifying signature (HASH_i)")); @@ -885,11 +1051,11 @@ static void silc_ske_responder_phase2_final(SilcSKE ske, silc_pkcs_public_key_set(ske->prop->pkcs, public_key); if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data, recv_payload->sign_len, hash, hash_len) == FALSE) { + /** Incorrect signature */ SILC_LOG_ERROR(("Signature verification failed, incorrect signature")); ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE; - if (ske->callbacks->proto_continue) - ske->callbacks->proto_continue(ske, ske->callbacks->context); - return; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; } SILC_LOG_DEBUG(("Signature is Ok")); @@ -906,12 +1072,12 @@ static void silc_ske_responder_phase2_final(SilcSKE ske, silc_mp_sizeinbase(&ske->prop->group->group_order, 2), x); if (status != SILC_SKE_STATUS_OK) { + /** Error generating random number */ silc_mp_uninit(x); silc_free(x); ske->status = status; - if (ske->callbacks->proto_continue) - ske->callbacks->proto_continue(ske, ske->callbacks->context); - return; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; } /* Save the results for later processing */ @@ -926,119 +1092,42 @@ static void silc_ske_responder_phase2_final(SilcSKE ske, silc_mp_pow_mod(&send_payload->x, &ske->prop->group->generator, x, &ske->prop->group->group); - /* Call the callback. The caller may now continue with the SKE protocol. */ - ske->status = SILC_SKE_STATUS_OK; - if (ske->callbacks->proto_continue) - ske->callbacks->proto_continue(ske, ske->callbacks->context); -} - -/* This function receives the Key Exchange Payload from the initiator. - This also performs the mutual authentication if required. Then, this - function first generated a random number x, such that 1 < x < q - and computes f = g ^ x mod p. This then puts the result f to a Key - Exchange Payload. - - The `proto_continue' will be called to indicate that the caller may - continue with the SKE protocol. The caller must not continue - before the SKE libary has called that callback. If this function - returns an error the callback will not be called. It is called - if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING. - However, note that when the library calls the callback the ske->status - may be error. - - This calls the `verify_key' callback to verify the received public - key or certificate if the Mutual Authentication flag is set. If the - `verify_key' is provided then the remote must send public key and it - is considered to be an error if remote does not send its public key. */ - -SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske, - SilcBuffer ke_payload) -{ - SilcSKEStatus status = SILC_SKE_STATUS_OK; - SilcSKEKEPayload *recv_payload; - - SILC_LOG_DEBUG(("Start")); - - /* Decode Key Exchange Payload */ - status = silc_ske_payload_ke_decode(ske, ke_payload, &recv_payload); - if (status != SILC_SKE_STATUS_OK) { - ske->status = status; - return status; - } - - ske->ke1_payload = recv_payload; - - /* 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) { - SILC_LOG_ERROR(("Remote end did not send its public key (or " - "certificate), even though we require it")); - ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED; - return status; - } - - if (recv_payload->pk_data && ske->callbacks->verify_key) { - SILC_LOG_DEBUG(("Verifying public key")); - - ske->users++; - (*ske->callbacks->verify_key)(ske, recv_payload->pk_data, - recv_payload->pk_len, - recv_payload->pk_type, - ske->callbacks->context, - silc_ske_responder_phase2_final, NULL); - - /* We will continue to the final state after the public key has - been verified by the caller. */ - return SILC_SKE_STATUS_PENDING; - } - } + SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p")); - /* Continue to final state */ - ske->users++; - silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL); + /* Compute the shared secret key */ + KEY = silc_calloc(1, sizeof(*KEY)); + silc_mp_init(KEY); + silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x, + &ske->prop->group->group); + ske->KEY = KEY; - return SILC_SKE_STATUS_OK; + /** Send KE2 payload */ + silc_fsm_next(fsm, silc_ske_st_responder_phase4); + return SILC_FSM_CONTINUE; } -/* This functions generates the secret key KEY = e ^ x mod p, and, a hash - value to be signed and sent to the other end. This then encodes Key - Exchange Payload and sends it to the other end. */ +/* Phase-4. Send KE2 payload */ -SilcSKEStatus silc_ske_responder_finish(SilcSKE ske, - SilcPublicKey public_key, - SilcPrivateKey private_key, - SilcSKEPKType pk_type) +SILC_FSM_STATE(silc_ske_st_responder_phase4) { - SilcSKEStatus status = SILC_SKE_STATUS_OK; + SilcSKE ske = fsm_context; + SilcSKEStatus status; SilcBuffer payload_buf; - SilcMPInt *KEY; unsigned char hash[SILC_HASH_MAXLEN], sign[2048 + 1], *pk; SilcUInt32 hash_len, sign_len, pk_len; SILC_LOG_DEBUG(("Start")); - SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p")); - - /* Compute the shared secret key */ - KEY = silc_calloc(1, sizeof(*KEY)); - silc_mp_init(KEY); - silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x, - &ske->prop->group->group); - ske->KEY = KEY; - - if (public_key && private_key) { + if (ske->public_key && ske->private_key) { SILC_LOG_DEBUG(("Getting public key")); /* Get the public key */ - pk = silc_pkcs_public_key_encode(public_key, &pk_len); + pk = silc_pkcs_public_key_encode(ske->public_key, &pk_len); if (!pk) { + /** Error encoding public key */ status = SILC_SKE_STATUS_OUT_OF_MEMORY; - goto err; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; } ske->ke2_payload->pk_data = pk; ske->ke2_payload->pk_len = pk_len; @@ -1048,8 +1137,12 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske, /* 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) - goto err; + 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; @@ -1057,107 +1150,211 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske, SILC_LOG_DEBUG(("Signing HASH value")); /* Sign the hash value */ - silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, - private_key->prv_len); + silc_pkcs_private_key_data_set(ske->prop->pkcs, ske->private_key->prv, + ske->private_key->prv_len); if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 || !silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) { + /** Error computing signature */ status = SILC_SKE_STATUS_SIGNATURE_ERROR; - goto err; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; } ske->ke2_payload->sign_data = silc_memdup(sign, sign_len); ske->ke2_payload->sign_len = sign_len; memset(sign, 0, sizeof(sign)); } - ske->ke2_payload->pk_type = pk_type; + ske->ke2_payload->pk_type = ske->pk_type; /* Encode the Key Exchange Payload */ status = silc_ske_payload_ke_encode(ske, ske->ke2_payload, &payload_buf); - if (status != SILC_SKE_STATUS_OK) - goto err; + if (status != SILC_SKE_STATUS_OK) { + /** Error encoding KE payload */ + ske->status = status; + silc_fsm_next(fsm, silc_ske_st_responder_error); + return SILC_FSM_CONTINUE; + } /* Send the packet. */ - if (ske->callbacks->send_packet) - (*ske->callbacks->send_packet)(ske, payload_buf, - SILC_PACKET_KEY_EXCHANGE_2, - ske->callbacks->context); + /* XXX */ silc_buffer_free(payload_buf); - return status; + /** Waiting completion */ + silc_fsm_next(fsm, silc_ske_st_responder_end); + return SILC_FSM_WAIT; +} - err: - silc_mp_uninit(ske->KEY); - silc_free(ske->KEY); - ske->KEY = NULL; - silc_ske_payload_ke_free(ske->ke2_payload); +/* Protocol completed */ - if (status == SILC_SKE_STATUS_OK) - return SILC_SKE_STATUS_ERROR; +SILC_FSM_STATE(silc_ske_st_responder_end) +{ + SilcSKE ske = fsm_context; - ske->status = status; - return status; + if (ske->aborted) { + /** Aborted */ + silc_fsm_next(fsm, silc_ske_st_responder_aborted); + return SILC_FSM_CONTINUE; + } + + /* Call the completion callback */ + if (ske->callbacks->completed) + ske->callbacks->completed(ske, ske->status, NULL, NULL, NULL, NULL); + + return SILC_FSM_FINISH; } -/* The Key Exchange protocol is ended by calling this function. This - must not be called until the keys are processed like the protocol - defines. This function is for both initiator and responder. */ +/* Aborted by application */ -SilcSKEStatus silc_ske_end(SilcSKE ske) +SILC_FSM_STATE(silc_ske_st_responder_aborted) { - SilcBufferStruct packet; - unsigned char data[4]; - SILC_LOG_DEBUG(("Start")); + /* Send FAILURE */ - SILC_PUT32_MSB((SilcUInt32)SILC_SKE_STATUS_OK, data); - silc_buffer_set(&packet, data, 4); + return SILC_FSM_FINISH; +} - if (ske->callbacks->send_packet) - (*ske->callbacks->send_packet)(ske, &packet, SILC_PACKET_SUCCESS, - ske->callbacks->context); +/* Error occurred */ - return SILC_SKE_STATUS_OK; +SILC_FSM_STATE(silc_ske_st_responder_error) +{ + + /* Send FAILURE */ + + return SILC_FSM_FINISH; } -/* Aborts the Key Exchange protocol. This is called if error occurs - while performing the protocol. The status argument is the error - status and it is sent to the remote end. */ -SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status) +static void silc_ske_responder_finished(SilcFSM fsm, void *fsm_context, + void *destructor_context) { - SilcBufferStruct packet; - unsigned char data[4]; - SILC_LOG_DEBUG(("Start")); +} - if (status > SILC_SKE_STATUS_INVALID_COOKIE) - status = SILC_SKE_STATUS_BAD_PAYLOAD; +/* Starts the protocol as responder. */ - SILC_PUT32_MSB((SilcUInt32)status, data); - silc_buffer_set(&packet, data, 4); +SilcAsyncOperation +silc_ske_responder_start(SilcSKE ske, + SilcPacketStream stream, + const char *version, + SilcBuffer start_payload, + SilcSKESecurityPropertyFlag flags) +{ + SILC_LOG_DEBUG(("Start SKE as responder")); - if (ske->callbacks->send_packet) - (*ske->callbacks->send_packet)(ske, &packet, SILC_PACKET_FAILURE, - ske->callbacks->context); + if (!ske || !stream || !start_payload) + return NULL; - return SILC_SKE_STATUS_OK; + if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske)) + return NULL; + + if (!silc_fsm_init(&ske->fsm, ske, silc_ske_responder_finished, ske, + ske->schedule)) + return NULL; + + ske->packet_buf = start_payload; + ske->flags = flags; + ske->version = strdup(version); + + /* Link to packet stream to get key exchange packets */ + ske->stream = stream; + silc_packet_stream_ref(ske->stream); + silc_packet_stream_callbacks(ske->stream, &silc_ske_stream_cbs, ske); + + /* Start SKE as responder */ + silc_fsm_start(&ske->fsm, silc_ske_st_initiator_start); + + return &ske->op; +} + +SILC_FSM_STATE(silc_ske_st_rekey_initiator_start); + +SILC_FSM_STATE(silc_ske_st_rekey_initiator_start) +{ + +} + +/* Starts rekey protocol as initiator */ + +SilcAsyncOperation +silc_ske_rekey_initiator_start(SilcSKE ske, + SilcPacketStream stream, + SilcSKERekeyMaterial rekey) +{ + SILC_LOG_DEBUG(("Start SKE rekey as initator")); + + if (!ske || !stream || !rekey) + return NULL; + + if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske)) + return NULL; + + if (!silc_fsm_init(&ske->fsm, ske, NULL, NULL, ske->schedule)) + return NULL; + + ske->rekey = rekey; + + /* Link to packet stream to get key exchange packets */ + ske->stream = stream; + silc_packet_stream_ref(ske->stream); + silc_packet_stream_callbacks(ske->stream, &silc_ske_stream_cbs, ske); + + /* Start SKE rekey as initiator */ + silc_fsm_start(&ske->fsm, silc_ske_st_rekey_initiator_start); + + return &ske->op; +} + +SILC_FSM_STATE(silc_ske_st_rekey_responder_start); + +SILC_FSM_STATE(silc_ske_st_rekey_responder_start) +{ + +} + +/* Starts rekey protocol as responder */ + +SilcAsyncOperation +silc_ske_rekey_responder_start(SilcSKE ske, + SilcPacketStream stream, + SilcBuffer ke_payload, + SilcSKERekeyMaterial rekey) +{ + SILC_LOG_DEBUG(("Start SKE rekey as responder")); + + if (!ske || !stream || !rekey) + return NULL; + if (rekey->pfs && !ke_payload) + return NULL; + + if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske)) + return NULL; + + if (!silc_fsm_init(&ske->fsm, ske, NULL, NULL, ske->schedule)) + return NULL; + + ske->packet_buf = ke_payload; + ske->rekey = rekey; + + /* Link to packet stream to get key exchange packets */ + ske->stream = stream; + silc_packet_stream_ref(ske->stream); + silc_packet_stream_callbacks(ske->stream, &silc_ske_stream_cbs, ske); + + /* Start SKE rekey as responder */ + silc_fsm_start(&ske->fsm, silc_ske_st_rekey_responder_start); + + return &ske->op; } -/* Assembles security properties to Key Exchange Start Payload to be - sent to the remote end. This checks system wide (SILC system, that is) - settings and chooses from those. However, if other properties - should be used this function is easy to replace by another function, - as, this function is called by the caller of the protocol and not - by the protocol itself. */ +/* Assembles security properties */ -SilcSKEStatus +SilcSKEStartPayload silc_ske_assemble_security_properties(SilcSKE ske, SilcSKESecurityPropertyFlag flags, - const char *version, - SilcSKEStartPayload **return_payload) + const char *version) { - SilcSKEStartPayload *rp; + SilcSKEStartPayload rp; int i; SILC_LOG_DEBUG(("Assembling KE Start Payload")); @@ -1208,22 +1405,20 @@ silc_ske_assemble_security_properties(SilcSKE ske, 2 + rp->enc_alg_len + 2 + rp->hash_alg_len + 2 + rp->hmac_alg_len + 2 + rp->comp_alg_len; - *return_payload = rp; - - return SILC_SKE_STATUS_OK; + return rp; } /* Selects the supported security properties from the remote end's Key Exchange Start Payload. */ -SilcSKEStatus +static SilcSKEStatus silc_ske_select_security_properties(SilcSKE ske, const char *version, - SilcSKEStartPayload *payload, - SilcSKEStartPayload *remote_payload) + SilcSKEStartPayload payload, + SilcSKEStartPayload remote_payload) { SilcSKEStatus status; - SilcSKEStartPayload *rp; + SilcSKEStartPayload rp; char *cp; int len; @@ -1637,7 +1832,7 @@ static SilcSKEStatus silc_ske_make_hash(SilcSKE ske, KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len); /* Format the buffer used to compute the hash value */ - buf = silc_buffer_alloc_size(ske->start_payload_copy->len + + buf = silc_buffer_alloc_size(silc_buffer_len(ske->start_payload_copy) + ske->ke2_payload->pk_len + ske->ke1_payload->pk_len + e_len + f_len + KEY_len); @@ -1648,10 +1843,9 @@ 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, - ske->start_payload_copy-> - len), + 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), @@ -1661,10 +1855,9 @@ static SilcSKEStatus silc_ske_make_hash(SilcSKE ske, } else { ret = silc_buffer_format(buf, - SILC_STR_UI_XNSTRING(ske->start_payload_copy-> - data, - ske->start_payload_copy-> - len), + 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, @@ -1694,8 +1887,8 @@ static SilcSKEStatus silc_ske_make_hash(SilcSKE ske, } else { e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len); - buf = silc_buffer_alloc_size(ske->start_payload_copy->len + - ske->ke1_payload->pk_len + e_len); + buf = silc_buffer_alloc_size(silc_buffer_len(ske->start_payload_copy) + + ske->ke1_payload->pk_len + e_len); if (!buf) return SILC_SKE_STATUS_OUT_OF_MEMORY; @@ -1703,7 +1896,7 @@ static SilcSKEStatus silc_ske_make_hash(SilcSKE ske, ret = silc_buffer_format(buf, SILC_STR_UI_XNSTRING(ske->start_payload_copy->data, - ske->start_payload_copy->len), + 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), @@ -1720,7 +1913,8 @@ static SilcSKEStatus silc_ske_make_hash(SilcSKE ske, } /* Make the hash */ - silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash); + silc_hash_make(ske->prop->hash, buf->data, silc_buffer_len(buf), + return_hash); *return_hash_len = silc_hash_len(ske->prop->hash); if (initiator == FALSE) { @@ -1737,28 +1931,28 @@ static SilcSKEStatus silc_ske_make_hash(SilcSKE ske, /* Processes the provided key material `data' as the SILC protocol specification defines. */ -SilcSKEStatus +SilcSKEKeyMaterial silc_ske_process_key_material_data(unsigned char *data, SilcUInt32 data_len, SilcUInt32 req_iv_len, SilcUInt32 req_enc_key_len, SilcUInt32 req_hmac_key_len, - SilcHash hash, - SilcSKEKeyMaterial *key) + SilcHash hash) { SilcBuffer buf; unsigned char hashd[SILC_HASH_MAXLEN]; SilcUInt32 hash_len = req_hmac_key_len; SilcUInt32 enc_key_len = req_enc_key_len / 8; + SilcSKEKeyMaterial key; SILC_LOG_DEBUG(("Start")); if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len) - return SILC_SKE_STATUS_ERROR; + return NULL; buf = silc_buffer_alloc_size(1 + data_len); if (!buf) - return SILC_SKE_STATUS_OUT_OF_MEMORY; + return NULL; silc_buffer_format(buf, SILC_STR_UI_CHAR(0), SILC_STR_UI_XNSTRING(data, data_len), @@ -1767,12 +1961,12 @@ silc_ske_process_key_material_data(unsigned char *data, /* Take IVs */ memset(hashd, 0, sizeof(hashd)); buf->data[0] = 0; - silc_hash_make(hash, buf->data, buf->len, hashd); + silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd); key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char)); memcpy(key->send_iv, hashd, req_iv_len); memset(hashd, 0, sizeof(hashd)); buf->data[0] = 1; - silc_hash_make(hash, buf->data, buf->len, hashd); + silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd); key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char)); memcpy(key->receive_iv, hashd, req_iv_len); key->iv_len = req_iv_len; @@ -1789,22 +1983,22 @@ silc_ske_process_key_material_data(unsigned char *data, /* XXX */ if (enc_key_len > (3 * hash_len)) - return SILC_SKE_STATUS_ERROR; + return NULL; /* Take first round */ memset(k1, 0, sizeof(k1)); - silc_hash_make(hash, buf->data, buf->len, k1); + silc_hash_make(hash, buf->data, silc_buffer_len(buf), k1); /* Take second round */ dist = silc_buffer_alloc_size(data_len + hash_len); if (!dist) - return SILC_SKE_STATUS_OUT_OF_MEMORY; + return NULL; silc_buffer_format(dist, SILC_STR_UI_XNSTRING(data, data_len), SILC_STR_UI_XNSTRING(k1, hash_len), SILC_STR_END); memset(k2, 0, sizeof(k2)); - silc_hash_make(hash, dist->data, dist->len, k2); + silc_hash_make(hash, dist->data, silc_buffer_len(dist), k2); /* Take third round */ dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len); @@ -1815,7 +2009,7 @@ silc_ske_process_key_material_data(unsigned char *data, SILC_STR_END); silc_buffer_push(dist, data_len + hash_len); memset(k3, 0, sizeof(k3)); - silc_hash_make(hash, dist->data, dist->len, k3); + silc_hash_make(hash, dist->data, silc_buffer_len(dist), k3); /* Then, save the keys */ dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char)); @@ -1837,7 +2031,7 @@ silc_ske_process_key_material_data(unsigned char *data, } else { /* Take normal hash as key */ memset(hashd, 0, sizeof(hashd)); - silc_hash_make(hash, buf->data, buf->len, hashd); + silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd); key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char)); memcpy(key->send_enc_key, hashd, enc_key_len); key->enc_key_len = req_enc_key_len; @@ -1852,22 +2046,22 @@ silc_ske_process_key_material_data(unsigned char *data, /* XXX */ if (enc_key_len > (3 * hash_len)) - return SILC_SKE_STATUS_ERROR; + return NULL; /* Take first round */ memset(k1, 0, sizeof(k1)); - silc_hash_make(hash, buf->data, buf->len, k1); + silc_hash_make(hash, buf->data, silc_buffer_len(buf), k1); /* Take second round */ dist = silc_buffer_alloc_size(data_len + hash_len); if (!dist) - return SILC_SKE_STATUS_OUT_OF_MEMORY; + return NULL; silc_buffer_format(dist, SILC_STR_UI_XNSTRING(data, data_len), SILC_STR_UI_XNSTRING(k1, hash_len), SILC_STR_END); memset(k2, 0, sizeof(k2)); - silc_hash_make(hash, dist->data, dist->len, k2); + silc_hash_make(hash, dist->data, silc_buffer_len(dist), k2); /* Take third round */ dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len); @@ -1878,7 +2072,7 @@ silc_ske_process_key_material_data(unsigned char *data, SILC_STR_END); silc_buffer_push(dist, data_len + hash_len); memset(k3, 0, sizeof(k3)); - silc_hash_make(hash, dist->data, dist->len, k3); + silc_hash_make(hash, dist->data, silc_buffer_len(dist), k3); /* Then, save the keys */ dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char)); @@ -1900,7 +2094,7 @@ silc_ske_process_key_material_data(unsigned char *data, } else { /* Take normal hash as key */ memset(hashd, 0, sizeof(hashd)); - silc_hash_make(hash, buf->data, buf->len, hashd); + silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd); key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char)); memcpy(key->receive_enc_key, hashd, enc_key_len); key->enc_key_len = req_enc_key_len; @@ -1909,12 +2103,12 @@ silc_ske_process_key_material_data(unsigned char *data, /* Take HMAC keys */ memset(hashd, 0, sizeof(hashd)); buf->data[0] = 4; - silc_hash_make(hash, buf->data, buf->len, hashd); + silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd); key->send_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char)); 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, buf->len, hashd); + silc_hash_make(hash, buf->data, silc_buffer_len(buf), hashd); key->receive_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char)); memcpy(key->receive_hmac_key, hashd, req_hmac_key_len); key->hmac_key_len = req_hmac_key_len; @@ -1923,51 +2117,52 @@ silc_ske_process_key_material_data(unsigned char *data, silc_buffer_clear(buf); silc_buffer_free(buf); - return SILC_SKE_STATUS_OK; + return key; } /* Processes negotiated key material as protocol specifies. This returns the actual keys to be used in the SILC. */ -SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, - SilcUInt32 req_iv_len, - SilcUInt32 req_enc_key_len, - SilcUInt32 req_hmac_key_len, - SilcSKEKeyMaterial *key) +SilcSKEKeyMaterial +silc_ske_process_key_material(SilcSKE ske, + SilcUInt32 req_iv_len, + SilcUInt32 req_enc_key_len, + SilcUInt32 req_hmac_key_len) { SilcSKEStatus status; SilcBuffer buf; unsigned char *tmpbuf; SilcUInt32 klen; + SilcSKEKeyMaterial key; /* Encode KEY to binary data */ tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen); buf = silc_buffer_alloc_size(klen + ske->hash_len); if (!buf) - return SILC_SKE_STATUS_OUT_OF_MEMORY; + return NULL; silc_buffer_format(buf, SILC_STR_UI_XNSTRING(tmpbuf, klen), SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len), SILC_STR_END); /* Process the key material */ - status = silc_ske_process_key_material_data(buf->data, buf->len, - req_iv_len, req_enc_key_len, - req_hmac_key_len, - ske->prop->hash, key); + key = silc_ske_process_key_material_data(buf->data, silc_buffer_len(buf), + req_iv_len, req_enc_key_len, + req_hmac_key_len, + ske->prop->hash); memset(tmpbuf, 0, klen); silc_free(tmpbuf); silc_buffer_clear(buf); silc_buffer_free(buf); - return status; + return key; } /* Free key material structure */ -void silc_ske_free_key_material(SilcSKEKeyMaterial *key) +void silc_ske_free_key_material(SilcSKEKeyMaterial key) { if (!key) return; diff --git a/lib/silcske/silcske.h b/lib/silcske/silcske.h index 554da9e7..389b5532 100644 --- a/lib/silcske/silcske.h +++ b/lib/silcske/silcske.h @@ -1,10 +1,10 @@ /* - silcske.h + silcske.h Author: Pekka Riikonen - Copyright (C) 2000 - 2002 Pekka Riikonen + Copyright (C) 2000 - 2005 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 @@ -24,7 +24,7 @@ * * DESCRIPTION * - * Implementation of the SILC Key Exchange Protocol (SKE). The SKE protocol + * The SILC Key Exchange (SKE) protocol interface. The SKE protocol * is used to negotiate secret key material between two parties, to be used * as session key or some other key. For example, when client connects to * server SKE is performed to exchange public keys, and to generate the key @@ -32,20 +32,13 @@ * two create secret key material for securing for example file transfer * stream. * - * SKE is based on Diffie-Hellman, and it derives its functionality from - * SSH2 Key Exchange protocol, OAKLEY Key Determination protocol and - * Station-To-Station (STS) protocols. - * * This SKE implementation provides easy interface for application - * that wants to use SKE. In fact, the interface is designed to be + * that wants to use SKE. In fact, the interface is designed to be * application independent, and does not expect that the application using * SKE would actually relate in any way to SILC. Hence, the interface * can be used in any kind of application needing to perform key exchange * protocol with two parties. The network connection is also handled - * outside the SKE interface. For the interface application must provide - * a packet sending function which SKE library can call when it wants - * to send packet to the remote host. The actual network connection - * therefore is handled in the application and not by the SKE library. + * outside the SKE interface. * * The protocol has initiator and responder. The initiator is the one * that starts the protocol, and the responder is the one that receives @@ -61,98 +54,133 @@ #include "silcske_status.h" -/****s* silcske/SilcSKEAPI/SilcSKE +/* Length of cookie in Start Payload */ +#define SILC_SKE_COOKIE_LEN 16 + +/* Forward declarations */ +typedef struct SilcSKECallbacksStruct *SilcSKECallbacks; +typedef struct SilcSKEStruct *SilcSKE; + +#include "silcske_groups.h" +#include "silcske_payload.h" + +/****d* silcske/SilcSKEAPI/SilcSKESecurityPropertyFlag * * NAME * - * typedef struct SilcSKEStruct *SilcSKE; + * typedef enum { ... } SilcSKESecurityPropertyFlag * * DESCRIPTION * - * This context is forward declaration for the SilcSKEStruct. - * This is allocated by the silc_ske_alloc and freed by the - * silc_ske_free function. This context represents the SKE session. + * SKE security property flags as defined by the SK protocol. * - ***/ -typedef struct SilcSKEStruct *SilcSKE; + * SOURCE + */ +typedef enum { + SILC_SKE_SP_FLAG_NONE = 0x00, /* No flags */ + SILC_SKE_SP_FLAG_IV_INCLUDED = 0x01, /* IV included in packet */ + SILC_SKE_SP_FLAG_PFS = 0x02, /* Perfect Forward Secrecy */ + SILC_SKE_SP_FLAG_MUTUAL = 0x04, /* Mutual authentication */ +} SilcSKESecurityPropertyFlag; +/***/ /****s* silcske/SilcSKEAPI/SilcSKESecurityProperties * * NAME * - * typedef struct SilcSKESecurityPropertiesStruct - * *SilcSKESecurityProperties; + * typedef struct { ... } *SilcSKESecurityProperties; * * DESCRIPTION * - * This context is forward declaration for the - * SilcSKESecurityPropertiesStruct structure. It is allocated by the - * library, and it represents the security properties selected during - * the SKE negotiation. + * Security Properties negotiated between key exchange parties. This + * structure is filled from the Key Exchange Start Payload which is used + * to negotiate what security properties should be used in the + * communication. * - ***/ -typedef struct SilcSKESecurityPropertiesStruct *SilcSKESecurityProperties; - -/* Forward declaration for SKE callbacks structure, which is internal. */ -typedef struct SilcSKECallbacksStruct *SilcSKECallbacks; + * SOURCE + */ +typedef struct { + SilcSKESecurityPropertyFlag flags; /* Flags */ + SilcSKEDiffieHellmanGroup group; /* Selected Diffie Hellman group */ + SilcPKCS pkcs; /* Selected PKCS algorithm */ + SilcCipher cipher; /* Selected cipher */ + SilcHash hash; /* Selected hash algorithm */ + SilcHmac hmac; /* Selected HMAC */ +} *SilcSKESecurityProperties; +/***/ -/****d* silcske/SilcSKEAPI/SilcSKEPKType +/****s* silcske/SilcSKEAPI/SilcSKEKeyMaterial * * NAME * - * typedef enum { ... } SilcSKEPKType; + * typedef struct { ... } *SilcSKEKeyMaterial; * * DESCRIPTION * - * Public key and certificate types defined by the SKE protocol. + * This is the key material structure, and is passed as argument by the + * application to silc_ske_process_key_material* functions. It includes + * the processed key material which can be used as SILC session keys. * - * SOURCE */ -typedef enum { - SILC_SKE_PK_TYPE_SILC = 1, /* Mandatory type */ - /* Optional types. These are not implemented currently */ - SILC_SKE_PK_TYPE_SSH2 = 2, - SILC_SKE_PK_TYPE_X509V3 = 3, - SILC_SKE_PK_TYPE_OPENPGP = 4, - SILC_SKE_PK_TYPE_SPKI = 5 -} SilcSKEPKType; +typedef struct { + unsigned char *send_iv; + unsigned char *receive_iv; + SilcUInt32 iv_len; + unsigned char *send_enc_key; + unsigned char *receive_enc_key; + SilcUInt32 enc_key_len; + unsigned char *send_hmac_key; + unsigned char *receive_hmac_key; + SilcUInt32 hmac_key_len; +} *SilcSKEKeyMaterial; /***/ -/****f* silcske/SilcSKEAPI/SilcSKESendPacketCb +/****s* silcske/SilcSKEAPI/SilcSKERekeyMaterial * - * SYNOPSIS + * NAME * - * typedef void (*SilcSKESendPacketCb)(SilcSKE ske, SilcBuffer packet, - * SilcPacketType type, void *context); + * typedef struct { ... } *SilcSKERekeyMaterial; * * DESCRIPTION * - * Packet sending callback. Caller of the SKE routines must provide - * a routine to send packets to negotiation parties. See the - * silc_ske_set_callbacks for more information. + * 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 + * need the context, it may free it with silc_free function. * - ***/ -typedef void (*SilcSKESendPacketCb)(SilcSKE ske, SilcBuffer packet, - SilcPacketType type, void *context); + * Application may save application specific data to `user_context'. + * + */ +typedef struct { + void *user_context; /* Application specific data */ + unsigned char *send_enc_key; + unsigned int enc_key_len : 23; + unsigned int ske_group : 8; + unsigned int pfs : 1; +} *SilcSKERekeyMaterial; +/***/ -/****f* silcske/SilcSKEAPI/SilcSKECb +/****d* silcske/SilcSKEAPI/SilcSKEPKType * - * SYNOPSIS + * NAME * - * typedef void (*SilcSKECb)(SilcSKE ske, void *context); + * typedef enum { ... } SilcSKEPKType; * * DESCRIPTION * - * Generic SKE callback function. This is called in various SKE - * routines. The SilcSKE object sent as argument provides all the data - * callers routine might need (payloads etc). This is usually called - * to indicate that the application may continue the execution of the - * SKE protocol. The application should check the ske->status in this - * callback function. This callback is also called when Start Payload - * is processed. See silc_ske_set_callbacks function for more information. + * Public key and certificate types defined by the SKE protocol. * - ***/ -typedef void (*SilcSKECb)(SilcSKE ske, void *context); + * SOURCE + */ +typedef enum { + SILC_SKE_PK_TYPE_SILC = 1, /* SILC Public Key, mandatory */ + SILC_SKE_PK_TYPE_SSH2 = 2, /* SSH2 Public key, not supported */ + SILC_SKE_PK_TYPE_X509V3 = 3, /* X.509v3 certificate, not supported */ + SILC_SKE_PK_TYPE_OPENPGP = 4, /* OpenPGP certificate, not supported */ + SILC_SKE_PK_TYPE_SPKI = 5 /* SPKI certificate, not supported */ +} SilcSKEPKType; +/***/ /****f* silcske/SilcSKEAPI/SilcSKEVerifyCbCompletion * @@ -182,7 +210,7 @@ typedef void (*SilcSKEVerifyCbCompletion)(SilcSKE ske, * SYNOPSIS * * typedef void (*SilcSKEVerifyCb)(SilcSKE ske, - * unsigned char *pk_data, + * const unsigned char *pk_data, * SilcUInt32 pk_len, * SilcSKEPKType pk_type, * void *context, @@ -192,16 +220,15 @@ typedef void (*SilcSKEVerifyCbCompletion)(SilcSKE ske, * DESCRIPTION * * Callback function used to verify the received public key or certificate. - * The verification process is most likely asynchronous. That's why the + * The verification process is most likely asynchronous. That's why the * application must call the `completion' callback when the verification - * process has been completed. The library then calls the user callback - * (SilcSKECb), if it was provided for the function that takes this callback - * function as argument, to indicate that the SKE protocol may continue. - * See silc_ske_set_callbacks for more information. + * process has been completed. The `context' is the context given as + * arugment to silc_ske_set_callbacks. See silc_ske_set_callbacks for + * more information. * ***/ typedef void (*SilcSKEVerifyCb)(SilcSKE ske, - unsigned char *pk_data, + const unsigned char *pk_data, SilcUInt32 pk_len, SilcSKEPKType pk_type, void *context, @@ -212,98 +239,39 @@ typedef void (*SilcSKEVerifyCb)(SilcSKE ske, * * SYNOPSIS * - * typedef SilcSKEStatus (*SilcSKECheckVersion)(SilcSKE ske, - * unsigned char *version, - * SilcUInt32 len, void *context); + * typedef SilcSKEStatus + * (*SilcSKECheckVersionCb)(SilcSKE ske, + * const unsigned char *version, + * SilcUInt32 len, void *context); * * DESCRIPTION * * Callback function used to check the version of the remote SKE server. * The SKE library will call this function so that the appliation may - * check its version against the remote host's version. This returns + * check its version against the remote host's version. This returns * SILC_SKE_STATUS_OK if the version string is Ok, and returns * SILC_SKE_STATUS_BAD_VERSION if the version was not acceptable. * ***/ -typedef SilcSKEStatus (*SilcSKECheckVersion)(SilcSKE ske, - unsigned char *version, - SilcUInt32 len, void *context); +typedef SilcSKEStatus (*SilcSKECheckVersionCb)(SilcSKE ske, + const unsigned char *version, + SilcUInt32 len, void *context); -/****s* silcske/SilcSKEAPI/SilcSKEKeyMaterial +/****f* silcske/SilcSKEAPI/SilcSKECompletionCb * - * NAME + * SYNOPSIS * - * typedef struct { ... } SilcSKEKeyMaterial; * * DESCRIPTION * - * This is the key material structure, and is passed as argument by the - * application to silc_ske_process_key_material* functions. It includes - * the processed key material which can be used as SILC session keys. * ***/ -typedef struct { - unsigned char *send_iv; - unsigned char *receive_iv; - SilcUInt32 iv_len; - unsigned char *send_enc_key; - unsigned char *receive_enc_key; - SilcUInt32 enc_key_len; - unsigned char *send_hmac_key; - unsigned char *receive_hmac_key; - SilcUInt32 hmac_key_len; -} SilcSKEKeyMaterial; - -/* Length of cookie in Start Payload */ -#define SILC_SKE_COOKIE_LEN 16 - -#include "silcske_groups.h" -#include "silcske_payload.h" - -/****d* silcske/SilcSKEAPI/SilcSKESecurityPropertyFlag - * - * NAME - * - * typedef enum { ... } SilcSKESecurityPropertyFlag - * - * DESCRIPTION - * - * SKE security property flags as defined by the SK protocol. - * - * SOURCE - */ -typedef enum { - SILC_SKE_SP_FLAG_NONE = 0x00, /* No flags */ - SILC_SKE_SP_FLAG_IV_INCLUDED = 0x01, /* IV included in ciphertexts */ - SILC_SKE_SP_FLAG_PFS = 0x02, /* Perfect Forward Secrecy */ - SILC_SKE_SP_FLAG_MUTUAL = 0x04, /* Mutual authentication */ -} SilcSKESecurityPropertyFlag; -/***/ - -/****s* silcske/SilcSKEAPI/SilcSKESecurityPropertiesStruct - * - * NAME - * - * struct SilcSKESecurityPropertiesStruct { ... }; - * - * DESCRIPTION - * - * Security Properties negotiated between key exchange parties. This - * structure is filled from the Key Exchange Start Payload which is used - * to negotiate what security properties should be used in the - * communication. - * - * SOURCE - */ -struct SilcSKESecurityPropertiesStruct { - SilcSKESecurityPropertyFlag flags; /* Flags */ - SilcSKEDiffieHellmanGroup group; /* Selected Diffie Hellman group */ - SilcPKCS pkcs; /* Selected PKCS algorithm */ - SilcCipher cipher; /* Selected cipher */ - SilcHash hash; /* Selected hash algorithm */ - SilcHmac hmac; /* Selected HMAC */ -}; -/***/ +typedef void (*SilcSKECompletionCb)(SilcSKE ske, + SilcSKEStatus status, + SilcSKESecurityProperties prop, + SilcSKEKeyMaterial keymat, + SilcSKERekeyMaterial rekey, + void *context); /****s* silcske/SilcSKEAPI/SilcSKEStruct * @@ -315,7 +283,7 @@ struct SilcSKESecurityPropertiesStruct { * * This structure is the SKE session context, and has a type definition * to SilcSKE. The structure includes the network connection socket, - * securit properties collected during the SKE negotiation, payloads + * security properties collected during the SKE negotiation, payloads * sent and received during the negotiation, and the actual raw key * material too. The application usually does not need to reference * to the inside of this structure. However, checking the current @@ -324,19 +292,17 @@ struct SilcSKESecurityPropertiesStruct { * SOURCE */ struct SilcSKEStruct { - /* The connection object. This is initialized by the caller. */ -#if 0 - SilcSocketConnection sock; -#endif + /* The network socket connection stream. Set by application. */ + SilcPacketStream stream; - /* Security properties negotiated */ + /* Negotiated Security properties. May be NULL in case of error. */ SilcSKESecurityProperties prop; /* Key Exchange payloads filled during key negotiation with remote data. Responder may save local data here as well. */ - SilcSKEStartPayload *start_payload; - SilcSKEKEPayload *ke1_payload; - SilcSKEKEPayload *ke2_payload; + SilcSKEStartPayload start_payload; + SilcSKEKEPayload ke1_payload; + SilcSKEKEPayload ke2_payload; unsigned char *remote_version; /* Temporary copy of the KE Start Payload used in the @@ -346,7 +312,7 @@ struct SilcSKEStruct { /* Random number x, 1 < x < q. This is the secret exponent used in Diffie Hellman computations. */ SilcMPInt *x; - + /* The secret shared key */ SilcMPInt *KEY; @@ -374,6 +340,19 @@ struct SilcSKEStruct { /* Backwards support version indicator */ SilcUInt32 backward_version; + + char *version; + SilcPublicKey public_key; + SilcPrivateKey private_key; + SilcSKEPKType pk_type; + SilcBuffer packet_buf; + SilcSKESecurityPropertyFlag flags; + SilcSKEKeyMaterial keymat; + SilcSKERekeyMaterial rekey; + SilcSchedule schedule; + SilcFSMStruct fsm; + SilcAsyncOperationStruct op; + bool aborted; }; /***/ @@ -383,21 +362,33 @@ struct SilcSKEStruct { * * SYNOPSIS * - * SilcSKE silc_ske_alloc(SilcRng rng, void *context); + * SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule, + * void *context); * * DESCRIPTION * * Allocates the SKE session context and returns it. The `rng' is * the random number generator the SKE is going to use when it needs * random number generation during the SKE session. The `context' is - * user context that the libary will not touch. The application can - * access that context with the ske->user_context if needed. The + * user context that the libary will not touch. Application can get the + * context by calling the fuction silc_ske_get_context function. The * application is responsible of freeing the `context'. After the * SKE session context is allocated application must call the * silc_ske_set_callbacks. * + * EXMPALE + * + * // Initiator example + * ske = silc_ske_alloc(rng, scheduler, app); + * silc_ske_set_callbacks(ske, verify_public_key, check_version, app); + * start_payload = + * silc_ske_assemble_security_properties(ske, SILC_SKE_SP_FLAG_PFS | + * SILC_SKE_SP_FLAG_MUTUAL, + * version); + * silc_ske_initiator_start(ske); + * ***/ -SilcSKE silc_ske_alloc(SilcRng rng, void *context); +SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule, void *context); /****f* silcske/SilcSKEAPI/silc_ske_free * @@ -412,501 +403,186 @@ SilcSKE silc_ske_alloc(SilcRng rng, void *context); ***/ void silc_ske_free(SilcSKE ske); +/****f* silcske/SilcSKEAPI/silc_ske_get_context + * + * SYNOPSIS + * + * void *silc_ske_get_context(SilcSKE ske); + * + * DESCRIPTION + * + * Returns the context that was given as argument to silc_ske_alloc. + * + ***/ +void *silc_ske_get_context(SilcSKE ske); + /****f* silcske/SilcSKEAPI/silc_ske_set_callbacks * * SYNOPSIS * * void silc_ske_set_callbacks(SilcSKE ske, - * SilcSKESendPacketCb send_packet, - * SilcSKECb payload_receive, * SilcSKEVerifyCb verify_key, - * SilcSKECb proto_continue, * SilcSKECheckVersion check_version, + * SilcSKECompletion completed, * void *context); * * DESCRIPTION * * Sets the callback functions for the SKE session. * - * The `send_packet' callback is a function that sends the packet to - * network. The SKE library will call it at any time packet needs to - * be sent to the remote host. - * - * The `payload_receive' callback is called when the remote host's Key - * Exchange Start Payload has been processed. The payload is saved - * to ske->start_payload if the application would need it. The application - * must also provide the payload to the next state of the SKE. - * * The `verify_key' callback is called to verify the received public key * or certificate. The verification process is most likely asynchronous. * That is why the application must call the completion callback when the - * verification process has been completed. The library then calls the user - * callback (`proto_continue'), if it is provided to indicate that the SKE - * protocol may continue. If this SKE session context is used to perform - * rekey, this callback usually is not provided as argument since sending - * public key in rekey is not mandatory. Setting this callback implies - * that remote end MUST send its public key, and this could cause - * problems when performing rekey. When doing normal SKE session this - * callback should be set. - * - * The `proto_continue' callback is called to indicate that it is - * safe to continue the execution of the SKE protocol after executing - * an asynchronous operation, such as calling the `verify_key' callback - * function, which is asynchronous. The application should check the - * ske->status in this function to check whether it is Ok to continue - * the execution of the protocol. + * verification process has been completed. If this SKE session context + * is used to perform rekey, this callback usually is not provided as + * argument since sending public key in rekey is not mandatory. Setting + * this callback implies that remote end MUST send its public key. * * The `check_version' callback is called to verify the remote host's - * version. The application may check its own version against the remote + * version. The application may check its own version against the remote * host's version and determine whether supporting the remote host * is possible. * + * The `completed' callback will be called once the protocol has completed, + * either successfully or with an error. The status of the protocol is + * delivered to application with the callback. + * * The `context' is passed as argument to all of the above callback * functions. * ***/ void silc_ske_set_callbacks(SilcSKE ske, - SilcSKESendPacketCb send_packet, - SilcSKECb payload_receive, SilcSKEVerifyCb verify_key, - SilcSKECb proto_continue, - SilcSKECheckVersion check_version, + SilcSKECheckVersionCb check_version, + SilcSKECompletionCb completed, void *context); /****f* silcske/SilcSKEAPI/silc_ske_initiator_start * * SYNOPSIS * - * SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng, - * SilcSocketConnection sock, - * SilcSKEStartPayload - * *start_payload); + * SilcAsyncOperation + * silc_ske_initiator_start(SilcSKE ske, + * SilcPacketStream stream, + * SilcSKEStartPayload start_payload); * * DESCRIPTION * - * Starts the SILC Key Exchange protocol for initiator. The connection - * to the responder end must be established before calling this function - * and the connecting socket must be sent as argument. This function - * creates the Key Exchange Start Payload which includes all our - * configured security properties. This payload is then sent to the - * responder end for further processing. This payload must be sent as - * argument to the function, however, it must not be encoded - * already, it is done by this function. The caller must not free - * the `start_payload' since the SKE library will save it. + * Starts the SILC Key Exchange protocol as initiator. The completion + * callback that was set in silc_ske_set_callbacks will be called once + * the protocol has completed. * - * Before calling this function application calls the - * silc_ske_assemble_security_properties which returns the `start_payload' - * which application must provide for this function. + * The `stream' is the network connection to the remote host. Note that + * SKE library will take over the packet stream `stream' while the + * protocol is in process. The application will not receive any packets + * for `stream' after this function is called. The `stream' is turned + * over to application once the completion callback is called. * - * After calling this function the application must wait for reply - * from the responder. + * The `start_payload' includes all configured security properties that + * will be sent to the responder. The `start_payload' must be provided. + * It can be created by calling silc_ske_assemble_security_properties + * function. The caller must not free the payload once it has been + * given as argument to this function. * - ***/ -SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng, -#if 0 - SilcSocketConnection sock, -#endif - SilcSKEStartPayload *start_payload); - -/****f* silcske/SilcSKEAPI/silc_ske_initiator_phase_1 - * - * SYNOPSIS - * - * SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, - * SilcBuffer start_payload); - * - * DESCRIPTION - * - * Function called after ske_initiator_start fuction. This receives - * the responder's Key Exchange Start payload which includes the - * security properties selected by the responder from our payload - * sent in the silc_ske_initiator_start function. The `start_payload' - * is the received payload and the application must send it as argument. - * - * After calling this function the application must call immediately, - * or with short timeout, the silc_ske_initiator_phase_2 function. + * This function returns SilcAsyncOperation operation context which can + * be used to control the protocol from the application. Application may + * for example safely abort the protocol at any point, if needed. Returns + * NULL on error. * ***/ -SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, - SilcBuffer start_payload); - -/****f* silcske/SilcSKEAPI/silc_ske_initiator_phase_2 - * - * SYNOPSIS - * - * SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, - * SilcPublicKey public_key, - * SilcPrivateKey private_key, - * SilcSKEPKType pk_type) - * - * DESCRIPTION - * - * This function continues the SKE session after the initiator has - * called the silc_ske_initiator_phase_1. After that function returns - * the application should call immediately, or with short timeout, this - * function which will continue with the session, and sends next phase - * packet to the responder. The caller must provide the caller's - * public key and private key as argument, since the public key is - * sent to the responder, and the private key is be used to generate - * digital signature. - * - * After this function the application must wait for reply from the - * responder. - * - ***/ -SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, - SilcPublicKey public_key, - SilcPrivateKey private_key, - SilcSKEPKType pk_type); - -/****f* silcske/SilcSKEAPI/silc_ske_initiator_finish - * - * SYNOPSIS - * - * SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske, - * SilcBuffer ke_payload); - * - * DESCRIPTION - * - * Receives the reply from the responder and processes it. The - * `ke_payload' is the reply and application must provide it as argument. - * This function will verify the responder's public key, by calling - * the `verify_key' callback that was set with silc_ske_set_callbacks - * function. - * - * If this function returns error, no callbacks will be called. If - * this function needs to verify remote end's public key, this will - * return SILC_SKE_STATUS_PENDING, which indicates application that - * SKE is performing asynchronous operation and is in pending status. - * When in this status application must not continue with calling - * any other SKE routine. The asynchronous operation is the `verify_key' - * callback, which application completes by calling its completion - * callback. After completion the SKE libary will call the - * `proto_continue' callback, to indicate application that pending - * status is over and it is safe to continue the execution of SKE, - * which application does by calling the silc_ske_end function. - * - * If this function returns SILC_SKE_STATUS_OK, it will not call the - * `verify_key' callback, however, it will or has already called the - * `proto_continue' callback. - * - * Application must not continue execution of the SKE before library - * has called the `proto_continue' callback. After it is called - * the application finishes SKE session by calling silc_ske_end - * function. - * - ***/ -SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske, - SilcBuffer ke_payload); +SilcAsyncOperation +silc_ske_initiator_start(SilcSKE ske, + SilcPacketStream stream, + SilcSKEStartPayload start_payload); /****f* silcske/SilcSKEAPI/silc_ske_responder_start * * SYNOPSIS * - * SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng, - * SilcSocketConnection sock, - * const char *version, - * SilcBuffer start_payload, - * SilcSKESecurityPropertyFlag - * flags); - * - * DESCRIPTION - * - * Starts Key Exchange protocol for responder. The application has - * received initiator's first packet from network and it must provide - * it as `start_payload' argument to this function. The function - * processes the packet and makes security property selection from - * the initiator's proposal. The `version' is the responder's version - * that will be sent in reply to the initiator. The `flags' indicates - * SilcSKESecurityPropertyFlag flags that responder enforces for the - * initiator. Responder may, for example, enforce that the PFS - * will be performed in rekey. This example can be done by providing - * SILC_SKE_SP_FLAG_PFS as `flags'. The `flags' is a bit mask of - * enforced flags. - * - * After this function the responder calls immediately, or with short - * timeout the silc_ske_responder_phase_1 function. - * - ***/ -SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng, -#if 0 - SilcSocketConnection sock, -#endif - const char *version, - SilcBuffer start_payload, - SilcSKESecurityPropertyFlag flags); - -/****f* silcske/SilcSKEAPI/silc_ske_responder_phase_1 - * - * SYNOPSIS - * - * SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske); - * - * DESCRIPTION - * - * This function is called after the silc_ske_responder_start, and - * is used to send our reply to the initiator. This function is - * called either immediately, or with short timeout, after the - * silc_ske_responder_start function returned. - * - * After this function the responder must wait for reply from the - * initiator. - * - ***/ -SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske); - -/****f* silcske/SilcSKEAPI/silc_ske_responder_phase_2 - * - * SYNOPSIS - * - * SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske, - * SilcBuffer ke_payload); - * - * DESCRIPTION - * - * Receives the reply from the initiator and procedses it. The - * `ke_payload' is the reply and application must provide it as argument. - * This function will verify the remote host's public key, by calling - * the `verify_key' callback that was set with silc_ske_set_callbacks - * function. - * - * If this function returns error, no callbacks will be called. If - * this function needs to verify remote end's public key, this will - * return SILC_SKE_STATUS_PENDING, which indicates application that - * SKE is performing asynchronous operation and is in pending status. - * When in this status application must not continue with calling - * any other SKE routine. The asynchronous operation is the `verify_key' - * callback, which application completes by calling its completion - * callback. After completion the SKE libary will call the - * `proto_continue' callback, to indicate application that pending - * status is over and it is safe to continue the execution of SKE, - * which application does by calling the silc_ske_responder_finish - * function. - * - * If this function returns SILC_SKE_STATUS_OK, it will not call the - * `verify_key' callback, however, it will or has already called the - * `proto_continue' callback. - * - * Application must not continue execution of the SKE before library - * has called the `proto_continue' callback. After it is called - * the application calls the silc_ske_responder_finish function. - * - ***/ -SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske, - SilcBuffer ke_payload); - -/****f* silcske/SilcSKEAPI/silc_ske_responder_finish - * - * SYNOPSIS - * - * SilcSKEStatus silc_ske_responder_finish(SilcSKE ske, - * SilcPublicKey public_key, - * SilcPrivateKey private_key, - * SilcSKEPKType pk_type); - * - * DESCRIPTION - * - * This function finishes the responder's SKE session, and this function - * is called either immediately, or with short timeout, after the - * silc_ske_responder_phase_2 returned. This will send our reply to - * the initiator. The caller must provide the caller's public key and - * private key as argument, since the public key is sent to the responder, - * and the private key is be used to generate digital signature. - * - * After this function the application must wait for the end indication - * from the intiator, and when it is received the silc_ske_end is called. - * - ***/ -SilcSKEStatus silc_ske_responder_finish(SilcSKE ske, - SilcPublicKey public_key, - SilcPrivateKey private_key, - SilcSKEPKType pk_type); - -/****f* silcske/SilcSKEAPI/silc_ske_end - * - * SYNOPSIS - * - * SilcSKEStatus silc_ske_end(SilcSKE ske); + * SilcAsyncOperation + * silc_ske_responder_start(SilcSKE ske, + * SilcPacketStream stream, + * const char *version, + * SilcBuffer start_payload, + * SilcSKESecurityPropertyFlag flags); * * DESCRIPTION * - * The Key Exchange protocol is ended by calling this function. This - * must not be called until the keys are processed by calling the - * silc_ske_process_key_material function. The protocol prohibits - * calling this function before key material is processed properly. + * Starts SILC Key Exchange protocol as responder. The completion + * callback that was set in silc_ske_set_callbacks will be called once + * the protocol has completed. * - * This function is for both initiator and responder. After calling - * this function initiator must wait for end indication from the - * responder. After that the silc_ske_free may be called. The responder - * calls this function after it has received the intiator's end - * indication. + * The `stream' is the network connection to the remote host. Note that + * SKE library will take over the packet stream `stream' while the + * protocol is in process. The application will not receive any packets + * for `stream' after this function is called. The `stream' is turned + * over to application once the completion callback is called. * - * NOTES + * The application has received initiator's first packet from network + * and it must provide it as `start_payload' argument to this function. + * The function processes the packet and makes security property selection + * from the initiator's proposal. The `version' is the responder's version + * that will be sent in reply to the initiator. The `flags' indicates + * SilcSKESecurityPropertyFlag flags that responder supports and enforces + * for the initiator. Responder may, for example, enforce that the PFS + * will be performed in rekey. * - * Initiator must not start using the negotiated key material before - * calling this function or before remote end has sent its end - * indication. Only after that the key material may be taken in use. + * This function returns SilcAsyncOperation operation context which can + * be used to control the protocol from the application. Application may + * for example safely abort the protocol at any point, if needed. Returns + * NULL on error. * ***/ -SilcSKEStatus silc_ske_end(SilcSKE ske); - -/****f* silcske/SilcSKEAPI/silc_ske_abort - * - * SYNOPSIS - * - * SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status); - * - * DESCRIPTION - * - * Aborts the Key Exchange protocol. This is called if error occurs - * while performing the protocol. The status argument is the error - * status and it is sent to the remote end. - * - ***/ -SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status); +SilcAsyncOperation +silc_ske_responder_start(SilcSKE ske, + SilcPacketStream stream, + const char *version, + SilcBuffer start_payload, + SilcSKESecurityPropertyFlag flags); + +SilcAsyncOperation +silc_ske_rekey_initiator_start(SilcSKE ske, + SilcPacketStream stream, + SilcSKERekeyMaterial rekey); + +SilcAsyncOperation +silc_ske_rekey_responder_start(SilcSKE ske, + SilcPacketStream stream, + SilcBuffer ke_payload, + SilcSKERekeyMaterial rekey); /****f* silcske/SilcSKEAPI/silc_ske_assemble_security_properties * * SYNOPSIS * - * SilcSKEStatus + * SilcSKEStartPayload * silc_ske_assemble_security_properties(SilcSKE ske, * SilcSKESecurityPropertyFlag flags, - * const char *version, - * SilcSKEStartPayload - * **return_payload); + * const char *version); * * DESCRIPTION * * Assembles security properties to Key Exchange Start Payload to be - * sent to the remote end. This checks system wide (SILC system, that is) - * settings and chooses from those. However, if other properties + * sent to the remote end. This checks system wide (SILC system, that is) + * settings and chooses from those. However, if other properties * should be used this function is easy to replace by another function, * as, this function is called by the caller of the library and not - * by the SKE library itself. The assembled payload is returned into - * the `return_payload' pointer. + * by the SKE library itself. Returns NULL on error. * ***/ -SilcSKEStatus +SilcSKEStartPayload silc_ske_assemble_security_properties(SilcSKE ske, SilcSKESecurityPropertyFlag flags, - const char *version, - SilcSKEStartPayload **return_payload); - -/****f* silcske/SilcSKEAPI/silc_ske_select_security_properties - * - * SYNOPSIS - * - * SilcSKEStatus - * silc_ske_select_security_properties(SilcSKE ske, - * const char *version, - * SilcSKEStartPayload *payload, - * SilcSKEStartPayload *remote_payload); - * - * DESCRIPTION - * - * Parses the Key Exchange Start Payload indicated by `remote_payload', - * and selects the security properties properties from it, and puts the - * selection into the `payload'. This always attempts to select the - * best security properties from the payload, and it always selects - * one of each kind of security property, as this is dictated by the - * protocol. The `version' is our version, that we will put to the - * `payload', since the `payload' is usually sent to the remote end. - * the `check_version' callback will be called in this function so - * that application can do version check with the remote end. - * - ***/ -SilcSKEStatus -silc_ske_select_security_properties(SilcSKE ske, - const char *version, - SilcSKEStartPayload *payload, - SilcSKEStartPayload *remote_payload); - -/****f* silcske/SilcSKEAPI/silc_ske_process_key_material - * - * SYNOPSIS - * - * SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, - * SilcUInt32 req_iv_len, - * SilcUInt32 req_enc_key_len, - * SilcUInt32 req_hmac_key_len, - * SilcSKEKeyMaterial *key); - * - * DESCRIPTION - * - * This function is used by the application to process the key material - * negotiated with the SKE session, to actually produce the keys that - * is to be used in SILC protocol. The key processing is defined by the - * protocol. The `req_iv_len', `req_enc_key_len' and `req_hmac_key_len' - * are the request IV length, requested encryption/decrypt key length, - * and requested HMAC key length, respectively, and they cannot be - * zero (0). They tell the function how long the keys should be, and - * it will produce the requested length keys for the application. - * The key material is returned in to the `key', which the caller must - * free. - * - ***/ -SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, - SilcUInt32 req_iv_len, - SilcUInt32 req_enc_key_len, - SilcUInt32 req_hmac_key_len, - SilcSKEKeyMaterial *key); - -/****f* silcske/SilcSKEAPI/silc_ske_process_key_material_data - * - * SYNOPSIS - * - * SilcSKEStatus - * silc_ske_process_key_material_data(unsigned char *data, - * SilcUInt32 data_len, - * SilcUInt32 req_iv_len, - * SilcUInt32 req_enc_key_len, - * SilcUInt32 req_hmac_key_len, - * SilcHash hash, - * SilcSKEKeyMaterial *key); - * - * DESCRIPTION - * - * This function is equivalent to silc_ske_process_key_material, except - * that the caller provides the raw key material as argument, the `data' - * and `data_len'. This is special utility function provided for the - * application, if it needs to generate key material as the protocol - * defines for some other purpose than strictly SILC session key usage. - * Hence, this function can be used outside SKE protocol to just produce - * key material from some raw data. The `hash' is a hash algorithm that - * is used as part of key processing, and caller must provide it. - * - ***/ -SilcSKEStatus -silc_ske_process_key_material_data(unsigned char *data, - SilcUInt32 data_len, - SilcUInt32 req_iv_len, - SilcUInt32 req_enc_key_len, - SilcUInt32 req_hmac_key_len, - SilcHash hash, - SilcSKEKeyMaterial *key); - -/****f* silcske/SilcSKEAPI/silc_ske_free_key_material - * - * SYNOPSIS - * - * void silc_ske_free_key_material(SilcSKEKeyMaterial *key); - * - * DESCRIPTION - * - * Frees the key material indicated by `key', and all data in it. - * - ***/ -void silc_ske_free_key_material(SilcSKEKeyMaterial *key); + const char *version); /****f* silcske/SilcSKEAPI/silc_ske_parse_version * * SYNOPSIS * - * bool silc_ske_parse_version(SilcSKE ske, + * bool silc_ske_parse_version(SilcSKE ske, * SilcUInt32 *protocol_version, * char **protocol_version_string, - * SilcUInt32 *software_version, + * SilcUInt32 *software_version, * char **software_version_string, * char **vendor_version); * @@ -920,10 +596,10 @@ void silc_ske_free_key_material(SilcSKEKeyMaterial *key); * string was successfully parsed. * ***/ -bool silc_ske_parse_version(SilcSKE ske, +bool silc_ske_parse_version(SilcSKE ske, SilcUInt32 *protocol_version, char **protocol_version_string, - SilcUInt32 *software_version, + SilcUInt32 *software_version, char **software_version_string, char **vendor_version); diff --git a/lib/silcske/silcske_payload.h b/lib/silcske/silcske_payload.h index 22755524..849e12f6 100644 --- a/lib/silcske/silcske_payload.h +++ b/lib/silcske/silcske_payload.h @@ -1,10 +1,10 @@ /* - silcske_payload.h + silcske_payload.h Author: Pekka Riikonen - Copyright (C) 2000 - 2002 Pekka Riikonen + Copyright (C) 2000 - 2005 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 @@ -35,7 +35,7 @@ /****s* silcske/SilcSKEPayloads/SilcSKEStartPayload * * NAME - * + * * typedef struct SilcSKEStartPayloadStruct SilcSKEStartPayload; * * DESCRIPTION @@ -45,22 +45,22 @@ * silc_ske_payload_start_free function. * ***/ -typedef struct SilcSKEStartPayloadStruct SilcSKEStartPayload; +typedef struct SilcSKEStartPayloadStruct *SilcSKEStartPayload; /****s* silcske/SilcSKEPayloads/SilcSKEKEPayload * * NAME - * + * * typedef struct SilcSKEKEPayloadStruct SilcSKEKEPayload; * * DESCRIPTION * * This context is the actual Key Exchange Payload and is allocated * by silc_ske_payload_ke_decode. It is freed by calling the - * silc_ske_payload_ke_free function. + * silc_ske_payload_ke_free function. * ***/ -typedef struct SilcSKEKEPayloadStruct SilcSKEKEPayload; +typedef struct SilcSKEKEPayloadStruct *SilcSKEKEPayload; /* SILC Key Exchange Start Payload */ struct SilcSKEStartPayloadStruct { @@ -81,7 +81,7 @@ struct SilcSKEStartPayloadStruct { SilcUInt16 enc_alg_len; unsigned char *enc_alg_list; - + SilcUInt16 hash_alg_len; unsigned char *hash_alg_list; @@ -111,7 +111,7 @@ struct SilcSKEKEPayloadStruct { * SYNOPSIS * * SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske, - * SilcSKEStartPayload *payload, + * SilcSKEStartPayload payload, * SilcBuffer *return_buffer); * * DESCRIPTION @@ -122,17 +122,17 @@ struct SilcSKEKEPayloadStruct { * ***/ SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske, - SilcSKEStartPayload *payload, + SilcSKEStartPayload payload, SilcBuffer *return_buffer); /****f* silcske/SilcSKEPayloads/silc_ske_payload_start_decode * * SYNOPSIS * - * SilcSKEStatus + * SilcSKEStatus * silc_ske_payload_start_decode(SilcSKE ske, * SilcBuffer buffer, - * SilcSKEStartPayload **return_payload); + * SilcSKEStartPayload *return_payload); * * DESCRIPTION * @@ -141,10 +141,10 @@ SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske, * `return_payload' and the caller must free it. * ***/ -SilcSKEStatus +SilcSKEStatus silc_ske_payload_start_decode(SilcSKE ske, SilcBuffer buffer, - SilcSKEStartPayload **return_payload); + SilcSKEStartPayload *return_payload); /****f* silcske/SilcSKEPayloads/silc_ske_payload_start_free * @@ -157,14 +157,14 @@ silc_ske_payload_start_decode(SilcSKE ske, * Frees the Key Exchange Start Payload indicated by `payload'. * ***/ -void silc_ske_payload_start_free(SilcSKEStartPayload *payload); +void silc_ske_payload_start_free(SilcSKEStartPayload payload); /****f* silcske/SilcSKEPayloads/silc_ske_payload_ke_encode * * SYNOPSIS * * SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske, - * SilcSKEKEPayload *payload, + * SilcSKEKEPayload payload, * SilcBuffer *return_buffer); * * DESCRIPTION @@ -175,7 +175,7 @@ void silc_ske_payload_start_free(SilcSKEStartPayload *payload); * ***/ SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske, - SilcSKEKEPayload *payload, + SilcSKEKEPayload payload, SilcBuffer *return_buffer); /****f* silcske/SilcSKEPayloads/silc_ske_payload_ke_decode @@ -184,7 +184,7 @@ SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske, * * SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske, * SilcBuffer buffer, - * SilcSKEKEPayload + * SilcSKEKEPayload * **return_payload); * * DESCRIPTION @@ -196,7 +196,7 @@ SilcSKEStatus silc_ske_payload_ke_encode(SilcSKE ske, ***/ SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske, SilcBuffer buffer, - SilcSKEKEPayload **return_payload); + SilcSKEKEPayload *return_payload); /****f* silcske/SilcSKEPayloads/silc_ske_payload_ke_free * @@ -209,6 +209,6 @@ SilcSKEStatus silc_ske_payload_ke_decode(SilcSKE ske, * Frees the Key Exchange Payload indicated by `payload'. * ***/ -void silc_ske_payload_ke_free(SilcSKEKEPayload *payload); +void silc_ske_payload_ke_free(SilcSKEKEPayload payload); #endif /* SILCSKE_PAYLOAD_H */