Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- Copyright (C) 2000 Pekka Riikonen
+ Copyright (C) 2000 - 2001 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
if (ske->start_payload)
silc_ske_payload_start_free(ske->start_payload);
- /* Free KE1 payload */
+ /* Free KE payload */
if (ske->ke1_payload)
- silc_ske_payload_one_free(ske->ke1_payload);
-
- /* Free KE2 payload */
- if (ske->ke2_payload)
- silc_ske_payload_two_free(ske->ke2_payload);
+ silc_ske_payload_ke_free(ske->ke1_payload);
/* Free rest */
if (ske->prop) {
silc_cipher_free(ske->prop->cipher);
if (ske->prop->hash)
silc_hash_free(ske->prop->hash);
+ if (ske->prop->hmac)
+ silc_hmac_free(ske->prop->hmac);
silc_free(ske->prop);
}
if (ske->start_payload_copy)
goto err;
}
+ if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_HMAC;
+ goto err;
+ }
+
ske->start_payload = payload;
/* Return the received payload by calling the callback function. */
silc_cipher_free(prop->cipher);
if (prop->hash)
silc_hash_free(prop->hash);
+ if (prop->hmac)
+ silc_hmac_free(prop->hmac);
silc_free(prop);
ske->prop = NULL;
/* 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 1 Payload. */
+ Key Exchange Payload. */
SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
SilcPublicKey public_key,
+ SilcPrivateKey private_key,
SilcSKESendPacketCb send_packet,
void *context)
{
SilcSKEStatus status = SILC_SKE_STATUS_OK;
SilcBuffer payload_buf;
SilcInt *x, e;
- SilcSKEOnePayload *payload;
- unsigned int pk_len;
+ SilcSKEKEPayload *payload;
+ uint32 pk_len;
SILC_LOG_DEBUG(("Start"));
silc_mp_init(&e);
silc_mp_powm(&e, &ske->prop->group->generator, x,
&ske->prop->group->group);
-
- /* Encode the result to Key Exchange 1 Payload. */
+
+ /* Encode the result to Key Exchange Payload. */
+
payload = silc_calloc(1, sizeof(*payload));
- payload->e = e;
+ ske->ke1_payload = payload;
+
+ payload->x = e;
+
+ /* Get public key */
payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
if (!payload->pk_data) {
silc_mp_clear(x);
}
payload->pk_len = pk_len;
payload->pk_type = SILC_SKE_PK_TYPE_SILC;
- status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
+
+ /* Compute signature data if we are doing mutual authentication */
+ if (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
+ unsigned char hash[32], sign[1024];
+ uint32 hash_len, sign_len;
+
+ SILC_LOG_DEBUG(("We are doing mutual authentication"));
+ SILC_LOG_DEBUG(("Computing HASH value"));
+
+ /* Compute the hash value */
+ memset(hash, 0, sizeof(hash));
+ silc_ske_make_hash(ske, hash, &hash_len, TRUE);
+
+ 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_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
+ payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
+ memcpy(payload->sign_data, sign, sign_len);
+ memset(sign, 0, sizeof(sign));
+ payload->sign_len = sign_len;
+ }
+
+ status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
if (status != SILC_SKE_STATUS_OK) {
silc_mp_clear(x);
silc_free(x);
return status;
}
- ske->ke1_payload = payload;
ske->x = x;
/* Send the packet. */
return status;
}
-/* Receives Key Exchange 2 Payload from responder consisting responders
+/* 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. */
SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
- SilcBuffer ke2_payload,
+ SilcBuffer ke_payload,
SilcSKEVerifyCb verify_key,
void *verify_context,
SilcSKECb callback,
void *context)
{
SilcSKEStatus status = SILC_SKE_STATUS_OK;
- SilcSKETwoPayload *payload;
+ SilcSKEKEPayload *payload;
SilcPublicKey public_key = NULL;
SilcInt *KEY;
unsigned char hash[32];
- unsigned int hash_len;
+ uint32 hash_len;
SILC_LOG_DEBUG(("Start"));
/* Decode the payload */
- status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
+ status = silc_ske_payload_ke_decode(ske, ke_payload, &payload);
if (status != SILC_SKE_STATUS_OK) {
ske->status = status;
return status;
/* Compute the shared secret key */
KEY = silc_calloc(1, sizeof(*KEY));
silc_mp_init(KEY);
- silc_mp_powm(KEY, &payload->f, ske->x, &ske->prop->group->group);
+ silc_mp_powm(KEY, &payload->x, ske->x, &ske->prop->group->group);
ske->KEY = KEY;
SILC_LOG_DEBUG(("Verifying public key"));
SILC_LOG_DEBUG(("Public key is authentic"));
/* Compute the hash value */
- status = silc_ske_make_hash(ske, hash, &hash_len);
+ status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
if (status != SILC_SKE_STATUS_OK)
goto err;
memcpy(ske->hash, hash, hash_len);
ske->hash_len = hash_len;
- SILC_LOG_DEBUG(("Verifying signature"));
+ SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
/* Verify signature */
silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
err:
memset(hash, 'F', sizeof(hash));
- silc_ske_payload_two_free(payload);
+ silc_ske_payload_ke_free(payload);
ske->ke2_payload = NULL;
silc_mp_clear(ske->KEY);
SilcSocketConnection sock,
char *version,
SilcBuffer start_payload,
+ int mutual_auth,
SilcSKECb callback,
void *context)
{
compute the HASH value. */
ske->start_payload_copy = silc_buffer_copy(start_payload);
+ /* Force the mutual authentication flag if we want to do it. */
+ if (mutual_auth) {
+ SILC_LOG_DEBUG(("Force mutual authentication"));
+ remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
+ }
+
/* Parse and select the security properties from the payload */
payload = silc_calloc(1, sizeof(*payload));
status = silc_ske_select_security_properties(ske, version,
goto err;
}
+ if (silc_hmac_alloc(start_payload->hmac_alg_list, NULL,
+ &prop->hmac) == FALSE) {
+ status = SILC_SKE_STATUS_UNKNOWN_HMAC;
+ goto err;
+ }
+
/* Encode the payload */
status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
if (status != SILC_SKE_STATUS_OK)
silc_cipher_free(prop->cipher);
if (prop->hash)
silc_hash_free(prop->hash);
+ if (prop->hmac)
+ silc_hmac_free(prop->hmac);
silc_free(prop);
ske->prop = NULL;
return status;
}
-/* This function receives the Key Exchange 1 Payload from the initiator.
+/* This function receives the Key Exchange Payload from the initiator.
After processing the payload this then selects 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 2 Payload which is later processed
+ the result f to a Key Exchange Payload which is later processed
in ske_responder_finish function. The callback function should
not touch the payload (it should merely call the ske_responder_finish
function). */
SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
- SilcBuffer ke1_payload,
+ SilcBuffer ke_payload,
+ SilcSKEVerifyCb verify_key,
+ void *verify_context,
SilcSKECb callback,
void *context)
{
SilcSKEStatus status = SILC_SKE_STATUS_OK;
- SilcSKEOnePayload *one_payload;
- SilcSKETwoPayload *two_payload;
+ SilcSKEKEPayload *recv_payload, *send_payload;
SilcInt *x, f;
SILC_LOG_DEBUG(("Start"));
- /* Decode Key Exchange 1 Payload */
- status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
+ /* 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->flags & SILC_SKE_SP_FLAG_MUTUAL) {
+ SilcPublicKey public_key = NULL;
+ unsigned char hash[32];
+ uint32 hash_len;
+
+ SILC_LOG_DEBUG(("We are doing mutual authentication"));
+ SILC_LOG_DEBUG(("Verifying public key"));
+
+ if (!silc_pkcs_public_key_decode(recv_payload->pk_data,
+ recv_payload->pk_len,
+ &public_key)) {
+ status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
+ return status;
+ }
+
+ if (verify_key) {
+ status = (*verify_key)(ske, recv_payload->pk_data, recv_payload->pk_len,
+ recv_payload->pk_type, verify_context);
+ if (status != SILC_SKE_STATUS_OK)
+ return status;
+ }
+
+ SILC_LOG_DEBUG(("Public key is authentic"));
+
+ /* Compute the hash value */
+ status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
+ if (status != SILC_SKE_STATUS_OK)
+ return status;
+
+ SILC_LOG_DEBUG(("Verifying signature"));
+
+ /* Verify signature */
+ silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
+ public_key->pk_len);
+ if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data,
+ recv_payload->sign_len, hash, hash_len) == FALSE) {
+
+ SILC_LOG_DEBUG(("Signature don't match"));
+
+ status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
+ return status;
+ }
+
+ SILC_LOG_DEBUG(("Signature is Ok"));
+
+ silc_pkcs_public_key_free(public_key);
+ memset(hash, 'F', hash_len);
+ }
+
/* Create the random number x, 1 < x < q. */
x = silc_calloc(1, sizeof(*x));
silc_mp_init(x);
&ske->prop->group->group);
/* Save the results for later processing */
- two_payload = silc_calloc(1, sizeof(*two_payload));
- two_payload->f = f;
+ send_payload = silc_calloc(1, sizeof(*send_payload));
+ send_payload->x = f;
ske->x = x;
- ske->ke1_payload = one_payload;
- ske->ke2_payload = two_payload;
+ ske->ke2_payload = send_payload;
/* Call the callback. */
if (callback)
/* This function computes the secret shared key KEY = e ^ x mod p, and,
a hash value to be signed and sent to the other end. This then
- encodes Key Exchange 2 Payload and sends it to the other end. */
+ encodes Key Exchange Payload and sends it to the other end. */
SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
SilcPublicKey public_key,
SilcSKEStatus status = SILC_SKE_STATUS_OK;
SilcBuffer payload_buf;
SilcInt *KEY;
- unsigned char hash[32], sign[256], *pk;
- unsigned int hash_len, sign_len, pk_len;
+ unsigned char hash[32], sign[1024], *pk;
+ uint32 hash_len, sign_len, pk_len;
SILC_LOG_DEBUG(("Start"));
/* Compute the shared secret key */
KEY = silc_calloc(1, sizeof(*KEY));
silc_mp_init(KEY);
- silc_mp_powm(KEY, &ske->ke1_payload->e, ske->x,
+ silc_mp_powm(KEY, &ske->ke1_payload->x, ske->x,
&ske->prop->group->group);
ske->KEY = KEY;
/* Compute the hash value */
memset(hash, 0, sizeof(hash));
- status = silc_ske_make_hash(ske, hash, &hash_len);
+ status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
if (status != SILC_SKE_STATUS_OK)
goto err;
memset(sign, 0, sizeof(sign));
ske->ke2_payload->sign_len = sign_len;
- /* Encode the Key Exchange 2 Payload */
- status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
- &payload_buf);
+ /* 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;
silc_mp_clear(ske->KEY);
silc_free(ske->KEY);
ske->KEY = NULL;
- silc_ske_payload_two_free(ske->ke2_payload);
+ silc_ske_payload_ke_free(ske->ke2_payload);
if (status == SILC_SKE_STATUS_OK)
return SILC_SKE_STATUS_ERROR;
rp->hash_alg_list = silc_hash_get_supported();
rp->hash_alg_len = strlen(rp->hash_alg_list);
+ /* Get supported HMACs */
+ rp->hmac_alg_list = silc_hmac_get_supported();
+ rp->hmac_alg_len = strlen(rp->hmac_alg_list);
+
/* XXX */
/* Get supported compression algorithms */
rp->comp_alg_list = "";
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;
+ 2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
*return_payload = rp;
payload->hash_alg_list = strdup(rp->hash_alg_list);
}
+ /* Get supported HMACs */
+ cp = rp->hmac_alg_list;
+ if (cp && strchr(cp, ',')) {
+ while(cp) {
+ char *item;
+
+ len = strcspn(cp, ",");
+ item = silc_calloc(len + 1, sizeof(char));
+ memcpy(item, cp, len);
+
+ SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
+
+ if (silc_hmac_is_supported(item) == TRUE) {
+ SILC_LOG_DEBUG(("Found HMAC `%s'", item));
+
+ payload->hmac_alg_len = len;
+ payload->hmac_alg_list = item;
+ break;
+ }
+
+ cp += len;
+ if (strlen(cp) == 0)
+ cp = NULL;
+ else
+ cp++;
+
+ if (item)
+ silc_free(item);
+ }
+
+ if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
+ SILC_LOG_DEBUG(("Could not find supported HMAC"));
+ silc_free(payload->ke_grp_list);
+ silc_free(payload->pkcs_alg_list);
+ silc_free(payload->enc_alg_list);
+ silc_free(payload->hash_alg_list);
+ silc_free(payload);
+ return SILC_SKE_STATUS_UNKNOWN_HMAC;
+ }
+ } else {
+
+ if (!rp->hmac_alg_len) {
+ SILC_LOG_DEBUG(("HMAC not defined in payload"));
+ silc_free(payload->ke_grp_list);
+ silc_free(payload->pkcs_alg_list);
+ silc_free(payload->enc_alg_list);
+ silc_free(payload->hash_alg_list);
+ silc_free(payload);
+ return SILC_SKE_STATUS_BAD_PAYLOAD;
+ }
+
+ SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
+ rp->hmac_alg_list));
+
+ payload->hmac_alg_len = rp->hmac_alg_len;
+ payload->hmac_alg_list = strdup(rp->hmac_alg_list);
+ }
+
#if 0
/* Get supported compression algorithms */
cp = rp->hash_alg_list;
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;
+ 2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
return SILC_SKE_STATUS_OK;
}
of len bits. The rnd sent as argument must be initialized. */
SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
- unsigned int len,
+ uint32 len,
SilcInt *rnd)
{
SilcSKEStatus status = SILC_SKE_STATUS_OK;
return status;
}
-/* Creates a hash value HASH as defined in the SKE protocol. */
+/* Creates a hash value HASH as defined in the SKE protocol. If the
+ `initiator' is TRUE then this function is used to create the HASH_i
+ hash value defined in the protocol. If it is FALSE then this is used
+ to create the HASH value defined by the protocol. */
SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
unsigned char *return_hash,
- unsigned int *return_hash_len)
+ uint32 *return_hash_len,
+ int initiator)
{
SilcSKEStatus status = SILC_SKE_STATUS_OK;
SilcBuffer buf;
unsigned char *e, *f, *KEY;
- unsigned int e_len, f_len, KEY_len;
+ uint32 e_len, f_len, KEY_len;
int ret;
SILC_LOG_DEBUG(("Start"));
- 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));
+ if (initiator == FALSE) {
+ e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
+ f = silc_mp_mp2bin(&ske->ke2_payload->x, 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 */
+ 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;
+ }
- /* Format the buffer used to compute the hash value */
- 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;
+ } else {
+ e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
+
+ buf = silc_buffer_alloc(ske->start_payload_copy->len +
+ ske->pk_len + e_len);
+ silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+
+ /* Format the buffer used to compute the hash value */
+ 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_END);
+ if (ret == -1) {
+ silc_buffer_free(buf);
+ memset(e, 0, e_len);
+ silc_free(e);
+ return SILC_SKE_STATUS_ERROR;
+ }
+
+ memset(e, 0, e_len);
+ silc_free(e);
}
/* Make the hash */
silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
*return_hash_len = ske->prop->hash->hash->hash_len;
- SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
+ if (initiator == FALSE) {
+ SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
+ } else {
+ SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
+ }
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 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,
+ uint32 data_len,
+ uint32 req_iv_len,
+ uint32 req_enc_key_len,
+ uint32 req_hmac_key_len,
+ SilcHash hash,
+ SilcSKEKeyMaterial *key)
{
- int klen;
SilcBuffer buf;
- unsigned char *tmpbuf;
- unsigned char hash[32];
- unsigned int hash_len = ske->prop->hash->hash->hash_len;
- unsigned int enc_key_len = req_enc_key_len / 8;
- int ret;
+ unsigned char hashd[32];
+ uint32 hash_len = req_hmac_key_len;
+ uint32 enc_key_len = req_enc_key_len / 8;
SILC_LOG_DEBUG(("Start"));
- /* Encode KEY to binary data */
- tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
-
- buf = silc_buffer_alloc(1 + klen + hash_len);
+ buf = silc_buffer_alloc(1 + data_len);
silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
- ret = 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_END);
- if (ret == -1) {
- memset(tmpbuf, 0, klen);
- silc_free(tmpbuf);
- silc_buffer_free(buf);
- return SILC_SKE_STATUS_ERROR;
- }
+ silc_buffer_format(buf,
+ SILC_STR_UI_CHAR(0),
+ 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);
-
- /* 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_tail(dist, 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);
+ 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_tail(dist, 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,
+ uint32 req_iv_len,
+ uint32 req_enc_key_len,
+ uint32 req_hmac_key_len,
+ SilcSKEKeyMaterial *key)
+{
+ SilcSKEStatus status;
+ SilcBuffer buf;
+ unsigned char *tmpbuf;
+ uint32 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)
+ return;
+
+ 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);
}