GNU General Public License for more details.
*/
-/*
- * $Id$
- * $Log$
- * Revision 1.4 2000/07/07 06:46:43 priikone
- * Removed ske_verify_public_key function as it is not needed
- * anymore. Added support to the public key verification as callback
- * function. Other minor changes and bug fixes.
- *
- * Revision 1.3 2000/07/06 07:12:39 priikone
- * Support for SILC style public keys added.
- *
- * Revision 1.2 2000/07/05 06:05:15 priikone
- * Global cosmetic change.
- *
- * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
- * Imported from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
#include "silcincludes.h"
#include "payload_internal.h"
SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
ske = silc_calloc(1, sizeof(*ske));
+ ske->status = SILC_SKE_STATUS_OK;
return ske;
}
silc_buffer_free(ske->start_payload_copy);
if (ske->pk)
silc_free(ske->pk);
- /* XXX
- silc_mp_clear(&ske->x);
- silc_mp_clear(&ske->KEY);
- */
+ if (ske->x) {
+ silc_mp_clear(ske->x);
+ silc_free(ske->x);
+ }
+ if (ske->KEY) {
+ silc_mp_clear(ske->KEY);
+ silc_free(ske->KEY);
+ }
if (ske->hash)
silc_free(ske->hash);
silc_free(ske);
/* Decode the payload */
status = silc_ske_payload_start_decode(ske, start_payload, &payload);
- if (status != SILC_SKE_STATUS_OK)
+ if (status != SILC_SKE_STATUS_OK) {
+ ske->status = status;
return status;
+ }
/* Take the selected security properties into use while doing
the key exchange. This is used only while doing the key
if (status == SILC_SKE_STATUS_OK)
return SILC_SKE_STATUS_ERROR;
+ ske->status = status;
return status;
}
Key Exchange 1 Payload. */
SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
+ SilcPublicKey public_key,
SilcSKESendPacketCb send_packet,
void *context)
{
SilcSKEStatus status = SILC_SKE_STATUS_OK;
SilcBuffer payload_buf;
- SilcInt x, e;
+ SilcInt *x, e;
SilcSKEOnePayload *payload;
+ unsigned int pk_len;
SILC_LOG_DEBUG(("Start"));
/* Create the random number x, 1 < x < q. */
- silc_mp_init(&x);
+ x = silc_calloc(1, sizeof(*x));
+ silc_mp_init(x);
status =
silc_ske_create_rnd(ske, ske->prop->group->group_order,
silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
- &x);
+ x);
if (status != SILC_SKE_STATUS_OK) {
- silc_mp_clear(&x);
+ silc_mp_clear(x);
+ silc_free(x);
+ ske->status = status;
return status;
}
/* Do the Diffie Hellman computation, e = g ^ x mod p */
silc_mp_init(&e);
- silc_mp_powm(&e, &ske->prop->group->generator, &x,
+ silc_mp_powm(&e, &ske->prop->group->generator, x,
&ske->prop->group->group);
/* Encode the result to Key Exchange 1 Payload. */
payload = silc_calloc(1, sizeof(*payload));
payload->e = e;
+ payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
+ if (!payload->pk_data) {
+ silc_mp_clear(x);
+ silc_free(x);
+ silc_mp_clear(&e);
+ silc_free(payload);
+ ske->status = SILC_SKE_STATUS_OK;
+ return ske->status;
+ }
+ payload->pk_len = pk_len;
+ payload->pk_type = SILC_SKE_PK_TYPE_SILC;
status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
if (status != SILC_SKE_STATUS_OK) {
- silc_mp_clear(&x);
+ silc_mp_clear(x);
+ silc_free(x);
silc_mp_clear(&e);
+ silc_free(payload->pk_data);
silc_free(payload);
+ ske->status = status;
return status;
}
SilcSKEStatus status = SILC_SKE_STATUS_OK;
SilcSKETwoPayload *payload;
SilcPublicKey public_key = NULL;
- SilcInt KEY;
+ SilcInt *KEY;
unsigned char hash[32];
unsigned int hash_len;
/* Decode the payload */
status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
- if (status != SILC_SKE_STATUS_OK)
+ if (status != SILC_SKE_STATUS_OK) {
+ ske->status = status;
return status;
+ }
ske->ke2_payload = payload;
SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
/* Compute the shared secret key */
- silc_mp_init(&KEY);
- silc_mp_powm(&KEY, &payload->f, &ske->x, &ske->prop->group->group);
+ KEY = silc_calloc(1, sizeof(*KEY));
+ silc_mp_init(KEY);
+ silc_mp_powm(KEY, &payload->f, ske->x, &ske->prop->group->group);
ske->KEY = KEY;
SILC_LOG_DEBUG(("Verifying public key"));
/* Verify signature */
silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
public_key->pk_len);
- if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
- payload->sign_data, payload->sign_len,
- hash, hash_len) == FALSE) {
+ if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data,
+ payload->sign_len, hash, hash_len) == FALSE) {
SILC_LOG_DEBUG(("Signature don't match"));
silc_ske_payload_two_free(payload);
ske->ke2_payload = NULL;
- silc_mp_clear(&ske->KEY);
+ silc_mp_clear(ske->KEY);
+ silc_free(ske->KEY);
+ ske->KEY = NULL;
if (public_key)
silc_pkcs_public_key_free(public_key);
if (status == SILC_SKE_STATUS_OK)
return SILC_SKE_STATUS_ERROR;
+ ske->status = status;
return status;
}
SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
SilcSocketConnection sock,
+ char *version,
SilcBuffer start_payload,
SilcSKECb callback,
void *context)
/* Decode the payload */
status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
- if (status != SILC_SKE_STATUS_OK)
+ if (status != SILC_SKE_STATUS_OK) {
+ ske->status = status;
return status;
+ }
/* Take a copy of the payload buffer for future use. It is used to
compute the HASH value. */
/* Parse and select the security properties from the payload */
payload = silc_calloc(1, sizeof(*payload));
- status = silc_ske_select_security_properties(ske, payload, remote_payload);
+ status = silc_ske_select_security_properties(ske, version,
+ payload, remote_payload);
if (status != SILC_SKE_STATUS_OK)
goto err;
if (status == SILC_SKE_STATUS_OK)
return SILC_SKE_STATUS_ERROR;
+ ske->status = status;
return status;
}
SilcSKEStatus status = SILC_SKE_STATUS_OK;
SilcBuffer payload_buf;
SilcSKESecurityProperties prop;
- SilcSKEDiffieHellmanGroup group;
+ SilcSKEDiffieHellmanGroup group = NULL;
SILC_LOG_DEBUG(("Start"));
return status;
err:
- silc_free(group);
+ if (group)
+ silc_free(group);
if (prop->pkcs)
silc_pkcs_free(prop->pkcs);
if (status == SILC_SKE_STATUS_OK)
return SILC_SKE_STATUS_ERROR;
+ ske->status = status;
return status;
}
SilcSKEStatus status = SILC_SKE_STATUS_OK;
SilcSKEOnePayload *one_payload;
SilcSKETwoPayload *two_payload;
- SilcInt x, f;
+ SilcInt *x, f;
SILC_LOG_DEBUG(("Start"));
/* Decode Key Exchange 1 Payload */
status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
- if (status != SILC_SKE_STATUS_OK)
+ if (status != SILC_SKE_STATUS_OK) {
+ ske->status = status;
return status;
+ }
/* Create the random number x, 1 < x < q. */
- silc_mp_init(&x);
+ x = silc_calloc(1, sizeof(*x));
+ silc_mp_init(x);
status =
silc_ske_create_rnd(ske, ske->prop->group->group_order,
silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
- &x);
+ x);
if (status != SILC_SKE_STATUS_OK) {
- silc_mp_clear(&x);
+ silc_mp_clear(x);
+ silc_free(x);
return status;
}
/* Do the Diffie Hellman computation, f = g ^ x mod p */
silc_mp_init(&f);
- silc_mp_powm(&f, &ske->prop->group->generator, &x,
+ silc_mp_powm(&f, &ske->prop->group->generator, x,
&ske->prop->group->group);
/* Save the results for later processing */
{
SilcSKEStatus status = SILC_SKE_STATUS_OK;
SilcBuffer payload_buf;
- SilcInt KEY;
+ SilcInt *KEY;
unsigned char hash[32], sign[256], *pk;
unsigned int hash_len, sign_len, pk_len;
SILC_LOG_DEBUG(("Start"));
+ if (!public_key || !private_key) {
+ status = SILC_SKE_STATUS_ERROR;
+ goto err;
+ }
+
SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
/* Compute the shared secret key */
- silc_mp_init(&KEY);
- silc_mp_powm(&KEY, &ske->ke1_payload->e, &ske->x,
+ KEY = silc_calloc(1, sizeof(*KEY));
+ silc_mp_init(KEY);
+ silc_mp_powm(KEY, &ske->ke1_payload->e, ske->x,
&ske->prop->group->group);
ske->KEY = KEY;
/* Get the public key */
pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+ if (!pk) {
+ status = SILC_SKE_STATUS_ERROR;
+ goto err;
+ }
ske->ke2_payload->pk_data = pk;
ske->ke2_payload->pk_len = pk_len;
ske->ke2_payload->pk_type = pk_type;
/* Sign the hash value */
silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
private_key->prv_len);
- ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
- hash, hash_len,
- sign, &sign_len);
+ silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
memcpy(ske->ke2_payload->sign_data, sign, sign_len);
memset(sign, 0, sizeof(sign));
return status;
err:
- silc_mp_clear(&ske->KEY);
+ silc_mp_clear(ske->KEY);
+ silc_free(ske->KEY);
+ ske->KEY = NULL;
silc_ske_payload_two_free(ske->ke2_payload);
if (status == SILC_SKE_STATUS_OK)
return SILC_SKE_STATUS_ERROR;
+ ske->status = status;
return status;
}
SilcSKESendPacketCb send_packet,
void *context)
{
- SilcSKEStatus status = SILC_SKE_STATUS_OK;
SilcBuffer packet;
SILC_LOG_DEBUG(("Start"));
- packet = silc_buffer_alloc(1);
- packet->len = 0;
+ packet = silc_buffer_alloc(4);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(SILC_SKE_STATUS_OK),
+ SILC_STR_END);
if (send_packet)
(*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
- return status;
+ silc_buffer_free(packet);
+
+ return SILC_SKE_STATUS_OK;
}
/* Aborts the Key Exchange protocol. This is called if error occurs
SilcSKEStatus
silc_ske_assemble_security_properties(SilcSKE ske,
+ unsigned char flags,
+ char *version,
SilcSKEStartPayload **return_payload)
{
SilcSKEStartPayload *rp;
+ int i;
SILC_LOG_DEBUG(("Assembling KE Start Payload"));
rp = silc_calloc(1, sizeof(*rp));
- /* XXX */
/* Set flags */
- rp->flags = 0;
+ rp->flags = flags;
- /* XXX */
- /* Cookie */
- rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
+ /* Set random cookie */
+ rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
+ for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
+ rp->cookie[i] = silc_rng_get_byte(ske->rng);
rp->cookie_len = SILC_SKE_COOKIE_LEN;
- memcpy(rp->cookie, "1234567890123456", SILC_SKE_COOKIE_LEN);
+
+ /* Put version */
+ rp->version = strdup(version);
+ rp->version_len = strlen(version);
/* Get supported Key Exhange groups */
rp->ke_grp_list = silc_ske_get_supported_groups();
rp->comp_alg_len = 0;
rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
+ 2 + rp->version_len +
2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
2 + rp->comp_alg_len;
SilcSKEStatus
silc_ske_select_security_properties(SilcSKE ske,
+ char *version,
SilcSKEStartPayload *payload,
SilcSKEStartPayload *remote_payload)
{
+ SilcSKEStatus status;
SilcSKEStartPayload *rp;
char *cp;
int len;
rp = remote_payload;
+ /* Check version string */
+ status = silc_ske_check_version(ske, rp->version, rp->version_len);
+ if (status != SILC_SKE_STATUS_OK) {
+ ske->status = status;
+ return status;
+ }
+
/* Flags are returned unchanged. */
payload->flags = rp->flags;
- /* XXX Cookie check?? */
+ /* Take cookie */
payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
payload->cookie_len = SILC_SKE_COOKIE_LEN;
memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
+ /* Put our version to our reply */
+ payload->version = strdup(version);
+ payload->version_len = strlen(version);
+
/* Get supported Key Exchange groups */
cp = rp->ke_grp_list;
if (cp && strchr(cp, ',')) {
#endif
payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
+ 2 + payload->version_len +
2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
2 + payload->comp_alg_len;
SILC_LOG_DEBUG(("Creating random number"));
/* Get the random number as string */
- string = silc_rng_get_rn_string(ske->rng, (len / 8));
+ string = silc_rng_get_rn_data(ske->rng, (len / 8));
+ if (!string)
+ return SILC_SKE_STATUS_ERROR;
/* Decode the string into a MP integer */
- silc_mp_set_str(rnd, string, 16);
+ silc_mp_bin2mp(string, (len / 8), rnd);
silc_mp_mod_2exp(rnd, rnd, len);
/* Checks */
SilcBuffer buf;
unsigned char *e, *f, *KEY;
unsigned int e_len, f_len, KEY_len;
+ int ret;
SILC_LOG_DEBUG(("Start"));
- e_len = silc_mp_sizeinbase(&ske->ke1_payload->e, 16);
- e = silc_calloc(e_len + 1, sizeof(unsigned char));
- silc_mp_get_str(e, 16, &ske->ke1_payload->e);
-
- f_len = silc_mp_sizeinbase(&ske->ke2_payload->f, 16);
- f = silc_calloc(f_len + 1, sizeof(unsigned char));
- silc_mp_get_str(f, 16, &ske->ke2_payload->f);
-
- KEY_len = silc_mp_sizeinbase(&ske->KEY, 16);
- KEY = silc_calloc(KEY_len + 1, sizeof(unsigned char));
- silc_mp_get_str(KEY, 16, &ske->KEY);
+ e = silc_mp_mp2bin(&ske->ke1_payload->e, 0, &e_len);
+ f = silc_mp_mp2bin(&ske->ke2_payload->f, 0, &f_len);
+ KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
buf = silc_buffer_alloc(ske->start_payload_copy->len +
ske->pk_len + e_len + f_len + KEY_len);
silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
/* Format the buffer used to compute the hash value */
- silc_buffer_format(buf,
- SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
- ske->start_payload_copy->len),
- SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
- SILC_STR_UI_XNSTRING(e, e_len),
- SILC_STR_UI_XNSTRING(f, f_len),
- SILC_STR_UI_XNSTRING(KEY, KEY_len),
- SILC_STR_END);
-
-#if 0
- SILC_LOG_HEXDUMP(("Hash buffer"), buf->data, buf->len);
-#endif
+ ret = silc_buffer_format(buf,
+ SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
+ ske->start_payload_copy->len),
+ SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
+ SILC_STR_UI_XNSTRING(e, e_len),
+ SILC_STR_UI_XNSTRING(f, f_len),
+ SILC_STR_UI_XNSTRING(KEY, KEY_len),
+ SILC_STR_END);
+ if (ret == -1) {
+ silc_buffer_free(buf);
+ memset(e, 0, e_len);
+ memset(f, 0, f_len);
+ memset(KEY, 0, KEY_len);
+ silc_free(e);
+ silc_free(f);
+ silc_free(KEY);
+ return SILC_SKE_STATUS_ERROR;
+ }
/* Make the hash */
silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
return status;
}
-/* Processes negotiated key material as protocol specifies. This returns
- the actual keys to be used in the SILC. */
+/* Processes the provided key material `data' as the SILC protocol
+ specification specifies. */
-SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
- unsigned int req_iv_len,
- unsigned int req_enc_key_len,
- unsigned int req_hmac_key_len,
- SilcSKEKeyMaterial *key)
+SilcSKEStatus
+silc_ske_process_key_material_data(unsigned char *data,
+ unsigned int data_len,
+ unsigned int req_iv_len,
+ unsigned int req_enc_key_len,
+ unsigned int req_hmac_key_len,
+ SilcHash hash,
+ SilcSKEKeyMaterial *key)
{
- int i, klen;
SilcBuffer buf;
- SilcInt tmp;
- unsigned char *tmpbuf;
- unsigned char hash[32];
- unsigned int hash_len = ske->prop->hash->hash->hash_len;
+ unsigned char hashd[32];
+ unsigned int hash_len = req_hmac_key_len;
unsigned int enc_key_len = req_enc_key_len / 8;
SILC_LOG_DEBUG(("Start"));
- silc_mp_init_set(&tmp, &ske->KEY);
-
- klen = silc_mp_size(&tmp);
-
- /* Format the KEY material into binary data */
- tmpbuf = silc_calloc(klen, sizeof(unsigned char));
- for (i = klen; i > 0; i--) {
- tmpbuf[i - 1] = (unsigned char)(silc_mp_get_ui(&tmp) & 0xff);
- silc_mp_fdiv_q_2exp(&tmp, &tmp, 8);
- }
-
- buf = silc_buffer_alloc(1 + klen + hash_len);
-
+ buf = silc_buffer_alloc(1 + data_len);
silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
silc_buffer_format(buf,
SILC_STR_UI_CHAR(0),
- SILC_STR_UI_XNSTRING(tmpbuf, klen),
- SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
+ SILC_STR_UI_XNSTRING(data, data_len),
SILC_STR_END);
/* Take IVs */
- memset(hash, 0, sizeof(hash));
+ memset(hashd, 0, sizeof(hashd));
buf->data[0] = 0;
- silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+ silc_hash_make(hash, buf->data, buf->len, hashd);
key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
- memcpy(key->send_iv, hash, req_iv_len);
- memset(hash, 0, sizeof(hash));
+ memcpy(key->send_iv, hashd, req_iv_len);
+ memset(hashd, 0, sizeof(hashd));
buf->data[0] = 1;
- silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+ silc_hash_make(hash, buf->data, buf->len, hashd);
key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
- memcpy(key->receive_iv, hash, req_iv_len);
+ memcpy(key->receive_iv, hashd, req_iv_len);
key->iv_len = req_iv_len;
/* Take the encryption keys. If requested key size is more than
if (enc_key_len > (3 * hash_len))
return SILC_SKE_STATUS_ERROR;
+ /* Take first round */
memset(k1, 0, sizeof(k1));
- silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
+ silc_hash_make(hash, buf->data, buf->len, k1);
- /* XXX */
- dist = silc_buffer_alloc(hash_len * 3);
-
- silc_buffer_pull_tail(dist, klen + hash_len);
+ /* Take second round */
+ dist = silc_buffer_alloc(data_len + hash_len);
+ silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
silc_buffer_format(dist,
- SILC_STR_UI_XNSTRING(tmpbuf, klen),
+ 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(ske->prop->hash, dist->data, dist->len, k2);
+ silc_hash_make(hash, dist->data, dist->len, k2);
- silc_buffer_pull(dist, klen + hash_len);
+ /* Take third round */
+ dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
+ silc_buffer_pull(dist, data_len + hash_len);
silc_buffer_format(dist,
SILC_STR_UI_XNSTRING(k2, hash_len),
SILC_STR_END);
- silc_buffer_push(dist, klen + hash_len);
-
+ silc_buffer_push(dist, data_len + hash_len);
memset(k3, 0, sizeof(k3));
- silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
-
+ silc_hash_make(hash, dist->data, dist->len, k3);
+
+ /* Then, save the keys */
dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
memcpy(dtmp, k1, hash_len);
memcpy(dtmp + hash_len, k2, hash_len);
silc_buffer_free(dist);
} else {
/* Take normal hash as key */
- memset(hash, 0, sizeof(hash));
- silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+ memset(hashd, 0, sizeof(hashd));
+ silc_hash_make(hash, buf->data, buf->len, hashd);
key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
- memcpy(key->send_enc_key, hash, enc_key_len);
+ memcpy(key->send_enc_key, hashd, enc_key_len);
key->enc_key_len = req_enc_key_len;
}
if (enc_key_len > (3 * hash_len))
return SILC_SKE_STATUS_ERROR;
+ /* Take first round */
memset(k1, 0, sizeof(k1));
- silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
-
- /* XXX */
- dist = silc_buffer_alloc(hash_len * 3);
+ silc_hash_make(hash, buf->data, buf->len, k1);
- silc_buffer_pull_tail(dist, klen + hash_len);
+ /* Take second round */
+ dist = silc_buffer_alloc(data_len + hash_len);
+ silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
silc_buffer_format(dist,
- SILC_STR_UI_XNSTRING(tmpbuf, klen),
+ 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(ske->prop->hash, dist->data, dist->len, k2);
+ silc_hash_make(hash, dist->data, dist->len, k2);
- silc_buffer_pull(dist, klen + hash_len);
+ /* Take third round */
+ dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
+ silc_buffer_pull(dist, data_len + hash_len);
silc_buffer_format(dist,
SILC_STR_UI_XNSTRING(k2, hash_len),
SILC_STR_END);
- silc_buffer_push(dist, klen + hash_len);
-
+ silc_buffer_push(dist, data_len + hash_len);
memset(k3, 0, sizeof(k3));
- silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
-
+ silc_hash_make(hash, dist->data, dist->len, k3);
+
+ /* Then, save the keys */
dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
memcpy(dtmp, k1, hash_len);
memcpy(dtmp + hash_len, k2, hash_len);
silc_buffer_free(dist);
} else {
/* Take normal hash as key */
- memset(hash, 0, sizeof(hash));
- silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+ memset(hashd, 0, sizeof(hashd));
+ silc_hash_make(hash, buf->data, buf->len, hashd);
key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
- memcpy(key->receive_enc_key, hash, enc_key_len);
+ memcpy(key->receive_enc_key, hashd, enc_key_len);
key->enc_key_len = req_enc_key_len;
}
/* Take HMAC key */
- memset(hash, 0, sizeof(hash));
+ memset(hashd, 0, sizeof(hashd));
buf->data[0] = 4;
- silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
+ silc_hash_make(hash, buf->data, buf->len, hashd);
key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
- memcpy(key->hmac_key, hash, req_hmac_key_len);
+ memcpy(key->hmac_key, hashd, req_hmac_key_len);
key->hmac_key_len = req_hmac_key_len;
+ silc_buffer_free(buf);
+
+ return SILC_SKE_STATUS_OK;
+}
+
+/* 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,
+ unsigned int req_iv_len,
+ unsigned int req_enc_key_len,
+ unsigned int req_hmac_key_len,
+ SilcSKEKeyMaterial *key)
+{
+ SilcSKEStatus status;
+ SilcBuffer buf;
+ unsigned char *tmpbuf;
+ int klen;
+
+ /* Encode KEY to binary data */
+ tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
+
+ buf = silc_buffer_alloc(klen + ske->hash_len);
+ silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+ 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);
+
memset(tmpbuf, 0, klen);
silc_free(tmpbuf);
+ silc_buffer_free(buf);
- return SILC_SKE_STATUS_OK;
+ return status;
+}
+
+/* Free key material structure */
+
+void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
+{
+ if (key->send_iv)
+ silc_free(key->send_iv);
+ if (key->receive_iv)
+ silc_free(key->receive_iv);
+ if (key->send_enc_key) {
+ memset(key->send_enc_key, 0, key->enc_key_len / 8);
+ silc_free(key->send_enc_key);
+ }
+ if (key->receive_enc_key) {
+ memset(key->receive_enc_key, 0, key->enc_key_len / 8);
+ silc_free(key->receive_enc_key);
+ }
+ if (key->hmac_key) {
+ memset(key->hmac_key, 0, key->hmac_key_len);
+ silc_free(key->hmac_key);
+ }
+ silc_free(key);
}