/* Free KE payload */
if (ske->ke1_payload)
silc_ske_payload_ke_free(ske->ke1_payload);
+ if (ske->ke2_payload)
+ silc_ske_payload_ke_free(ske->ke2_payload);
/* Free rest */
if (ske->prop) {
if (ske->prop->group)
- silc_free(ske->prop->group);
+ silc_ske_group_free(ske->prop->group);
if (ske->prop->pkcs)
silc_pkcs_free(ske->prop->pkcs);
if (ske->prop->cipher)
silc_mp_uninit(ske->KEY);
silc_free(ske->KEY);
}
- if (ske->hash)
- silc_free(ske->hash);
+ silc_free(ske->hash);
+ silc_free(ske->callbacks);
silc_free(ske);
}
}
return status;
}
+ /* Check version string */
+ if (ske->callbacks->check_version) {
+ status = ske->callbacks->check_version(ske, payload->version,
+ payload->version_len,
+ ske->callbacks->context);
+ if (status != SILC_SKE_STATUS_OK) {
+ ske->status = status;
+ silc_ske_payload_start_free(ske->start_payload);
+ return status;
+ }
+ }
+
/* Free our KE Start Payload context, we don't need it anymore. */
silc_ske_payload_start_free(ske->start_payload);
the callback function. */
ske->prop = prop = silc_calloc(1, sizeof(*prop));
prop->flags = payload->flags;
- status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
+ status = silc_ske_group_get_by_name(payload->ke_grp_list, &group);
if (status != SILC_SKE_STATUS_OK)
goto err;
if (payload)
silc_ske_payload_start_free(payload);
- silc_free(group);
+ silc_ske_group_free(group);
if (prop->pkcs)
silc_pkcs_free(prop->pkcs);
}
/* Continue to final state */
+ ske->users++;
silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, NULL);
return SILC_SKE_STATUS_OK;
SilcSocketConnection sock,
char *version,
SilcBuffer start_payload,
- bool mutual_auth)
+ SilcSKESecurityPropertyFlag flags)
{
SilcSKEStatus status = SILC_SKE_STATUS_OK;
SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
ske->start_payload_copy = silc_buffer_copy(start_payload);
/* Force the mutual authentication flag if we want to do it. */
- if (mutual_auth) {
+ if (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) {
+ SILC_LOG_DEBUG(("Force PFS"));
+ remote_payload->flags |= SILC_SKE_SP_FLAG_PFS;
+ }
+
/* Parse and select the security properties from the payload */
payload = silc_calloc(1, sizeof(*payload));
status = silc_ske_select_security_properties(ske, version,
if (ske->callbacks->payload_receive)
(*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
+ silc_ske_payload_start_free(remote_payload);
+
return status;
err:
only for this negotiation and will be free'd after KE is over. */
ske->prop = prop = silc_calloc(1, sizeof(*prop));
prop->flags = start_payload->flags;
- status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
+ status = silc_ske_group_get_by_name(start_payload->ke_grp_list, &group);
if (status != SILC_SKE_STATUS_OK)
goto err;
/* Send the packet. */
if (ske->callbacks->send_packet)
(*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
- ske->callbacks->context);
+ ske->callbacks->context);
silc_buffer_free(payload_buf);
err:
if (group)
- silc_free(group);
+ silc_ske_group_free(group);
if (prop->pkcs)
silc_pkcs_free(prop->pkcs);
}
/* Continue to final state */
+ ske->users++;
silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL);
return SILC_SKE_STATUS_OK;
SilcSKEStatus
silc_ske_assemble_security_properties(SilcSKE ske,
- unsigned char flags,
+ SilcSKESecurityPropertyFlag flags,
char *version,
SilcSKEStartPayload **return_payload)
{
SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
- if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
+ if (silc_ske_group_get_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
SILC_LOG_DEBUG(("Found KE group `%s'", item));
payload->ke_grp_len = 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->ke2_payload->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->ke2_payload->pk_data,
- ske->ke2_payload->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);
+ /* XXX Backward support for 0.6.1 */
+ if (ske->backward_version == 1) {
+ SILC_LOG_DEBUG(("*********** Using old KE payload"));
+ buf = silc_buffer_alloc(ske->start_payload_copy->len +
+ ske->ke2_payload->pk_len + e_len +
+ f_len + KEY_len);
+ silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+
+ ret =
+ silc_buffer_format(buf,
+ SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
+ ske->start_payload_copy->len),
+ SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data,
+ ske->ke2_payload->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);
+ } else {
+ /* Initiator is not required to send its public key */
+ SILC_LOG_DEBUG(("*********** Using new KE payload"));
+ buf = silc_buffer_alloc(ske->start_payload_copy->len +
+ ske->ke2_payload->pk_len +
+ ske->ke1_payload->pk_len +
+ e_len + f_len + KEY_len);
+ silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+
+ 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->ke2_payload->pk_data,
+ ske->ke2_payload->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);
+ } 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->ke2_payload->pk_data,
+ ske->ke2_payload->pk_len),
+ SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data,
+ ske->ke1_payload->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);
SILC_STR_END);
memset(k2, 0, sizeof(k2));
silc_hash_make(hash, dist->data, dist->len, k2);
-
+
/* Take third round */
dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
silc_buffer_pull_tail(dist, hash_len);
dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
memcpy(dtmp, k1, hash_len);
memcpy(dtmp + hash_len, k2, hash_len);
- memcpy(dtmp + hash_len, k3, hash_len);
+ memcpy(dtmp + hash_len + hash_len, k3, hash_len);
key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
memcpy(key->send_enc_key, dtmp, enc_key_len);
dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
memcpy(dtmp, k1, hash_len);
memcpy(dtmp + hash_len, k2, hash_len);
- memcpy(dtmp + hash_len, k3, hash_len);
+ memcpy(dtmp + hash_len + hash_len, k3, hash_len);
key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
memcpy(key->receive_enc_key, dtmp, enc_key_len);
key->enc_key_len = req_enc_key_len;
}
- /* Take HMAC key */
+ /* Take HMAC keys */
memset(hashd, 0, sizeof(hashd));
buf->data[0] = 4;
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, hashd, req_hmac_key_len);
+ 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);
+ 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;
+ memset(hashd, 0, sizeof(hashd));
silc_buffer_free(buf);
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);
+ if (key->send_hmac_key) {
+ memset(key->send_hmac_key, 0, key->hmac_key_len);
+ silc_free(key->send_hmac_key);
+ }
+ if (key->receive_hmac_key) {
+ memset(key->receive_hmac_key, 0, key->hmac_key_len);
+ silc_free(key->receive_hmac_key);
}
silc_free(key);
}
+
+const char *silc_ske_status_string[] =
+{
+ /* Official */
+ "Ok",
+ "Unkown error occurred",
+ "Bad payload in packet",
+ "Unsupported group",
+ "Unsupported cipher",
+ "Unsupported PKCS",
+ "Unsupported hash function",
+ "Unsupported HMAC",
+ "Unsupported public key (or certificate)",
+ "Incorrect signature",
+ "Bad or unsupported version",
+ "Invalid cookie",
+
+ /* Other errors */
+ "Pending",
+ "Remote did not provide public key",
+ "Key exchange protocol is not active",
+ "Bad reserved field in packet",
+ "Bad payload length in packet",
+ "Incorrect hash",
+
+ NULL
+};
+
+/* Maps status to readable string and returns the string. If string is not
+ found and empty character string ("") is returned. */
+
+const char *silc_ske_map_status(SilcSKEStatus status)
+{
+ int i;
+
+ for (i = 0; silc_ske_status_string[i]; i++)
+ if (status == i)
+ return silc_ske_status_string[i];
+
+ return "";
+}