From 7f26bf8964b7269f9a9f295afdff1b870ecc68e2 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Mon, 28 Apr 2014 22:39:06 +0300 Subject: [PATCH] SKE: support for simplified key exchange This commit adds support for simplified SILC Key Exchange protocol by allowing the caller to specify the security properties to be used in the key exchange. This will stop the library from exchanging the SILC_PACKET_KEY_EXCHANGE packet containing the properties. Support for not sending the SILC_PACKET_SUCCESS acks after a successful key exchange. These two changes allow the SKE to be simplified to exchanging only the SILC_PACKET_KEY_EXHANGE_1 and SILC_PACKET_KEY_EXCHANGE_2 packets to produce the shared key and to do mutual authentication. The commit also adds support for generating small proposals in SILC_PACKET_KEY_EXCHANGE packet by including only one security property per item instead of listing all of them in the proposal. Additionally the commit adds support for probe timeout which affects the first packet sent by initiator. If responder does not respond to the first packet in the specified timeframe the key exchange will timeout. If it replies the normal key exchange timeout has effect after that. --- lib/silcske/groups.c | 7 +- lib/silcske/payload.c | 11 +- lib/silcske/silcske.c | 196 ++++++++++++++++++++++++----------- lib/silcske/silcske.h | 23 +++- lib/silcske/silcske_groups.h | 7 +- lib/silcske/silcske_i.h | 4 +- 6 files changed, 177 insertions(+), 71 deletions(-) diff --git a/lib/silcske/groups.c b/lib/silcske/groups.c index f6333e8f..d5b3b128 100644 --- a/lib/silcske/groups.c +++ b/lib/silcske/groups.c @@ -153,13 +153,16 @@ void silc_ske_group_free(SilcSKEDiffieHellmanGroup group) /* Returns comma separated list of supported groups */ -char *silc_ske_get_supported_groups() +char *silc_ske_get_supported_groups(SilcUInt32 limit) { char *list = NULL; int i, len; + if (!limit) + limit = ~0; + len = 0; - for (i = 0; silc_ske_groups[i].name; i++) { + for (i = 0; silc_ske_groups[i].name && i < limit; i++) { len += strlen(silc_ske_groups[i].name); list = silc_realloc(list, len + 1); diff --git a/lib/silcske/payload.c b/lib/silcske/payload.c index ad45ea8d..9c5451be 100644 --- a/lib/silcske/payload.c +++ b/lib/silcske/payload.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2000 - 2005 Pekka Riikonen + Copyright (C) 2000 - 2014 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -156,6 +156,15 @@ silc_ske_payload_start_decode(SilcSKE ske, goto err; } + if (payload->len != 4 + payload->cookie_len + payload->version_len + + payload->ke_grp_len + payload->pkcs_alg_len + payload->enc_alg_len + + payload->hash_alg_len + payload->hmac_alg_len + payload->comp_alg_len + + (2 * 7)) { + SILC_LOG_ERROR(("Invalid fields in KE Start Payload")); + status = SILC_SKE_STATUS_BAD_PAYLOAD; + goto err; + } + /* Return the payload */ *return_payload = payload; diff --git a/lib/silcske/silcske.c b/lib/silcske/silcske.c index 36d36ac8..129c178e 100644 --- a/lib/silcske/silcske.c +++ b/lib/silcske/silcske.c @@ -864,7 +864,8 @@ silc_ske_make_rekey_material(SilcSKE ske, SilcSKEKeyMaterial keymat) static SilcSKEStartPayload silc_ske_assemble_security_properties(SilcSKE ske, SilcSKESecurityPropertyFlag flags, - const char *version) + const char *version, + SilcBool small_proposal) { SilcSKEStartPayload rp; int i; @@ -899,34 +900,48 @@ silc_ske_assemble_security_properties(SilcSKE ske, rp->version_len = strlen(version); /* Get supported Key Exhange groups */ - rp->ke_grp_list = silc_ske_get_supported_groups(); + rp->ke_grp_list = silc_ske_get_supported_groups(small_proposal); if (rp->ke_grp_list) rp->ke_grp_len = strlen(rp->ke_grp_list); /* Get supported PKCS algorithms */ - rp->pkcs_alg_list = silc_pkcs_get_supported(); + if (small_proposal) + rp->pkcs_alg_list = strdup(silc_default_pkcs_alg[0].name); + else + rp->pkcs_alg_list = silc_pkcs_get_supported(); if (rp->pkcs_alg_list) rp->pkcs_alg_len = strlen(rp->pkcs_alg_list); /* Get supported encryption algorithms */ - rp->enc_alg_list = silc_cipher_get_supported(); + if (small_proposal) + rp->enc_alg_list = strdup(silc_default_ciphers[0].name); + else + rp->enc_alg_list = silc_cipher_get_supported(); if (rp->enc_alg_list) rp->enc_alg_len = strlen(rp->enc_alg_list); /* Get supported hash algorithms */ - rp->hash_alg_list = silc_hash_get_supported(); + if (small_proposal) + rp->hash_alg_list = strdup(silc_default_hash[0].name); + else + rp->hash_alg_list = silc_hash_get_supported(); if (rp->hash_alg_list) rp->hash_alg_len = strlen(rp->hash_alg_list); /* Get supported HMACs */ - rp->hmac_alg_list = silc_hmac_get_supported(); + if (small_proposal) + rp->hmac_alg_list = strdup(silc_default_hmacs[0].name); + else + rp->hmac_alg_list = silc_hmac_get_supported(); if (rp->hmac_alg_list) rp->hmac_alg_len = strlen(rp->hmac_alg_list); - /* XXX */ - /* Get supported compression algorithms */ - rp->comp_alg_list = strdup("none"); - rp->comp_alg_len = strlen("none"); + if (!small_proposal) { + /* XXX */ + /* Get supported compression algorithms */ + rp->comp_alg_list = strdup("none"); + rp->comp_alg_len = strlen("none"); + } rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 2 + rp->version_len + @@ -951,7 +966,7 @@ SILC_TASK_CALLBACK(silc_ske_packet_send_retry) silc_free(ske->retrans.data); ske->retrans.data = NULL; ske->status = SILC_SKE_STATUS_TIMEOUT; - silc_ske_notify_failure(ske); + silc_ske_notify_failure(ske); silc_fsm_continue_sync(&ske->fsm); return; } @@ -1046,6 +1061,21 @@ SILC_TASK_CALLBACK(silc_ske_timeout) silc_fsm_continue_sync(&ske->fsm); } +/* Key exchange timeout task callback */ + +SILC_TASK_CALLBACK(silc_ske_probe_timeout) +{ + SilcSKE ske = context; + + SILC_LOG_DEBUG(("Probe timeout")); + + ske->packet = NULL; + ske->status = SILC_SKE_STATUS_PROBE_TIMEOUT; + silc_ske_notify_failure(ske); + + silc_fsm_continue_sync(&ske->fsm); +} + /******************************* Protocol API *******************************/ /* Allocates new SKE object. */ @@ -1229,10 +1259,6 @@ SILC_FSM_STATE(silc_ske_st_initiator_start) return SILC_FSM_CONTINUE; } - /* Add key exchange timeout */ - silc_schedule_task_add_timeout(ske->schedule, silc_ske_timeout, - ske, ske->timeout, 0); - /** Wait for responder proposal */ SILC_LOG_DEBUG(("Waiting for responder proposal")); silc_fsm_next(fsm, silc_ske_st_initiator_phase1); @@ -1263,6 +1289,8 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase1) return SILC_FSM_WAIT; } + silc_schedule_task_del_by_all(ske->schedule, 0, silc_ske_probe_timeout, ske); + /* Decode the payload */ status = silc_ske_payload_start_decode(ske, packet_buf, &payload); if (status != SILC_SKE_STATUS_OK) { @@ -1275,7 +1303,9 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase1) } /* Get remote ID and set it to stream */ - if (ske->packet->src_id_len) { + if (ske->packet->src_id_len && + (ske->packet->src_id_type == SILC_ID_SERVER || + ske->packet->src_id_type == SILC_ID_CLIENT)) { silc_id_str2id(ske->packet->src_id, ske->packet->src_id_len, ske->packet->src_id_type, (ske->packet->src_id_type == SILC_ID_SERVER ? @@ -1732,20 +1762,26 @@ SILC_FSM_STATE(silc_ske_st_initiator_phase4) goto err; } - /* Send SUCCESS packet */ - SILC_PUT32_MSB((SilcUInt32)SILC_SKE_STATUS_OK, hash); - if (!silc_ske_packet_send(ske, SILC_PACKET_SUCCESS, 0, hash, 4)) { - /** Error sending packet */ - SILC_LOG_DEBUG(("Error sending packet")); - ske->status = SILC_SKE_STATUS_ERROR; - silc_fsm_next(fsm, silc_ske_st_initiator_error); + if (!ske->no_acks) { + /* Send SUCCESS packet */ + SILC_PUT32_MSB((SilcUInt32)SILC_SKE_STATUS_OK, hash); + if (!silc_ske_packet_send(ske, SILC_PACKET_SUCCESS, 0, hash, 4)) { + /** Error sending packet */ + SILC_LOG_DEBUG(("Error sending packet")); + ske->status = SILC_SKE_STATUS_ERROR; + silc_fsm_next(fsm, silc_ske_st_initiator_error); + return SILC_FSM_CONTINUE; + } + + /** Waiting completion */ + silc_fsm_next(fsm, silc_ske_st_initiator_end); + return SILC_FSM_WAIT; + } else { + /** Complete protocol */ + silc_fsm_next(fsm, silc_ske_st_initiator_end); return SILC_FSM_CONTINUE; } - /** Waiting completion */ - silc_fsm_next(fsm, silc_ske_st_initiator_end); - return SILC_FSM_WAIT; - err: memset(hash, 'F', sizeof(hash)); silc_ske_payload_ke_free(payload); @@ -1778,7 +1814,7 @@ SILC_FSM_STATE(silc_ske_st_initiator_end) SILC_LOG_DEBUG(("Start")); - if (ske->packet->type != SILC_PACKET_SUCCESS) { + if (!ske->no_acks && ske->packet->type != SILC_PACKET_SUCCESS) { SILC_LOG_DEBUG(("Remote retransmitted an old packet")); silc_ske_install_retransmission(ske); silc_packet_free(ske->packet); @@ -1788,7 +1824,8 @@ SILC_FSM_STATE(silc_ske_st_initiator_end) SILC_LOG_DEBUG(("Key exchange completed successfully")); - silc_packet_free(ske->packet); + if (ske->packet) + silc_packet_free(ske->packet); ske->packet = NULL; silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske); silc_schedule_task_del_by_context(ske->schedule, ske); @@ -1826,7 +1863,7 @@ SILC_FSM_STATE(silc_ske_st_initiator_aborted) SILC_FSM_STATE(silc_ske_st_initiator_error) { SilcSKE ske = fsm_context; - SilcSKEStatus status; + SilcUInt32 status; unsigned char data[4]; SILC_LOG_DEBUG(("Error %s (%d) occurred during key exchange", @@ -1837,7 +1874,7 @@ SILC_FSM_STATE(silc_ske_st_initiator_error) status = SILC_SKE_STATUS_ERROR; /* Send FAILURE packet */ - SILC_PUT32_MSB((SilcUInt32)status, data); + SILC_PUT32_MSB(status, data); silc_ske_packet_send(ske, SILC_PACKET_FAILURE, 0, data, 4); silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske); @@ -1854,13 +1891,15 @@ SILC_FSM_STATE(silc_ske_st_initiator_error) SILC_FSM_STATE(silc_ske_st_initiator_failure) { SilcSKE ske = fsm_context; - SilcUInt32 error = SILC_SKE_STATUS_ERROR; + SilcUInt32 error = ske->status; if (ske->packet && silc_buffer_len(&ske->packet->buffer) == 4) { SILC_GET32_MSB(error, ske->packet->buffer.data); silc_packet_free(ske->packet); ske->packet = NULL; } + if (error == SILC_SKE_STATUS_OK) + error = SILC_SKE_STATUS_ERROR; ske->status = error; SILC_LOG_DEBUG(("Error %s (%d) received during key exchange", @@ -1898,17 +1937,22 @@ SilcAsyncOperation silc_ske_initiator(SilcSKE ske, ske->session_port = params->session_port; /* Generate security properties if not provided */ - if (!start_payload) { - start_payload = silc_ske_assemble_security_properties(ske, - params->flags, - params->version); + if (!start_payload && !params->prop) { + start_payload = + silc_ske_assemble_security_properties(ske, params->flags, + params->version, + params->small_proposal); if (!start_payload) return NULL; } ske->timeout = params->timeout_secs ? params->timeout_secs : 30; + ske->probe_timeout = (params->probe_timeout_secs ? + params->probe_timeout_secs : 30); ske->start_payload = start_payload; + ske->prop = params->prop; ske->version = params->version; + ske->no_acks = params->no_acks; ++ske->refcnt; /* Link to packet stream to get key exchange packets */ @@ -1919,8 +1963,18 @@ SilcAsyncOperation silc_ske_initiator(SilcSKE ske, SILC_PACKET_SUCCESS, SILC_PACKET_FAILURE, -1); + /* Add key exchange timeout */ + silc_schedule_task_add_timeout(ske->schedule, silc_ske_timeout, + ske, ske->timeout, 0); + if (ske->timeout != ske->probe_timeout) + silc_schedule_task_add_timeout(ske->schedule, silc_ske_probe_timeout, + ske, ske->probe_timeout, 0); + /* Start SKE as initiator */ - silc_fsm_start(&ske->fsm, silc_ske_st_initiator_start); + if (!ske->prop) + silc_fsm_start(&ske->fsm, silc_ske_st_initiator_start); + else + silc_fsm_start(&ske->fsm, silc_ske_st_initiator_phase2); return &ske->op; } @@ -1941,12 +1995,11 @@ SILC_FSM_STATE(silc_ske_st_responder_start) return SILC_FSM_CONTINUE; } - /* Add key exchange timeout */ - silc_schedule_task_add_timeout(ske->schedule, silc_ske_timeout, - ske, ske->timeout, 0); - /** Wait for initiator */ - silc_fsm_next(fsm, silc_ske_st_responder_phase1); + if (!ske->prop) + silc_fsm_next(fsm, silc_ske_st_responder_phase1); + else + silc_fsm_next(fsm, silc_ske_st_responder_phase2); return SILC_FSM_WAIT; } @@ -1975,7 +2028,9 @@ SILC_FSM_STATE(silc_ske_st_responder_phase1) } /* Get remote ID and set it to stream */ - if (ske->packet->src_id_len) { + if (ske->packet->src_id_len && + (ske->packet->src_id_type == SILC_ID_SERVER || + ske->packet->src_id_type == SILC_ID_CLIENT)) { silc_id_str2id(ske->packet->src_id, ske->packet->src_id_len, ske->packet->src_id_type, (ske->packet->src_id_type == SILC_ID_SERVER ? @@ -2194,8 +2249,9 @@ SILC_FSM_STATE(silc_ske_st_responder_phase4) /* The public key verification was performed only if the Mutual Authentication flag is set. */ - if (ske->start_payload && - ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) { + if ((ske->start_payload && + ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) || + ske->prop->flags & SILC_SKE_SP_FLAG_MUTUAL) { unsigned char hash[SILC_HASH_MAXLEN]; SilcUInt32 hash_len; @@ -2385,9 +2441,15 @@ SILC_FSM_STATE(silc_ske_st_responder_phase5) return SILC_FSM_CONTINUE; } - /** Waiting completion */ - silc_fsm_next(fsm, silc_ske_st_responder_end); - return SILC_FSM_WAIT; + if (!ske->no_acks) { + /** Waiting completion */ + silc_fsm_next(fsm, silc_ske_st_responder_end); + return SILC_FSM_WAIT; + } else { + /** Complete protocol */ + silc_fsm_next(fsm, silc_ske_st_responder_end); + return SILC_FSM_CONTINUE; + } } /* Protocol completed */ @@ -2398,14 +2460,15 @@ SILC_FSM_STATE(silc_ske_st_responder_end) unsigned char tmp[4]; SilcUInt32 hash_len, key_len, block_len; - if (ske->packet->type != SILC_PACKET_SUCCESS) { + if (!ske->no_acks && ske->packet->type != SILC_PACKET_SUCCESS) { SILC_LOG_DEBUG(("Remote retransmitted an old packet")); silc_ske_install_retransmission(ske); silc_packet_free(ske->packet); ske->packet = NULL; return SILC_FSM_WAIT; } - silc_packet_free(ske->packet); + if (ske->packet) + silc_packet_free(ske->packet); ske->packet = NULL; /* Process key material */ @@ -2422,9 +2485,11 @@ SILC_FSM_STATE(silc_ske_st_responder_end) return SILC_FSM_CONTINUE; } - /* Send SUCCESS packet */ - SILC_PUT32_MSB(SILC_SKE_STATUS_OK, tmp); - silc_ske_packet_send(ske, SILC_PACKET_SUCCESS, 0, tmp, 4); + if (!ske->no_acks) { + /* Send SUCCESS packet */ + SILC_PUT32_MSB(SILC_SKE_STATUS_OK, tmp); + silc_ske_packet_send(ske, SILC_PACKET_SUCCESS, 0, tmp, 4); + } silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske); silc_schedule_task_del_by_context(ske->schedule, ske); @@ -2462,7 +2527,7 @@ SILC_FSM_STATE(silc_ske_st_responder_aborted) SILC_FSM_STATE(silc_ske_st_responder_failure) { SilcSKE ske = fsm_context; - SilcUInt32 error = SILC_SKE_STATUS_ERROR; + SilcUInt32 error = ske->status; SILC_LOG_DEBUG(("Key exchange protocol failed")); @@ -2471,9 +2536,9 @@ SILC_FSM_STATE(silc_ske_st_responder_failure) silc_packet_free(ske->packet); ske->packet = NULL; } + if (error == SILC_SKE_STATUS_OK) + error = SILC_SKE_STATUS_ERROR; ske->status = error; - if (ske->status == SILC_SKE_STATUS_OK) - ske->status = SILC_SKE_STATUS_ERROR; silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske); silc_schedule_task_del_by_context(ske->schedule, ske); @@ -2490,16 +2555,16 @@ SILC_FSM_STATE(silc_ske_st_responder_error) { SilcSKE ske = fsm_context; unsigned char tmp[4]; + SilcUInt32 status; SILC_LOG_DEBUG(("Error %d (%s) during key exchange protocol", ske->status, silc_ske_map_status(ske->status))); /* Send FAILURE packet */ - if (ske->status == SILC_SKE_STATUS_OUT_OF_MEMORY) - ske->status = SILC_SKE_STATUS_ERROR; - else if (ske->status > SILC_SKE_STATUS_INVALID_COOKIE) - ske->status = SILC_SKE_STATUS_BAD_PAYLOAD; - SILC_PUT32_MSB(ske->status, tmp); + status = ske->status; + if (status > SILC_SKE_STATUS_INVALID_COOKIE) + status = SILC_SKE_STATUS_ERROR; + SILC_PUT32_MSB(status, tmp); silc_ske_packet_send(ske, SILC_PACKET_FAILURE, 0, tmp, 4); silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske); @@ -2534,6 +2599,8 @@ SilcAsyncOperation silc_ske_responder(SilcSKE ske, if (ske->flags & SILC_SKE_SP_FLAG_IV_INCLUDED) ske->session_port = params->session_port; ske->version = params->version; + ske->no_acks = params->no_acks; + ske->prop = params->prop; if (!ske->version) return NULL; ++ske->refcnt; @@ -2546,6 +2613,10 @@ SilcAsyncOperation silc_ske_responder(SilcSKE ske, SILC_PACKET_SUCCESS, SILC_PACKET_FAILURE, -1); + /* Add key exchange timeout */ + silc_schedule_task_add_timeout(ske->schedule, silc_ske_timeout, + ske, ske->timeout, 0); + /* Start SKE as responder */ silc_fsm_start(&ske->fsm, silc_ske_st_responder_start); @@ -3627,7 +3698,7 @@ const char *silc_ske_status_string[] = "Unsupported PKCS", "Unsupported hash function", "Unsupported HMAC", - "Unsupported public key (or certificate)", + "Public key not accepted", "Incorrect signature", "Bad or unsupported version", "Invalid cookie", @@ -3639,6 +3710,7 @@ const char *silc_ske_status_string[] = "Error computing signature", "System out of memory", "Key exchange timeout", + "Key exchange timeout", NULL }; diff --git a/lib/silcske/silcske.h b/lib/silcske/silcske.h index 9c637de6..ecb529fb 100644 --- a/lib/silcske/silcske.h +++ b/lib/silcske/silcske.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2000 - 2007 Pekka Riikonen + Copyright (C) 2000 - 2014 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -75,6 +75,7 @@ typedef enum { SILC_SKE_STATUS_SIGNATURE_ERROR, /* Error computing signature */ SILC_SKE_STATUS_OUT_OF_MEMORY, /* System out of memory */ SILC_SKE_STATUS_TIMEOUT, /* Timeout */ + SILC_SKE_STATUS_PROBE_TIMEOUT, /* Probe timeout */ } SilcSKEStatus; /***/ @@ -212,6 +213,24 @@ typedef struct SilcSKEParamsObject { this time it will timeout. If not specified (zero), default value (30 seconds) will be used. */ SilcUInt16 timeout_secs; + + /* Same as timeout_secs but affects only the first packet sent as + initiator. If the responder does not reply to the first packet in this + time frame the key exchange will timeout. If not specified (zero), + default value (30 seconds) will be used. */ + SilcUInt16 probe_timeout_secs; + + /* If TRUE small proposal is sent with only one security property + proposed instead of list of all currently registered. */ + SilcBool small_proposal; + + /* If TRUE protocol does not end in SUCCESS acknowledgements. */ + SilcBool no_acks; + + /* Pre-allocated security properties to use in negotiation. If provided + the library will perform only key exchange and proposals aren't + exchanged at all. */ + SilcSKESecurityProperties prop; } *SilcSKEParams, SilcSKEParamsStruct; /***/ @@ -413,7 +432,7 @@ void *silc_ske_get_context(SilcSKE ske); * 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. If this SKE session context - * is used to perform rekey, this callback usually is not provided as + * 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. * diff --git a/lib/silcske/silcske_groups.h b/lib/silcske/silcske_groups.h index 09c837c6..e4925312 100644 --- a/lib/silcske/silcske_groups.h +++ b/lib/silcske/silcske_groups.h @@ -102,16 +102,17 @@ void silc_ske_group_free(SilcSKEDiffieHellmanGroup group); * * SYNOPSIS * - * char *silc_ske_get_supported_groups(); + * char *silc_ske_get_supported_groups(SilcUInt32 limit); * * DESCRIPTION * * Returns a comma separated list of support Diffie Hellman groups. * This can be used to get the list of supported groups for SKE - * packets. + * packets. The `limit' specifies the maximum number of groups + * to return. * ***/ -char *silc_ske_get_supported_groups(); +char *silc_ske_get_supported_groups(SilcUInt32 limit); /****f* silcske/SilcSKEGroups/silc_ske_group_get_number * diff --git a/lib/silcske/silcske_i.h b/lib/silcske/silcske_i.h index b7b6e2e7..3467bc93 100644 --- a/lib/silcske/silcske_i.h +++ b/lib/silcske/silcske_i.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2005 - 2008 Pekka Riikonen + Copyright (C) 2005 - 2014 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -88,6 +88,7 @@ struct SilcSKEStruct { } retrans; SilcUInt16 timeout; /* SKE timeout */ + SilcUInt16 probe_timeout; /* First packet timeout */ SilcUInt16 refcnt; /* Reference counter */ unsigned int aborted : 1; /* Set when SKE aborted */ @@ -95,6 +96,7 @@ struct SilcSKEStruct { unsigned int rekeying : 1; /* Set when rekeying */ unsigned int failure_notified : 1; /* Set to indicate that we already called the failure notify routine */ + unsigned int no_acks : 1; /* No SUCCESS acks */ }; #endif /* SILCSKE_I_H */ -- 2.24.0