X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilcske%2Fsilcske.c;h=2fd4e0107ea646bea7f2fe87dabc7d29830a80a6;hp=c423b27cb6fd3976d1ca724a55aa6319896dd18c;hb=382d15d447b7a95390decfa783836ae4fe255b3d;hpb=e1459c7b692417464cf23b820ab74c98b0c36f25 diff --git a/lib/silcske/silcske.c b/lib/silcske/silcske.c index c423b27c..2fd4e010 100644 --- a/lib/silcske/silcske.c +++ b/lib/silcske/silcske.c @@ -50,6 +50,8 @@ SilcSKE silc_ske_alloc(SilcRng rng, void *context) SILC_LOG_DEBUG(("Allocating new Key Exchange object")); ske = silc_calloc(1, sizeof(*ske)); + if (!ske) + return NULL; ske->status = SILC_SKE_STATUS_OK; ske->rng = rng; ske->user_data = context; @@ -109,6 +111,8 @@ void silc_ske_free(SilcSKE ske) } silc_free(ske->hash); silc_free(ske->callbacks); + + memset(ske, 'F', sizeof(*ske)); silc_free(ske); } } @@ -157,6 +161,8 @@ void silc_ske_set_callbacks(SilcSKE ske, if (ske->callbacks) silc_free(ske->callbacks); 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; @@ -236,7 +242,7 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, /* Check that the cookie is returned unmodified */ if (memcmp(ske->start_payload->cookie, payload->cookie, ske->start_payload->cookie_len)) { - SILC_LOG_DEBUG(("Responder modified our cookie and it must not do it")); + 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; @@ -262,6 +268,8 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, exchange. The same data is returned to upper levels by calling the callback function. */ ske->prop = prop = silc_calloc(1, sizeof(*prop)); + if (!ske->prop) + goto err; prop->flags = payload->flags; status = silc_ske_group_get_by_name(payload->ke_grp_list, &group); if (status != SILC_SKE_STATUS_OK) @@ -341,6 +349,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){ + ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY; + return ske->status; + } silc_mp_init(x); status = silc_ske_create_rnd(ske, &ske->prop->group->group_order, @@ -356,6 +368,12 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, /* Encode the result to Key Exchange Payload. */ payload = silc_calloc(1, sizeof(*payload)); + if (!payload) { + silc_mp_uninit(x); + silc_free(x); + ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY; + return ske->status; + } ske->ke1_payload = payload; SILC_LOG_DEBUG(("Computing e = g ^ x mod p")); @@ -373,6 +391,7 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, silc_free(x); silc_mp_uninit(&payload->x); silc_free(payload); + ske->ke1_payload = NULL; ske->status = SILC_SKE_STATUS_OK; return ske->status; } @@ -382,7 +401,7 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, /* Compute signature data if we are doing mutual authentication */ if (private_key && ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) { - unsigned char hash[32], sign[1024]; + unsigned char hash[32], sign[2048 + 1]; SilcUInt32 hash_len, sign_len; SILC_LOG_DEBUG(("We are doing mutual authentication")); @@ -397,7 +416,17 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, /* 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); + 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)) { + silc_mp_uninit(x); + silc_free(x); + silc_mp_uninit(&payload->x); + silc_free(payload->pk_data); + silc_free(payload); + ske->ke1_payload = NULL; + ske->status = SILC_SKE_STATUS_SIGNATURE_ERROR; + return ske->status; + } payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char)); memcpy(payload->sign_data, sign, sign_len); memset(sign, 0, sizeof(sign)); @@ -410,7 +439,9 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske, silc_free(x); silc_mp_uninit(&payload->x); silc_free(payload->pk_data); + silc_free(payload->sign_data); silc_free(payload); + ske->ke1_payload = NULL; ske->status = status; return status; } @@ -470,6 +501,7 @@ static void silc_ske_initiator_finish_final(SilcSKE ske, 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; @@ -492,9 +524,7 @@ static void silc_ske_initiator_finish_final(SilcSKE ske, silc_pkcs_public_key_set(ske->prop->pkcs, public_key); 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_LOG_ERROR(("Signature verification failed, incorrect signature")); status = SILC_SKE_STATUS_INCORRECT_SIGNATURE; goto err; } @@ -669,6 +699,13 @@ SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng, 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)) { + 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, @@ -830,6 +867,7 @@ static void silc_ske_responder_phase2_final(SilcSKE ske, recv_payload->pk_len, &public_key)) { ske->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; @@ -852,9 +890,7 @@ 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) { - - SILC_LOG_DEBUG(("Signature don't match")); - + 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); @@ -945,7 +981,7 @@ SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske, SILC_LOG_DEBUG(("We are doing mutual authentication")); if (!recv_payload->pk_data && ske->callbacks->verify_key) { - SILC_LOG_DEBUG(("Remote end did not send its public key (or " + 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; @@ -986,7 +1022,7 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske, SilcSKEStatus status = SILC_SKE_STATUS_OK; SilcBuffer payload_buf; SilcMPInt *KEY; - unsigned char hash[32], sign[1024], *pk; + unsigned char hash[32], sign[2048 + 1], *pk; SilcUInt32 hash_len, sign_len, pk_len; SILC_LOG_DEBUG(("Start")); @@ -1006,7 +1042,7 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske, /* Get the public key */ pk = silc_pkcs_public_key_encode(public_key, &pk_len); if (!pk) { - status = SILC_SKE_STATUS_ERROR; + status = SILC_SKE_STATUS_OUT_OF_MEMORY; goto err; } ske->ke2_payload->pk_data = pk; @@ -1029,7 +1065,11 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske, /* 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); + 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)) { + status = SILC_SKE_STATUS_SIGNATURE_ERROR; + goto err; + } 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)); @@ -1076,8 +1116,9 @@ SilcSKEStatus silc_ske_end(SilcSKE ske) SILC_LOG_DEBUG(("Start")); - packet = silc_buffer_alloc(4); - silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); + packet = silc_buffer_alloc_size(4); + if (!packet) + return SILC_SKE_STATUS_OUT_OF_MEMORY; silc_buffer_format(packet, SILC_STR_UI_INT((SilcUInt32)SILC_SKE_STATUS_OK), SILC_STR_END); @@ -1104,8 +1145,9 @@ SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status) if (status > SILC_SKE_STATUS_INVALID_COOKIE) status = SILC_SKE_STATUS_BAD_PAYLOAD; - packet = silc_buffer_alloc(4); - silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); + packet = silc_buffer_alloc_size(4); + if (!packet) + return SILC_SKE_STATUS_OUT_OF_MEMORY; silc_buffer_format(packet, SILC_STR_UI_INT((SilcUInt32)status), SILC_STR_END); @@ -1145,7 +1187,7 @@ silc_ske_assemble_security_properties(SilcSKE ske, /* 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[i] = silc_rng_get_byte_fast(ske->rng); rp->cookie_len = SILC_SKE_COOKIE_LEN; /* Put version */ @@ -1174,8 +1216,8 @@ silc_ske_assemble_security_properties(SilcSKE ske, /* XXX */ /* Get supported compression algorithms */ - rp->comp_alg_list = strdup(""); - rp->comp_alg_len = 0; + 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 + @@ -1501,9 +1543,8 @@ silc_ske_select_security_properties(SilcSKE ske, payload->hmac_alg_list = strdup(rp->hmac_alg_list); } -#if 0 /* Get supported compression algorithms */ - cp = rp->hash_alg_list; + cp = rp->comp_alg_list; if (cp && strchr(cp, ',')) { while(cp) { char *item; @@ -1512,15 +1553,23 @@ silc_ske_select_security_properties(SilcSKE ske, item = silc_calloc(len + 1, sizeof(char)); memcpy(item, cp, len); - SILC_LOG_DEBUG(("Proposed hash alg `%s'", item)); + SILC_LOG_DEBUG(("Proposed Compression `%s'", item)); - if (silc_hash_is_supported(item) == TRUE) { - SILC_LOG_DEBUG(("Found hash alg `%s'", item)); - - payload->hash_alg_len = len; - payload->hash_alg_list = item; +#if 1 + if (!strcmp(item, "none")) { + SILC_LOG_DEBUG(("Found Compression `%s'", item)); + payload->comp_alg_len = len; + payload->comp_alg_list = item; + break; + } +#else + if (silc_hmac_is_supported(item) == TRUE) { + SILC_LOG_DEBUG(("Found Compression `%s'", item)); + payload->comp_alg_len = len; + payload->comp_alg_list = item; break; } +#endif cp += len; if (strlen(cp) == 0) @@ -1531,20 +1580,7 @@ silc_ske_select_security_properties(SilcSKE ske, if (item) silc_free(item); } - - if (!payload->hash_alg_len && !payload->hash_alg_list) { - SILC_LOG_DEBUG(("Could not find supported hash alg")); - silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION); - silc_free(payload->ke_grp_list); - silc_free(payload->pkcs_alg_list); - silc_free(payload->enc_alg_list); - silc_free(payload); - return; - } - } else { - } -#endif payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 2 + payload->version_len + @@ -1564,26 +1600,31 @@ static SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n, { SilcSKEStatus status = SILC_SKE_STATUS_OK; unsigned char *string; + SilcUInt32 l; + + if (!len) + return SILC_SKE_STATUS_ERROR; SILC_LOG_DEBUG(("Creating random number")); + l = ((len - 1) / 8); + /* Get the random number as string */ - string = silc_rng_get_rn_data(ske->rng, (len / 8)); + string = silc_rng_get_rn_data(ske->rng, l); if (!string) - return SILC_SKE_STATUS_ERROR; + return SILC_SKE_STATUS_OUT_OF_MEMORY; /* Decode the string into a MP integer */ - silc_mp_bin2mp(string, (len / 8), rnd); + silc_mp_bin2mp(string, l, rnd); silc_mp_mod_2exp(rnd, rnd, len); /* Checks */ if (silc_mp_cmp_ui(rnd, 1) < 0) status = SILC_SKE_STATUS_ERROR; - if (silc_mp_cmp(rnd, n) >= 0) status = SILC_SKE_STATUS_ERROR; - memset(string, 'F', (len / 8)); + memset(string, 'F', l); silc_free(string); return status; @@ -1613,11 +1654,12 @@ 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(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)); + buf = silc_buffer_alloc_size(ske->start_payload_copy->len + + ske->ke2_payload->pk_len + + ske->ke1_payload->pk_len + + e_len + f_len + KEY_len); + if (!buf) + return SILC_SKE_STATUS_OUT_OF_MEMORY; /* Initiator is not required to send its public key */ if (!ske->ke1_payload->pk_data) { @@ -1669,9 +1711,10 @@ static SilcSKEStatus silc_ske_make_hash(SilcSKE ske, } else { e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len); - buf = silc_buffer_alloc(ske->start_payload_copy->len + - ske->ke1_payload->pk_len + e_len); - silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf)); + buf = silc_buffer_alloc_size(ske->start_payload_copy->len + + ske->ke1_payload->pk_len + e_len); + if (!buf) + return SILC_SKE_STATUS_OUT_OF_MEMORY; /* Format the buffer used to compute the hash value */ ret = @@ -1730,8 +1773,9 @@ silc_ske_process_key_material_data(unsigned char *data, if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len) return SILC_SKE_STATUS_ERROR; - buf = silc_buffer_alloc(1 + data_len); - silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf)); + buf = silc_buffer_alloc_size(1 + data_len); + if (!buf) + return SILC_SKE_STATUS_OUT_OF_MEMORY; silc_buffer_format(buf, SILC_STR_UI_CHAR(0), SILC_STR_UI_XNSTRING(data, data_len), @@ -1768,8 +1812,9 @@ silc_ske_process_key_material_data(unsigned char *data, silc_hash_make(hash, buf->data, buf->len, k1); /* Take second round */ - dist = silc_buffer_alloc(data_len + hash_len); - silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist)); + dist = silc_buffer_alloc_size(data_len + hash_len); + if (!dist) + return SILC_SKE_STATUS_OUT_OF_MEMORY; silc_buffer_format(dist, SILC_STR_UI_XNSTRING(data, data_len), SILC_STR_UI_XNSTRING(k1, hash_len), @@ -1803,6 +1848,7 @@ silc_ske_process_key_material_data(unsigned char *data, memset(k2, 0, sizeof(k2)); memset(k3, 0, sizeof(k3)); silc_free(dtmp); + silc_buffer_clear(dist); silc_buffer_free(dist); } else { /* Take normal hash as key */ @@ -1828,8 +1874,9 @@ silc_ske_process_key_material_data(unsigned char *data, silc_hash_make(hash, buf->data, buf->len, k1); /* Take second round */ - dist = silc_buffer_alloc(data_len + hash_len); - silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist)); + dist = silc_buffer_alloc_size(data_len + hash_len); + if (!dist) + return SILC_SKE_STATUS_OUT_OF_MEMORY; silc_buffer_format(dist, SILC_STR_UI_XNSTRING(data, data_len), SILC_STR_UI_XNSTRING(k1, hash_len), @@ -1863,6 +1910,7 @@ silc_ske_process_key_material_data(unsigned char *data, memset(k2, 0, sizeof(k2)); memset(k3, 0, sizeof(k3)); silc_free(dtmp); + silc_buffer_clear(dist); silc_buffer_free(dist); } else { /* Take normal hash as key */ @@ -1887,6 +1935,7 @@ silc_ske_process_key_material_data(unsigned char *data, key->hmac_key_len = req_hmac_key_len; memset(hashd, 0, sizeof(hashd)); + silc_buffer_clear(buf); silc_buffer_free(buf); return SILC_SKE_STATUS_OK; @@ -1909,8 +1958,9 @@ SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, /* 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)); + buf = silc_buffer_alloc_size(klen + ske->hash_len); + if (!buf) + return SILC_SKE_STATUS_OUT_OF_MEMORY; silc_buffer_format(buf, SILC_STR_UI_XNSTRING(tmpbuf, klen), SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len), @@ -1924,6 +1974,7 @@ SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, memset(tmpbuf, 0, klen); silc_free(tmpbuf); + silc_buffer_clear(buf); silc_buffer_free(buf); return status; @@ -1981,7 +2032,8 @@ const char *silc_ske_status_string[] = "Key exchange protocol is not active", "Bad reserved field in packet", "Bad payload length in packet", - "Incorrect hash", + "Error computing signature", + "System out of memory", NULL };