X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccore%2Fsilcchannel.c;h=ae6ac4be73493973807189e916b875809ddc6176;hb=a818c5b5411bbc4436d1c5f011236985c96bb787;hp=5d1dd7d9261359662ba18f8578898a1c1ad37455;hpb=8c17815e64768f58f3b867dfa45ddc544b9822de;p=silc.git diff --git a/lib/silccore/silcchannel.c b/lib/silccore/silcchannel.c index 5d1dd7d9..ae6ac4be 100644 --- a/lib/silccore/silcchannel.c +++ b/lib/silccore/silcchannel.c @@ -33,26 +33,29 @@ /* Channel Message Payload structure. Contents of this structure is parsed from SILC packets. */ struct SilcChannelPayloadStruct { - unsigned short name_len; + SilcUInt16 name_len; unsigned char *channel_name; - unsigned short id_len; + SilcUInt16 id_len; unsigned char *channel_id; - unsigned int mode; + SilcUInt32 mode; }; /* Parses channel payload returning new channel payload structure. */ -SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer) +SilcChannelPayload silc_channel_payload_parse(const unsigned char *payload, + SilcUInt32 payload_len) { + SilcBufferStruct buffer; SilcChannelPayload new; int ret; SILC_LOG_DEBUG(("Parsing channel payload")); + silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); new = silc_calloc(1, sizeof(*new)); /* Parse the Channel Payload. Ignore the padding. */ - ret = silc_buffer_unformat(buffer, + ret = silc_buffer_unformat(&buffer, SILC_STR_UI16_NSTRING_ALLOC(&new->channel_name, &new->name_len), SILC_STR_UI16_NSTRING_ALLOC(&new->channel_id, @@ -62,8 +65,8 @@ SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer) if (ret == -1) goto err; - if ((new->name_len < 1 || new->name_len > buffer->len) || - (new->id_len < 1 || new->id_len > buffer->len)) { + if ((new->name_len < 1 || new->name_len > buffer.len) || + (new->id_len < 1 || new->id_len > buffer.len)) { SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped")); goto err; } @@ -77,19 +80,22 @@ SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer) /* Parses list of channel payloads returning list of payloads. */ -SilcDList silc_channel_payload_parse_list(SilcBuffer buffer) +SilcDList silc_channel_payload_parse_list(const unsigned char *payload, + SilcUInt32 payload_len) { + SilcBufferStruct buffer; SilcDList list; SilcChannelPayload new; int len, ret; SILC_LOG_DEBUG(("Parsing channel payload list")); + silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); list = silc_dlist_init(); - while (buffer->len) { + while (buffer.len) { new = silc_calloc(1, sizeof(*new)); - ret = silc_buffer_unformat(buffer, + ret = silc_buffer_unformat(&buffer, SILC_STR_UI16_NSTRING_ALLOC(&new->channel_name, &new->name_len), SILC_STR_UI16_NSTRING_ALLOC(&new->channel_id, @@ -99,16 +105,16 @@ SilcDList silc_channel_payload_parse_list(SilcBuffer buffer) if (ret == -1) goto err; - if ((new->name_len < 1 || new->name_len > buffer->len) || - (new->id_len < 1 || new->id_len > buffer->len)) { + if ((new->name_len < 1 || new->name_len > buffer.len) || + (new->id_len < 1 || new->id_len > buffer.len)) { SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped")); goto err; } len = 2 + new->name_len + 2 + new->id_len + 4; - if (buffer->len < len) + if (buffer.len < len) break; - silc_buffer_pull(buffer, len); + silc_buffer_pull(&buffer, len); silc_dlist_add(list, new); } @@ -122,11 +128,11 @@ SilcDList silc_channel_payload_parse_list(SilcBuffer buffer) /* Encode new channel payload and returns it as buffer. */ -SilcBuffer silc_channel_payload_encode(unsigned char *channel_name, - unsigned short channel_name_len, - unsigned char *channel_id, - unsigned int channel_id_len, - unsigned int mode) +SilcBuffer silc_channel_payload_encode(const unsigned char *channel_name, + SilcUInt16 channel_name_len, + const unsigned char *channel_id, + SilcUInt32 channel_id_len, + SilcUInt32 mode) { SilcBuffer buffer; @@ -147,7 +153,7 @@ SilcBuffer silc_channel_payload_encode(unsigned char *channel_name, return buffer; } -/* Free's Channel Payload */ +/* Frees Channel Payload */ void silc_channel_payload_free(SilcChannelPayload payload) { @@ -166,8 +172,8 @@ void silc_channel_payload_list_free(SilcDList list) while ((entry = silc_dlist_get(list)) != SILC_LIST_END) { silc_free(entry->channel_name); silc_free(entry->channel_id); - silc_free(entry); silc_dlist_del(list, entry); + silc_free(entry); } silc_dlist_uninit(list); @@ -176,7 +182,7 @@ void silc_channel_payload_list_free(SilcDList list) /* Return the channel name */ unsigned char *silc_channel_get_name(SilcChannelPayload payload, - unsigned int *channel_name_len) + SilcUInt32 *channel_name_len) { if (channel_name_len) *channel_name_len = payload->name_len; @@ -187,7 +193,7 @@ unsigned char *silc_channel_get_name(SilcChannelPayload payload, /* Return the channel ID */ unsigned char *silc_channel_get_id(SilcChannelPayload payload, - unsigned int *channel_id_len) + SilcUInt32 *channel_id_len) { if (channel_id_len) *channel_id_len = payload->id_len; @@ -207,7 +213,7 @@ SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload) channel or perhaps the mode of the client on the channel. The protocol dictates what the usage of the mode is in different circumstances. */ -unsigned int silc_channel_get_mode(SilcChannelPayload payload) +SilcUInt32 silc_channel_get_mode(SilcChannelPayload payload) { return payload->mode; } @@ -218,52 +224,71 @@ unsigned int silc_channel_get_mode(SilcChannelPayload payload) ******************************************************************************/ +#define SILC_CHANNEL_MESSAGE_PAD(__payloadlen) (16 - (__payloadlen) % 16) + /* Channel Message Payload structure. Contents of this structure is parsed from SILC packets. */ struct SilcChannelMessagePayloadStruct { - unsigned short flags; - unsigned short data_len; + SilcMessageFlags flags; + SilcUInt16 data_len; unsigned char *data; unsigned char *mac; unsigned char *iv; }; -/* Decrypts the channel message payload. */ +/* Decrypts the channel message payload. First push the IV out of the + packet. The IV is used in the decryption process. Then decrypt the + message. After decyprtion, take the MAC from the decrypted packet, + compute MAC and compare the MACs. If they match, the decryption was + successful and we have the channel message ready to be displayed. */ -int silc_channel_message_payload_decrypt(unsigned char *data, - size_t data_len, - SilcCipher cipher, - SilcHmac hmac) +bool silc_channel_message_payload_decrypt(unsigned char *data, + size_t data_len, + SilcCipher cipher, + SilcHmac hmac) { - unsigned int iv_len, mac_len; + SilcUInt32 iv_len, mac_len; unsigned char *end, *mac, mac2[32]; + unsigned char *dst, iv[SILC_CIPHER_MAX_IV_SIZE]; - /* Decrypt the channel message. First push the IV out of the packet. - The IV is used in the decryption process. Then decrypt the message. - After decyprtion, take the MAC from the decrypted packet, compute MAC - and compare the MACs. If they match, the decryption was successfull - and we have the channel message ready to be displayed. */ + /* Push the IV out of the packet, and copy the IV since we do not want + to modify the original data buffer. */ end = data + data_len; - - /* Push the IV out of the packet */ iv_len = silc_cipher_get_block_len(cipher); + memcpy(iv, end - iv_len, iv_len); + + /* Allocate destination decryption buffer since we do not want to modify + the original data buffer, since we might want to call this function + many times for same payload. */ + if (hmac) + dst = silc_calloc(data_len - iv_len, sizeof(*dst)); + else + dst = data; /* Decrypt the channel message */ - silc_cipher_decrypt(cipher, data, data, data_len - iv_len, (end - iv_len)); + silc_cipher_decrypt(cipher, data, dst, data_len - iv_len, iv); - /* Take the MAC */ if (hmac) { + /* Take the MAC */ + end = dst + (data_len - iv_len); mac_len = silc_hmac_len(hmac); - mac = (end - iv_len - mac_len); + mac = (end - mac_len); /* Check the MAC of the message */ SILC_LOG_DEBUG(("Checking channel message MACs")); - silc_hmac_make(hmac, data, (data_len - iv_len - mac_len), mac2, &mac_len); + silc_hmac_make(hmac, dst, (data_len - iv_len - mac_len), mac2, &mac_len); if (memcmp(mac, mac2, mac_len)) { SILC_LOG_DEBUG(("Channel message MACs does not match")); + silc_free(dst); return FALSE; } SILC_LOG_DEBUG(("MAC is Ok")); + + /* Now copy the decrypted data into the buffer since it is verified + it decrypted correctly. */ + memcpy(data, dst, data_len - iv_len); + memset(dst, 0, data_len - iv_len); + silc_free(dst); } return TRUE; @@ -273,19 +298,23 @@ int silc_channel_message_payload_decrypt(unsigned char *data, This also decrypts it and checks the MAC. */ SilcChannelMessagePayload -silc_channel_message_payload_parse(SilcBuffer buffer, +silc_channel_message_payload_parse(unsigned char *payload, + SilcUInt32 payload_len, SilcCipher cipher, SilcHmac hmac) { + SilcBufferStruct buffer; SilcChannelMessagePayload new; int ret; - unsigned int iv_len, mac_len; + SilcUInt32 iv_len, mac_len; SILC_LOG_DEBUG(("Parsing channel message payload")); + silc_buffer_set(&buffer, payload, payload_len); + /* Decrypt the payload */ - ret = silc_channel_message_payload_decrypt(buffer->data, buffer->len, - cipher, hmac); + ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len, + cipher, hmac); if (ret == FALSE) return NULL; @@ -295,7 +324,7 @@ silc_channel_message_payload_parse(SilcBuffer buffer, new = silc_calloc(1, sizeof(*new)); /* Parse the Channel Message Payload. Ignore the padding. */ - ret = silc_buffer_unformat(buffer, + ret = silc_buffer_unformat(&buffer, SILC_STR_UI_SHORT(&new->flags), SILC_STR_UI16_NSTRING_ALLOC(&new->data, &new->data_len), @@ -306,8 +335,8 @@ silc_channel_message_payload_parse(SilcBuffer buffer, if (ret == -1) goto err; - if (new->data_len < 1 || new->data_len > buffer->len) { - SILC_LOG_ERROR(("Incorrect channel messaeg payload in packet, " + if (new->data_len > buffer.len) { + SILC_LOG_ERROR(("Incorrect channel message payload in packet, " "packet dropped")); goto err; } @@ -324,18 +353,18 @@ silc_channel_message_payload_parse(SilcBuffer buffer, encrypted separately from other parts of the packet padding must be applied to the payload. */ -SilcBuffer silc_channel_message_payload_encode(unsigned short flags, - unsigned short data_len, - unsigned char *data, - unsigned short iv_len, +SilcBuffer silc_channel_message_payload_encode(SilcUInt16 flags, + SilcUInt16 data_len, + const unsigned char *data, + SilcUInt16 iv_len, unsigned char *iv, SilcCipher cipher, SilcHmac hmac) { int i; SilcBuffer buffer; - unsigned int len, pad_len, mac_len; - unsigned char pad[SILC_PACKET_MAX_PADLEN]; + SilcUInt32 len, pad_len, mac_len; + unsigned char pad[16]; unsigned char mac[32]; SILC_LOG_DEBUG(("Encoding channel message payload")); @@ -344,7 +373,7 @@ SilcBuffer silc_channel_message_payload_encode(unsigned short flags, since it is not encrypted. */ mac_len = silc_hmac_len(hmac); len = 6 + data_len + mac_len; - pad_len = SILC_PACKET_PADLEN((len + 2)); + pad_len = SILC_CHANNEL_MESSAGE_PAD(len); /* Allocate channel payload buffer */ len += pad_len + iv_len; @@ -396,10 +425,18 @@ void silc_channel_message_payload_free(SilcChannelMessagePayload payload) silc_free(payload); } +/* Return flags */ + +SilcMessageFlags +silc_channel_message_get_flags(SilcChannelMessagePayload payload) +{ + return payload->flags; +} + /* Return data */ unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload, - unsigned int *data_len) + SilcUInt32 *data_len) { if (data_len) *data_len = payload->data_len; @@ -409,7 +446,7 @@ unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload, /* Return MAC. The caller knows the length of the MAC */ -unsigned char *silc_channel_mesage_get_mac(SilcChannelMessagePayload payload) +unsigned char *silc_channel_message_get_mac(SilcChannelMessagePayload payload) { return payload->mac; } @@ -430,28 +467,32 @@ unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload) /* Channel Key Payload structrue. Channel keys are parsed from SILC packets into this structure. */ struct SilcChannelKeyPayloadStruct { - unsigned short id_len; + SilcUInt16 id_len; unsigned char *id; - unsigned short cipher_len; + SilcUInt16 cipher_len; unsigned char *cipher; - unsigned short key_len; + SilcUInt16 key_len; unsigned char *key; }; /* Parses channel key payload returning new channel key payload structure */ -SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer) +SilcChannelKeyPayload +silc_channel_key_payload_parse(const unsigned char *payload, + SilcUInt32 payload_len) { + SilcBufferStruct buffer; SilcChannelKeyPayload new; int ret; SILC_LOG_DEBUG(("Parsing channel key payload")); + silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); new = silc_calloc(1, sizeof(*new)); /* Parse the Channel Key Payload */ ret = - silc_buffer_unformat(buffer, + silc_buffer_unformat(&buffer, SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len), SILC_STR_UI16_NSTRING_ALLOC(&new->cipher, &new->cipher_len), @@ -481,15 +522,15 @@ SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer) /* Encodes channel key payload into a buffer and returns it. This is used to add channel key payload into a packet. */ -SilcBuffer silc_channel_key_payload_encode(unsigned short id_len, - unsigned char *id, - unsigned short cipher_len, - unsigned char *cipher, - unsigned short key_len, - unsigned char *key) +SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len, + const unsigned char *id, + SilcUInt16 cipher_len, + const unsigned char *cipher, + SilcUInt16 key_len, + const unsigned char *key) { SilcBuffer buffer; - unsigned int len; + SilcUInt32 len; SILC_LOG_DEBUG(("Encoding channel key payload")); @@ -513,15 +554,13 @@ SilcBuffer silc_channel_key_payload_encode(unsigned short id_len, return buffer; } -/* Free's Channel Key Payload */ +/* Frees Channel Key Payload */ void silc_channel_key_payload_free(SilcChannelKeyPayload payload) { if (payload) { - if (payload->id) - silc_free(payload->id); - if (payload->cipher) - silc_free(payload->cipher); + silc_free(payload->id); + silc_free(payload->cipher); if (payload->key) { memset(payload->key, 0, payload->key_len); silc_free(payload->key); @@ -533,7 +572,7 @@ void silc_channel_key_payload_free(SilcChannelKeyPayload payload) /* Return ID */ unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, - unsigned int *id_len) + SilcUInt32 *id_len) { if (id_len) *id_len = payload->id_len; @@ -544,7 +583,7 @@ unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, /* Return cipher name */ unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload, - unsigned int *cipher_len) + SilcUInt32 *cipher_len) { if (cipher_len) *cipher_len = payload->cipher_len; @@ -555,7 +594,7 @@ unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload, /* Return key */ unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload, - unsigned int *key_len) + SilcUInt32 *key_len) { if (key_len) *key_len = payload->key_len;