From 1e4e7d57f414a337e084df4072a2690f0c9b71c6 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Tue, 16 Oct 2001 22:06:51 +0000 Subject: [PATCH] updates. --- CHANGES | 18 ++ apps/silcd/idlist.c | 4 +- apps/silcd/packet_receive.c | 15 +- apps/silcd/packet_send.c | 119 ++++++---- apps/silcd/packet_send.h | 2 + apps/silcd/protocol.c | 77 +++++-- apps/silcd/server.c | 80 ++----- apps/silcd/server.h | 3 +- apps/silcd/server_backup.c | 2 +- doc/draft-riikonen-silc-pp-04.nroff | 47 ++-- lib/silcclient/client.c | 88 +++---- lib/silcclient/client.h | 2 + lib/silcclient/client_channel.c | 10 +- lib/silcclient/client_prvmsg.c | 9 +- lib/silcclient/protocol.c | 45 ++-- lib/silccore/silcchannel.c | 5 +- lib/silccore/silcpacket.c | 344 +++++++++++++++++++--------- lib/silccore/silcpacket.h | 149 +++++------- lib/silccore/silcprivate.c | 5 +- lib/silccrypt/silccipher.h | 4 + lib/silccrypt/silchmac.c | 14 ++ lib/silccrypt/silchmac.h | 3 + lib/silcske/silcske.c | 30 ++- lib/silcske/silcske.h | 6 +- 24 files changed, 616 insertions(+), 465 deletions(-) diff --git a/CHANGES b/CHANGES index 25649f7f..427f1110 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,21 @@ +Tue Oct 16 20:45:49 EDT 2001 Pekka Riikonen + + * Changed the SILC packet header to have the first two bytes + (the packet length) encrypted. Affected files aroung the + code tree, lib/silccore/silcpacket.[ch]. Removed the + SilcPacketCheckDecrypt callback. It is not needed anymore + since the silc_packet_receive_process will determine now + whether the packet is normal or special. + + * Implemented the unidirectional MAC keys. Affected files + lib/silcske/silcske.c, silcd/protocol.c and + lib/silcclient/protocol.c. + + * Implemented the packet sequence number to the MAC computation. + Affected files lib/silccore/silcpacket.c, silcd/protocol.c, + silcd/packet_send.c, silcd/server.c, lib/silcclient/client.c, + lib/silcclient/protocol.c. + Mon Oct 15 17:42:55 EDT 2001 Pekka Riikonen * Allow backup router to announce servers. All servers diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index 527b49ea..4a72bcb9 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -66,8 +66,10 @@ void silc_idlist_del_data(void *entry) } silc_free(idata->rekey); } - if (idata->hmac_send) /* Same as idata->hmac_receive */ + if (idata->hmac_send) silc_hmac_free(idata->hmac_send); + if (idata->hmac_receive) + silc_hmac_free(idata->hmac_receive); if (idata->public_key) silc_pkcs_public_key_free(idata->public_key); } diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 983d44f3..5c73655e 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -71,7 +71,8 @@ void silc_server_notify(SilcServer server, if (dst_sock) /* Relay the packet */ silc_server_relay_packet(server, dst_sock, idata->send_key, - idata->hmac_receive, packet, TRUE); + idata->hmac_receive, idata->psn_send++, + packet, TRUE); } /* Parse the Notify Payload */ @@ -1161,7 +1162,8 @@ void silc_server_private_message(SilcServer server, /* Send the private message */ silc_server_send_private_message(server, dst_sock, idata->send_key, - idata->hmac_send, packet); + idata->hmac_send, idata->psn_send++, + packet); } /* Received private message key packet.. This packet is never for us. It is to @@ -1193,7 +1195,7 @@ void silc_server_private_message_key(SilcServer server, /* Relay the packet */ silc_server_relay_packet(server, dst_sock, idata->send_key, - idata->hmac_send, packet, FALSE); + idata->hmac_send, idata->psn_send++, packet, FALSE); } /* Processes incoming command reply packet. The command reply packet may @@ -1257,8 +1259,8 @@ void silc_server_command_reply(SilcServer server, idata = (SilcIDListData)client; /* Encrypt packet */ - silc_packet_encrypt(idata->send_key, idata->hmac_send, dst_sock->outbuf, - buffer->len); + silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++, + dst_sock->outbuf, buffer->len); /* Send the packet */ silc_server_packet_send_real(server, dst_sock, TRUE); @@ -2344,7 +2346,8 @@ void silc_server_key_agreement(SilcServer server, /* Relay the packet */ silc_server_relay_packet(server, dst_sock, idata->send_key, - idata->hmac_send, packet, FALSE); + idata->hmac_send, idata->psn_send++, + packet, FALSE); } /* Received connection auth request packet that is used during connection diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index a7349360..81305e72 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -140,8 +140,10 @@ void silc_server_packet_send_dest(SilcServer server, SilcIDListData idata = (SilcIDListData)sock->user_data; SilcCipher cipher = NULL; SilcHmac hmac = NULL; + uint32 sequence = 0; unsigned char *dst_id_data = NULL; uint32 dst_id_len = 0; + int block_len = 0; /* If disconnecting, ignore the data */ if (SILC_IS_DISCONNECTING(sock)) @@ -158,6 +160,13 @@ void silc_server_packet_send_dest(SilcServer server, dst_id_len = silc_id_get_len(dst_id, dst_id_type); } + if (idata) { + cipher = idata->send_key; + hmac = idata->hmac_send; + sequence = idata->psn_send++; + block_len = silc_cipher_get_block_len(cipher); + } + /* Set the packet context pointers */ packetdata.type = type; packetdata.flags = flags; @@ -169,7 +178,7 @@ void silc_server_packet_send_dest(SilcServer server, packetdata.dst_id_type = dst_id_type; packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + packetdata.src_id_len + dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen); + packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len); /* Prepare outgoing data buffer for packet sending */ silc_packet_send_prepare(sock, @@ -188,17 +197,13 @@ void silc_server_packet_send_dest(SilcServer server, silc_buffer_put(sock->outbuf, data, data_len); /* Create the outgoing packet */ - silc_packet_assemble(&packetdata); - - if (idata) { - cipher = idata->send_key; - hmac = idata->hmac_send; - } + silc_packet_assemble(&packetdata, cipher); /* Encrypt the packet */ - silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len); + silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, sock->outbuf->len); - SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len), + SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence, + sock->outbuf->len), sock->outbuf->data, sock->outbuf->len); /* Now actually send the packet */ @@ -234,10 +239,12 @@ void silc_server_packet_send_srcdest(SilcServer server, SilcIDListData idata; SilcCipher cipher = NULL; SilcHmac hmac = NULL; + uint32 sequence = 0; unsigned char *dst_id_data = NULL; uint32 dst_id_len = 0; unsigned char *src_id_data = NULL; uint32 src_id_len = 0; + int block_len = 0; SILC_LOG_DEBUG(("Sending packet, type %d", type)); @@ -254,6 +261,13 @@ void silc_server_packet_send_srcdest(SilcServer server, src_id_len = silc_id_get_len(src_id, src_id_type); } + if (idata) { + cipher = idata->send_key; + hmac = idata->hmac_send; + sequence = idata->psn_send++; + block_len = silc_cipher_get_block_len(cipher); + } + /* Set the packet context pointers */ packetdata.type = type; packetdata.flags = flags; @@ -265,7 +279,7 @@ void silc_server_packet_send_srcdest(SilcServer server, packetdata.dst_id_type = dst_id_type; packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + packetdata.src_id_len + dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen); + packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len); /* Prepare outgoing data buffer for packet sending */ silc_packet_send_prepare(sock, @@ -284,17 +298,13 @@ void silc_server_packet_send_srcdest(SilcServer server, silc_buffer_put(sock->outbuf, data, data_len); /* Create the outgoing packet */ - silc_packet_assemble(&packetdata); - - if (idata) { - cipher = idata->send_key; - hmac = idata->hmac_send; - } + silc_packet_assemble(&packetdata, cipher); /* Encrypt the packet */ - silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len); + silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, sock->outbuf->len); - SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len), + SILC_LOG_HEXDUMP(("Outgoing packet (%d), len %d", sequence, + sock->outbuf->len), sock->outbuf->data, sock->outbuf->len); /* Now actually send the packet */ @@ -330,10 +340,11 @@ void silc_server_packet_broadcast(SilcServer server, silc_buffer_push(buffer, buffer->data - buffer->head); silc_packet_send_prepare(sock, 0, 0, buffer->len); silc_buffer_put(sock->outbuf, buffer->data, buffer->len); - silc_packet_encrypt(idata->send_key, idata->hmac_send, + silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++, sock->outbuf, sock->outbuf->len); - SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len), + SILC_LOG_HEXDUMP(("Broadcasted packet (%d), len %d", idata->psn_send - 1, + sock->outbuf->len), sock->outbuf->data, sock->outbuf->len); /* Now actually send the packet */ @@ -364,10 +375,11 @@ void silc_server_packet_route(SilcServer server, silc_buffer_push(buffer, buffer->data - buffer->head); silc_packet_send_prepare(sock, 0, 0, buffer->len); silc_buffer_put(sock->outbuf, buffer->data, buffer->len); - silc_packet_encrypt(idata->send_key, idata->hmac_send, + silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++, sock->outbuf, sock->outbuf->len); - SILC_LOG_HEXDUMP(("Routed packet, len %d", sock->outbuf->len), + SILC_LOG_HEXDUMP(("Routed packet (%d), len %d", idata->psn_send - 1, + sock->outbuf->len), sock->outbuf->data, sock->outbuf->len); /* Now actually send the packet */ @@ -385,14 +397,27 @@ silc_server_packet_send_to_channel_real(SilcServer server, SilcPacketContext *packet, SilcCipher cipher, SilcHmac hmac, + uint32 sequence, unsigned char *data, uint32 data_len, - int channel_message, + bool channel_message, bool force_send) { + int block_len = 0; packet->truelen = data_len + SILC_PACKET_HEADER_LEN + packet->src_id_len + packet->dst_id_len; + if (cipher) { + block_len = silc_cipher_get_block_len(cipher); + + if (channel_message) + packet->padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + + packet->src_id_len + + packet->dst_id_len), block_len); + else + packet->padlen = SILC_PACKET_PADLEN(packet->truelen, block_len); + } + /* Prepare outgoing data buffer for packet sending */ silc_packet_send_prepare(sock, SILC_PACKET_HEADER_LEN + @@ -407,15 +432,17 @@ silc_server_packet_send_to_channel_real(SilcServer server, is encrypted with normal session key shared with the client, unless the `channel_message' is TRUE. */ silc_buffer_put(sock->outbuf, data, data_len); - silc_packet_assemble(packet); + silc_packet_assemble(packet, cipher); if (channel_message) - silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + - packet->src_id_len + packet->dst_id_len + - packet->padlen); + silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, + SILC_PACKET_HEADER_LEN + packet->src_id_len + + packet->dst_id_len + packet->padlen); else - silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len); + silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, + sock->outbuf->len); - SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len), + SILC_LOG_HEXDUMP(("Channel packet (%d), len %d", sequence, + sock->outbuf->len), sock->outbuf->data, sock->outbuf->len); /* Now actually send the packet */ @@ -465,9 +492,6 @@ void silc_server_packet_send_to_channel(SilcServer server, packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL); packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL); packetdata.dst_id_type = SILC_ID_CHANNEL; - packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + - packetdata.src_id_len + packetdata.dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen); /* If there are global users in the channel we will send the message first to our router for further routing. */ @@ -486,6 +510,7 @@ void silc_server_packet_send_to_channel(SilcServer server, silc_server_packet_send_to_channel_real(server, sock, &packetdata, idata->send_key, idata->hmac_send, + idata->psn_send++, data, data_len, FALSE, force_send); } @@ -532,6 +557,7 @@ void silc_server_packet_send_to_channel(SilcServer server, silc_server_packet_send_to_channel_real(server, sock, &packetdata, idata->send_key, idata->hmac_send, + idata->psn_send++, data, data_len, FALSE, force_send); @@ -556,6 +582,7 @@ void silc_server_packet_send_to_channel(SilcServer server, silc_server_packet_send_to_channel_real(server, sock, &packetdata, idata->send_key, idata->hmac_send, + idata->psn_send++, data, data_len, FALSE, force_send); } @@ -667,9 +694,6 @@ void silc_server_packet_relay_to_channel(SilcServer server, packetdata.dst_id = silc_id_id2str(channel->id, SILC_ID_CHANNEL); packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL); packetdata.dst_id_type = SILC_ID_CHANNEL; - packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + - packetdata.src_id_len + - packetdata.dst_id_len)); /* If there are global users in the channel we will send the message first to our router for further routing. */ @@ -689,6 +713,7 @@ void silc_server_packet_relay_to_channel(SilcServer server, silc_server_packet_send_to_channel_real(server, sock, &packetdata, idata->send_key, idata->hmac_send, + idata->psn_send++, data, data_len, TRUE, force_send); } @@ -814,6 +839,7 @@ void silc_server_packet_relay_to_channel(SilcServer server, silc_server_packet_send_to_channel_real(server, sock, &packetdata, idata->send_key, idata->hmac_send, + idata->psn_send++, data, data_len, TRUE, force_send); @@ -838,6 +864,7 @@ void silc_server_packet_relay_to_channel(SilcServer server, silc_server_packet_send_to_channel_real(server, sock, &packetdata, idata->send_key, idata->hmac_send, + idata->psn_send++, data, data_len, TRUE, force_send); } @@ -892,6 +919,7 @@ void silc_server_send_private_message(SilcServer server, SilcSocketConnection dst_sock, SilcCipher cipher, SilcHmac hmac, + uint32 sequence, SilcPacketContext *packet) { SilcBuffer buffer = packet->buffer; @@ -905,7 +933,7 @@ void silc_server_send_private_message(SilcServer server, silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len); /* Re-encrypt packet */ - silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, buffer->len); + silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf, buffer->len); /* Send the packet */ silc_server_packet_send_real(server, dst_sock, FALSE); @@ -918,7 +946,7 @@ void silc_server_send_private_message(SilcServer server, silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len); /* Encrypt header */ - silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, + silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf, SILC_PACKET_HEADER_LEN + packet->src_id_len + packet->dst_id_len + packet->padlen); @@ -1391,6 +1419,7 @@ void silc_server_send_notify_on_channels(SilcServer server, uint32 data_len; bool force_send = FALSE; va_list ap; + int block_len; SILC_LOG_DEBUG(("Start")); @@ -1442,18 +1471,21 @@ void silc_server_send_notify_on_channels(SilcServer server, /* Get data used in packet header encryption, keys and stuff. */ sock = (SilcSocketConnection)c->router->connection; idata = (SilcIDListData)c->router; - + block_len = idata->send_key ? + silc_cipher_get_block_len(idata->send_key) : 0; + packetdata.dst_id = silc_id_id2str(c->router->id, SILC_ID_SERVER); packetdata.dst_id_len = silc_id_get_len(c->router->id, SILC_ID_SERVER); packetdata.dst_id_type = SILC_ID_SERVER; packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + packetdata.src_id_len + packetdata.dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen); + packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len); /* Send the packet */ silc_server_packet_send_to_channel_real(server, sock, &packetdata, idata->send_key, idata->hmac_send, + idata->psn_send++, data, data_len, FALSE, force_send); @@ -1475,18 +1507,21 @@ void silc_server_send_notify_on_channels(SilcServer server, /* Get data used in packet header encryption, keys and stuff. */ sock = (SilcSocketConnection)c->connection; idata = (SilcIDListData)c; + block_len = idata->send_key ? + silc_cipher_get_block_len(idata->send_key) : 0; packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT); packetdata.dst_id_len = silc_id_get_len(c->id, SILC_ID_CLIENT); packetdata.dst_id_type = SILC_ID_CLIENT; packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + packetdata.src_id_len + packetdata.dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen); + packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len); /* Send the packet */ silc_server_packet_send_to_channel_real(server, sock, &packetdata, idata->send_key, idata->hmac_send, + idata->psn_send++, data, data_len, FALSE, force_send); @@ -1654,6 +1689,7 @@ void silc_server_relay_packet(SilcServer server, SilcSocketConnection dst_sock, SilcCipher cipher, SilcHmac hmac, + uint32 sequence, SilcPacketContext *packet, bool force_send) { @@ -1664,7 +1700,8 @@ void silc_server_relay_packet(SilcServer server, silc_buffer_put(dst_sock->outbuf, packet->buffer->data, packet->buffer->len); /* Re-encrypt packet */ - silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, packet->buffer->len); + silc_packet_encrypt(cipher, hmac, sequence, dst_sock->outbuf, + packet->buffer->len); /* Send the packet */ silc_server_packet_send_real(server, dst_sock, force_send); diff --git a/apps/silcd/packet_send.h b/apps/silcd/packet_send.h index f8c98233..25efb1a1 100644 --- a/apps/silcd/packet_send.h +++ b/apps/silcd/packet_send.h @@ -87,6 +87,7 @@ void silc_server_send_private_message(SilcServer server, SilcSocketConnection dst_sock, SilcCipher cipher, SilcHmac hmac, + uint32 sequence, SilcPacketContext *packet); void silc_server_send_motd(SilcServer server, SilcSocketConnection sock); @@ -221,6 +222,7 @@ void silc_server_relay_packet(SilcServer server, SilcSocketConnection dst_sock, SilcCipher cipher, SilcHmac hmac, + uint32 sequence, SilcPacketContext *packet, bool force_send); void silc_server_send_connection_auth_request(SilcServer server, diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c index c3cad75b..50fdc707 100644 --- a/apps/silcd/protocol.c +++ b/apps/silcd/protocol.c @@ -227,6 +227,32 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske, return FALSE; } + if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, + &idata->hmac_send)) { + silc_cipher_free(idata->send_key); + silc_cipher_free(idata->receive_key); + silc_free(conn_data); + return FALSE; + } + + if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, + &idata->hmac_receive)) { + silc_cipher_free(idata->send_key); + silc_cipher_free(idata->receive_key); + silc_hmac_free(idata->hmac_send); + silc_free(conn_data); + return FALSE; + } + + /* XXX backwards support for old MAC thingy + XXX Remove ing 0.7.x */ + if (ske->backward_version) { + silc_hmac_set_b(idata->hmac_send); + silc_hmac_set_b(idata->hmac_receive); + idata->send_key->back = TRUE; + idata->receive_key->back = TRUE; + } + if (is_responder == TRUE) { silc_cipher_set_key(idata->send_key, keymat->receive_enc_key, keymat->enc_key_len); @@ -234,6 +260,10 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske, silc_cipher_set_key(idata->receive_key, keymat->send_enc_key, keymat->enc_key_len); silc_cipher_set_iv(idata->receive_key, keymat->send_iv); + silc_hmac_set_key(idata->hmac_send, keymat->receive_hmac_key, + keymat->hmac_key_len); + silc_hmac_set_key(idata->hmac_receive, keymat->send_hmac_key, + keymat->hmac_key_len); } else { silc_cipher_set_key(idata->send_key, keymat->send_enc_key, keymat->enc_key_len); @@ -241,6 +271,10 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske, silc_cipher_set_key(idata->receive_key, keymat->receive_enc_key, keymat->enc_key_len); silc_cipher_set_iv(idata->receive_key, keymat->receive_iv); + silc_hmac_set_key(idata->hmac_send, keymat->send_hmac_key, + keymat->hmac_key_len); + silc_hmac_set_key(idata->hmac_receive, keymat->receive_hmac_key, + keymat->hmac_key_len); } idata->rekey = silc_calloc(1, sizeof(*idata->rekey)); @@ -255,29 +289,19 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske, idata->rekey->pfs = TRUE; idata->rekey->ske_group = silc_ske_group_get_number(group); - /* Save the remote host's public key */ - silc_pkcs_public_key_decode(ske->ke1_payload->pk_data, - ske->ke1_payload->pk_len, &idata->public_key); - /* Save the hash */ if (!silc_hash_alloc(hash->hash->name, &idata->hash)) { silc_cipher_free(idata->send_key); silc_cipher_free(idata->receive_key); + silc_hmac_free(idata->hmac_send); + silc_hmac_free(idata->hmac_receive); silc_free(conn_data); return FALSE; } - /* Save HMAC key to be used in the communication. */ - if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, - &idata->hmac_send)) { - silc_cipher_free(idata->send_key); - silc_cipher_free(idata->receive_key); - silc_hash_free(idata->hash); - silc_free(conn_data); - return FALSE; - } - silc_hmac_set_key(idata->hmac_send, keymat->hmac_key, keymat->hmac_key_len); - idata->hmac_receive = idata->hmac_send; + /* Save the remote host's public key */ + silc_pkcs_public_key_decode(ske->ke1_payload->pk_data, + ske->ke1_payload->pk_len, &idata->public_key); sock->user_data = (void *)conn_data; @@ -345,6 +369,11 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version, if (min > min2) status = SILC_SKE_STATUS_BAD_VERSION; + /* Backwards support for 0.5.x for various MAC related issues. + XXX Remove in 0.7.x */ + if (maj == 0 && min < 6) + ske->backward_version = 1; + return status; } @@ -1211,33 +1240,31 @@ silc_server_protocol_rekey_validate(SilcServer server, silc_cipher_set_key(idata->send_key, keymat->receive_enc_key, keymat->enc_key_len); silc_cipher_set_iv(idata->send_key, keymat->receive_iv); + silc_hmac_set_key(idata->hmac_send, keymat->receive_hmac_key, + keymat->hmac_key_len); } else { silc_cipher_set_key(idata->receive_key, keymat->send_enc_key, keymat->enc_key_len); silc_cipher_set_iv(idata->receive_key, keymat->send_iv); + silc_hmac_set_key(idata->hmac_receive, keymat->send_hmac_key, + keymat->hmac_key_len); } } else { if (send) { silc_cipher_set_key(idata->send_key, keymat->send_enc_key, keymat->enc_key_len); silc_cipher_set_iv(idata->send_key, keymat->send_iv); + silc_hmac_set_key(idata->hmac_send, keymat->send_hmac_key, + keymat->hmac_key_len); } else { silc_cipher_set_key(idata->receive_key, keymat->receive_enc_key, keymat->enc_key_len); silc_cipher_set_iv(idata->receive_key, keymat->receive_iv); + silc_hmac_set_key(idata->hmac_receive, keymat->receive_hmac_key, + keymat->hmac_key_len); } } - if (send) { - silc_hmac_alloc((char *)silc_hmac_get_name(idata->hmac_send), NULL, - &idata->hmac_send); - silc_hmac_set_key(idata->hmac_send, keymat->hmac_key, - keymat->hmac_key_len); - } else { - silc_hmac_free(idata->hmac_receive); - idata->hmac_receive = idata->hmac_send; - } - /* Save the current sending encryption key */ if (!send) { memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len); diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 5c95ce98..bad68ba9 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -1448,6 +1448,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process) SilcIDListData idata; SilcCipher cipher = NULL; SilcHmac hmac = NULL; + uint32 sequence = 0; int ret; if (!sock) @@ -1548,46 +1549,14 @@ SILC_TASK_CALLBACK(silc_server_packet_process) if (idata) { cipher = idata->receive_key; hmac = idata->hmac_receive; + sequence = idata->psn_receive; } /* Process the packet. This will call the parser that will then decrypt and parse the packet. */ - silc_packet_receive_process(sock, cipher, hmac, silc_server_packet_parse, - server); -} - -/* Callback function that the silc_packet_decrypt will call to make the - decision whether the packet is normal or special packet. We will - return TRUE if it is normal and FALSE if it is special */ - -static int silc_server_packet_decrypt_check(SilcPacketType packet_type, - SilcBuffer buffer, - SilcPacketContext *packet, - void *context) -{ - SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context; - SilcServer server = (SilcServer)parse_ctx->context; - - /* Packet is normal packet, if: - - 1) packet is private message packet and does not have private key set - 2) is other packet than channel message packet - 3) is channel message packet and remote is router and we are router - - all other packets are special packets - */ - - if (packet_type == SILC_PACKET_PRIVATE_MESSAGE && - (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) - return FALSE; - - if (packet_type != SILC_PACKET_CHANNEL_MESSAGE || - (packet_type == SILC_PACKET_CHANNEL_MESSAGE && - parse_ctx->sock->type == SILC_SOCKET_TYPE_ROUTER && - server->server_type == SILC_ROUTER)) - return TRUE; - - return FALSE; + silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? + TRUE : FALSE, cipher, hmac, sequence, + silc_server_packet_parse, server); } /* Parses whole packet, received earlier. */ @@ -1603,29 +1572,15 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real) SILC_LOG_DEBUG(("Start")); - /* Decrypt the received packet */ - ret = silc_packet_decrypt(idata ? idata->receive_key : NULL, - idata ? idata->hmac_receive : NULL, - packet->buffer, packet, - silc_server_packet_decrypt_check, parse_ctx); - if (ret < 0) { - SILC_LOG_WARNING(("Packet decryption failed for connection " - "%s:%d [%s]", sock->hostname, sock->port, - (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" : - sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" : - sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" : - "Router"))); - goto out; - } + /* XXX backwards support for 0.5.x + XXX remove in 0.7.x */ + packet->sock = sock; - if (ret == 0) { - /* Parse the packet. Packet type is returned. */ - ret = silc_packet_parse(packet); - } else { - /* Parse the packet header in special way as this is "special" - packet type. */ - ret = silc_packet_parse_special(packet); - } + /* Parse the packet */ + if (parse_ctx->normal) + ret = silc_packet_parse(packet, idata ? idata->receive_key : NULL); + else + ret = silc_packet_parse_special(packet, idata ? idata->receive_key : NULL); /* If entry is disabled ignore what we got. */ if (ret != SILC_PACKET_RESUME_ROUTER && @@ -1699,10 +1654,15 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real) /* Parser callback called by silc_packet_receive_process. This merely registers timeout that will handle the actual parsing when appropriate. */ -void silc_server_packet_parse(SilcPacketParserContext *parser_context) +void silc_server_packet_parse(SilcPacketParserContext *parser_context, + void *context) { - SilcServer server = (SilcServer)parser_context->context; + SilcServer server = (SilcServer)context; SilcSocketConnection sock = parser_context->sock; + SilcIDListData idata = (SilcIDListData)sock->user_data; + + if (idata) + idata->psn_receive = parser_context->packet->sequence + 1; switch (sock->type) { case SILC_SOCKET_TYPE_UNKNOWN: diff --git a/apps/silcd/server.h b/apps/silcd/server.h index a09d41b9..5249e6b8 100644 --- a/apps/silcd/server.h +++ b/apps/silcd/server.h @@ -126,7 +126,8 @@ void silc_server_stop(SilcServer server); void silc_server_start_key_exchange(SilcServer server, SilcServerConnection sconn, int sock); -void silc_server_packet_parse(SilcPacketParserContext *parser_context); +void silc_server_packet_parse(SilcPacketParserContext *parser_context, + void *context); void silc_server_packet_parse_type(SilcServer server, SilcSocketConnection sock, SilcPacketContext *packet); diff --git a/apps/silcd/server_backup.c b/apps/silcd/server_backup.c index d782297a..2088dd9a 100644 --- a/apps/silcd/server_backup.c +++ b/apps/silcd/server_backup.c @@ -293,7 +293,7 @@ void silc_server_backup_broadcast(SilcServer server, silc_packet_send_prepare(sock, 0, 0, buffer->len); silc_buffer_put(sock->outbuf, buffer->data, buffer->len); - silc_packet_encrypt(idata->send_key, idata->hmac_send, + silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++, sock->outbuf, sock->outbuf->len); SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len), diff --git a/doc/draft-riikonen-silc-pp-04.nroff b/doc/draft-riikonen-silc-pp-04.nroff index d54920dc..bb44b7c5 100644 --- a/doc/draft-riikonen-silc-pp-04.nroff +++ b/doc/draft-riikonen-silc-pp-04.nroff @@ -209,17 +209,16 @@ Figure 1: Typical SILC Packet SILC Header is always the first part of the packet and its purpose is to provide information about the packet. It provides for example the packet type, origin of the packet and the destination of the packet. -The header is variable in length and first two (2) bytes of the -header (thus first two bytes of the packet) are not encrypted. The -first two (2) bytes are the length of the packet which is not encrypted. -See the following section for description of SILC Packet header. Packets -without SILC header or with malformed SILC header MUST be dropped. +The header is variable in length. See the following section for +description of SILC Packet header. Packets without SILC header or +with malformed SILC header MUST be dropped. Padding follows the packet header. The purpose of the padding is to make the packet multiple by eight (8) or by the block size of the cipher used in the encryption, which ever is larger. The maximum length of padding is currently 16 bytes. The padding is always -encrypted. +encrypted. See the section 2.7 Padding Generation for more detailed +information. Data payload area follows padding and it is the actual data of the packet. The packet data is the packet payloads defined in this @@ -245,15 +244,14 @@ detailed information about the packet. The receiver of the packet uses the packet header to parse the packet and gain other relevant parameters of the packet. -The following diagram represents the SILC packet header. (*) indicates -that this field is never encrypted. Other fields are always encrypted. +The following diagram represents the SILC packet header. .in 5 .nf 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Payload Length * | Flags | Packet Type | +| Payload Length | Flags | Packet Type | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source ID Length | Destination ID Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -277,8 +275,7 @@ Figure 2: SILC Packet Header .in 6 o Payload Length (2 bytes) - Is the length of the packet - not including the padding of the packet. This field must - not be encrypted but must always be authenticated. + not including the padding of the packet. o Flags (1 byte) - Indicates flags to be used in packet processing. Several flags may be set by ORing the flags @@ -2398,12 +2395,6 @@ any of the special cases described in the following sections the packet decryption is special. If the packet type is not among those special packet types rest of the packet can be decrypted with the same key. -Also, note that two bytes of the SILC Packet header are not encrypted -thus it must be noticed in the decryption process by starting the -decryption from the second byte of the header. This sets some rules -to padding generation as well, see the section 2.7 Packet Padding -Generation. - With out a doubt, this sort of decryption processing causes some overhead to packet decryption, but never the less, is required. @@ -2512,7 +2503,11 @@ Hence, packet's MAC generation is as follows: The MAC key is negotiated during the SKE protocol. The sequence number is a 32 bit MSB first value starting from zero for first packet and increasing for subsequent packets, finally wrapping after 2^32 packets. -The value is never reset, not even after rekey has been performed. +The value is never reset, not even after rekey has been performed. Note +that the sequence number is incremented only when MAC is computed for a +packet. If packet is not encrypted and MAC is not computed then the +sequence number is not incremented. Hence, the sequence number is zero +for first encrypted packet. See [SILC1] for defined and allowed MAC algorithms. @@ -2529,23 +2524,21 @@ and between the Data Payload area. The padding for normal packets are calculated as follows: .in 6 -padding length = 16 - ((packet length - 2) mod 16) +padding length = 16 - (packet_length mod block_size) .in 3 -The 16 is the maximum padding allowed in SILC packet. Two (2) is -subtracted from the true length of the packet because two (2) bytes -is not encrypted in SILC Packet Header, see section 2.2 SILC Packet -Header. Those two bytes that are not encrypted MUST NOT be calculated -to the padding length. +The `block_size' is the block size of the cipher. The maximum padding +length is 16 bytes, and minimum is 1 byte. The above algorithm calculates +the padding to the next block size, and always returns the padding +length between 1 - 16 bytes. -For special packets the padding calculation MAY be different as special +For special packets the padding calculation is different as special packets may be encrypted differently. In these cases the encrypted data area MUST already be multiple by the block size thus in this case the padding is calculated only for SILC Packet Header, not for any other area of the packet. The same algorithm works in this case as well, except that the `packet length' is now the SILC Packet Header -length. In this case, as well, two (2) is subtracted from the -length. +length. The padding MUST be random data, preferably, generated by cryptographically strong random number generator. diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 617682e1..c7c17591 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -30,7 +30,8 @@ SILC_TASK_CALLBACK(silc_client_packet_parse_real); SILC_TASK_CALLBACK(silc_client_rekey_callback); SILC_TASK_CALLBACK(silc_client_rekey_final); -static void silc_client_packet_parse(SilcPacketParserContext *parser_context); +static void silc_client_packet_parse(SilcPacketParserContext *parser_context, + void *context); static void silc_client_packet_parse_type(SilcClient client, SilcSocketConnection sock, SilcPacketContext *packet); @@ -748,42 +749,15 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process) /* Process the packet. This will call the parser that will then decrypt and parse the packet. */ if (sock->type != SILC_SOCKET_TYPE_UNKNOWN) - silc_packet_receive_process(sock, conn->receive_key, conn->hmac_receive, + silc_packet_receive_process(sock, FALSE, conn->receive_key, + conn->hmac_receive, conn->psn_receive, silc_client_packet_parse, client); else - silc_packet_receive_process(sock, NULL, NULL, + silc_packet_receive_process(sock, FALSE, NULL, NULL, 0, silc_client_packet_parse, client); } } -/* Callback function that the silc_packet_decrypt will call to make the - decision whether the packet is normal or special packet. We will - return TRUE if it is normal and FALSE if it is special */ - -static int silc_client_packet_decrypt_check(SilcPacketType packet_type, - SilcBuffer buffer, - SilcPacketContext *packet, - void *context) -{ - - /* Packet is normal packet, if: - - 1) packet is private message packet and does not have private key set - 2) is other packet than channel message packet - - all other packets are special packets - */ - - if (packet_type == SILC_PACKET_PRIVATE_MESSAGE && - (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) - return FALSE; - - if (packet_type != SILC_PACKET_CHANNEL_MESSAGE) - return TRUE; - - return FALSE; -} - /* Parses whole packet, received earlier. */ SILC_TASK_CALLBACK(silc_client_packet_parse_real) @@ -791,33 +765,17 @@ SILC_TASK_CALLBACK(silc_client_packet_parse_real) SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context; SilcClient client = (SilcClient)parse_ctx->context; SilcPacketContext *packet = parse_ctx->packet; - SilcBuffer buffer = packet->buffer; SilcSocketConnection sock = parse_ctx->sock; SilcClientConnection conn = (SilcClientConnection)sock->user_data; int ret; SILC_LOG_DEBUG(("Start")); - /* Decrypt the received packet */ - if (sock->type != SILC_SOCKET_TYPE_UNKNOWN) - ret = silc_packet_decrypt(conn->receive_key, conn->hmac_receive, - buffer, packet, - silc_client_packet_decrypt_check, parse_ctx); + /* Parse the packet */ + if (parse_ctx->normal) + ret = silc_packet_parse(packet, conn->receive_key); else - ret = silc_packet_decrypt(NULL, NULL, buffer, packet, - silc_client_packet_decrypt_check, parse_ctx); - - if (ret < 0) - goto out; - - if (ret == 0) { - /* Parse the packet. Packet type is returned. */ - ret = silc_packet_parse(packet); - } else { - /* Parse the packet header in special way as this is "special" - packet type. */ - ret = silc_packet_parse_special(packet); - } + ret = silc_packet_parse_special(packet, conn->receive_key); if (ret == SILC_PACKET_NONE) goto out; @@ -834,9 +792,15 @@ SILC_TASK_CALLBACK(silc_client_packet_parse_real) /* Parser callback called by silc_packet_receive_process. Thie merely registers timeout that will handle the actual parsing when appropriate. */ -void silc_client_packet_parse(SilcPacketParserContext *parser_context) +void silc_client_packet_parse(SilcPacketParserContext *parser_context, + void *context) { - SilcClient client = (SilcClient)parser_context->context; + SilcClient client = (SilcClient)context; + SilcSocketConnection sock = parser_context->sock; + SilcClientConnection conn = (SilcClientConnection)sock->user_data; + + if (conn && conn->hmac_receive) + conn->psn_receive = parser_context->packet->sequence + 1; /* Parse the packet */ silc_schedule_task_add(client->schedule, parser_context->sock->sock, @@ -1135,6 +1099,8 @@ void silc_client_packet_send(SilcClient client, int force_send) { SilcPacketContext packetdata; + int block_len; + uint32 sequence = 0; if (!sock) return; @@ -1153,8 +1119,13 @@ void silc_client_packet_send(SilcClient client, dst_id = ((SilcClientConnection)sock->user_data)->remote_id; dst_id_type = SILC_ID_SERVER; } + + if (hmac) + sequence = ((SilcClientConnection)sock->user_data)->psn_send++; } + block_len = cipher ? silc_cipher_get_block_len(cipher) : 0; + /* Set the packet context pointers */ packetdata.flags = 0; packetdata.type = type; @@ -1180,7 +1151,7 @@ void silc_client_packet_send(SilcClient client, } packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + packetdata.src_id_len + packetdata.dst_id_len; - packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen); + packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len); /* Prepare outgoing data buffer for packet sending */ silc_packet_send_prepare(sock, @@ -1199,11 +1170,12 @@ void silc_client_packet_send(SilcClient client, silc_buffer_put(sock->outbuf, data, data_len); /* Create the outgoing packet */ - silc_packet_assemble(&packetdata); + silc_packet_assemble(&packetdata, cipher); /* Encrypt the packet */ if (cipher) - silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len); + silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf, + sock->outbuf->len); SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len), sock->outbuf->data, sock->outbuf->len); @@ -1326,8 +1298,10 @@ void silc_client_close_connection(SilcClient client, silc_cipher_free(conn->send_key); if (conn->receive_key) silc_cipher_free(conn->receive_key); - if (conn->hmac_send) /* conn->hmac_receive is same */ + if (conn->hmac_send) silc_hmac_free(conn->hmac_send); + if (conn->hmac_receive) + silc_hmac_free(conn->hmac_receive); if (conn->pending_commands) silc_dlist_uninit(conn->pending_commands); if (conn->rekey) diff --git a/lib/silcclient/client.h b/lib/silcclient/client.h index a2677b70..2275194b 100644 --- a/lib/silcclient/client.h +++ b/lib/silcclient/client.h @@ -97,6 +97,8 @@ struct SilcClientConnectionStruct { SilcHmac hmac_send; SilcHmac hmac_receive; SilcHash hash; + uint32 psn_send; + uint32 psn_receive; /* Client ID and Channel ID cache. Messages transmitted in SILC network are done using different unique ID's. These are the cache for diff --git a/lib/silcclient/client_channel.c b/lib/silcclient/client_channel.c index d08b3da0..8bc011e1 100644 --- a/lib/silcclient/client_channel.c +++ b/lib/silcclient/client_channel.c @@ -49,6 +49,7 @@ void silc_client_send_channel_message(SilcClient client, SilcHmac hmac; unsigned char *id_string; uint32 iv_len; + int block_len; SILC_LOG_DEBUG(("Sending packet to channel")); @@ -86,6 +87,8 @@ void silc_client_send_channel_message(SilcClient client, if (!cipher || !hmac) return; + block_len = silc_cipher_get_block_len(cipher); + /* Generate IV */ iv_len = silc_cipher_get_block_len(cipher); if (channel->iv[0] == '\0') @@ -118,7 +121,7 @@ void silc_client_send_channel_message(SilcClient client, packetdata.src_id_len + packetdata.dst_id_len; packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + packetdata.src_id_len + - packetdata.dst_id_len)); + packetdata.dst_id_len), block_len); /* Prepare outgoing data buffer for packet sending */ silc_packet_send_prepare(sock, @@ -134,11 +137,12 @@ void silc_client_send_channel_message(SilcClient client, silc_buffer_put(sock->outbuf, payload->data, payload->len); /* Create the outgoing packet */ - silc_packet_assemble(&packetdata); + silc_packet_assemble(&packetdata, cipher); /* Encrypt the header and padding of the packet. This is encrypted with normal session key shared with our server. */ - silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + + silc_packet_encrypt(cipher, hmac, conn->psn_send++, + sock->outbuf, SILC_PACKET_HEADER_LEN + packetdata.src_id_len + packetdata.dst_id_len + packetdata.padlen); diff --git a/lib/silcclient/client_prvmsg.c b/lib/silcclient/client_prvmsg.c index 3da26c85..d9f2e65d 100644 --- a/lib/silcclient/client_prvmsg.c +++ b/lib/silcclient/client_prvmsg.c @@ -45,6 +45,7 @@ void silc_client_send_private_message(SilcClient client, SilcPacketContext packetdata; SilcCipher cipher; SilcHmac hmac; + int block_len; SILC_LOG_DEBUG(("Sending private message")); @@ -69,6 +70,7 @@ void silc_client_send_private_message(SilcClient client, /* Get data used in the encryption */ cipher = client_entry->send_key; hmac = conn->hmac_send; + block_len = silc_cipher_get_block_len(cipher); /* Set the packet context pointers. */ packetdata.flags = SILC_PACKET_FLAG_PRIVMSG_KEY; @@ -83,7 +85,7 @@ void silc_client_send_private_message(SilcClient client, packetdata.src_id_len + packetdata.dst_id_len; packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + packetdata.src_id_len + - packetdata.dst_id_len)); + packetdata.dst_id_len), block_len); /* Prepare outgoing data buffer for packet sending */ silc_packet_send_prepare(sock, @@ -99,11 +101,12 @@ void silc_client_send_private_message(SilcClient client, silc_buffer_put(sock->outbuf, buffer->data, buffer->len); /* Create the outgoing packet */ - silc_packet_assemble(&packetdata); + silc_packet_assemble(&packetdata, cipher); /* Encrypt the header and padding of the packet. */ cipher = conn->send_key; - silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + + silc_packet_encrypt(cipher, hmac, conn->psn_send++, + sock->outbuf, SILC_PACKET_HEADER_LEN + packetdata.src_id_len + packetdata.dst_id_len + packetdata.padlen); diff --git a/lib/silcclient/protocol.c b/lib/silcclient/protocol.c index 51ee452c..ef570d81 100644 --- a/lib/silcclient/protocol.c +++ b/lib/silcclient/protocol.c @@ -121,15 +121,19 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske, /* Allocate cipher to be used in the communication */ silc_cipher_alloc(cipher->cipher->name, &conn->send_key); silc_cipher_alloc(cipher->cipher->name, &conn->receive_key); - - conn->send_key->cipher->set_key(conn->send_key->context, - keymat->send_enc_key, - keymat->enc_key_len); - conn->send_key->set_iv(conn->send_key, keymat->send_iv); - conn->receive_key->cipher->set_key(conn->receive_key->context, - keymat->receive_enc_key, - keymat->enc_key_len); - conn->receive_key->set_iv(conn->receive_key, keymat->receive_iv); + silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &conn->hmac_send); + silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &conn->hmac_receive); + + silc_cipher_set_key(conn->send_key, keymat->send_enc_key, + keymat->enc_key_len); + silc_cipher_set_iv(conn->send_key, keymat->send_iv); + silc_cipher_set_key(conn->receive_key, keymat->receive_enc_key, + keymat->enc_key_len); + silc_cipher_set_iv(conn->receive_key, keymat->receive_iv); + silc_hmac_set_key(conn->hmac_send, keymat->send_hmac_key, + keymat->hmac_key_len); + silc_hmac_set_key(conn->hmac_receive, keymat->receive_hmac_key, + keymat->hmac_key_len); /* Rekey stuff */ conn->rekey = silc_calloc(1, sizeof(*conn->rekey)); @@ -144,11 +148,6 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske, conn->rekey->pfs = TRUE; conn->rekey->ske_group = silc_ske_group_get_number(group); - /* Save HMAC key to be used in the communication. */ - silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &conn->hmac_send); - silc_hmac_set_key(conn->hmac_send, keymat->hmac_key, keymat->hmac_key_len); - conn->hmac_receive = conn->hmac_send; - /* Save the HASH function */ silc_hash_alloc(hash->hash->name, &conn->hash); } @@ -750,33 +749,31 @@ silc_client_protocol_rekey_validate(SilcClient client, silc_cipher_set_key(conn->send_key, keymat->receive_enc_key, keymat->enc_key_len); silc_cipher_set_iv(conn->send_key, keymat->receive_iv); + silc_hmac_set_key(conn->hmac_send, keymat->receive_hmac_key, + keymat->hmac_key_len); } else { silc_cipher_set_key(conn->receive_key, keymat->send_enc_key, keymat->enc_key_len); silc_cipher_set_iv(conn->receive_key, keymat->send_iv); + silc_hmac_set_key(conn->hmac_receive, keymat->send_hmac_key, + keymat->hmac_key_len); } } else { if (send) { silc_cipher_set_key(conn->send_key, keymat->send_enc_key, keymat->enc_key_len); silc_cipher_set_iv(conn->send_key, keymat->send_iv); + silc_hmac_set_key(conn->hmac_send, keymat->send_hmac_key, + keymat->hmac_key_len); } else { silc_cipher_set_key(conn->receive_key, keymat->receive_enc_key, keymat->enc_key_len); silc_cipher_set_iv(conn->receive_key, keymat->receive_iv); + silc_hmac_set_key(conn->hmac_receive, keymat->receive_hmac_key, + keymat->hmac_key_len); } } - if (send) { - silc_hmac_alloc((char *)silc_hmac_get_name(conn->hmac_receive), NULL, - &conn->hmac_send); - silc_hmac_set_key(conn->hmac_send, keymat->hmac_key, - keymat->hmac_key_len); - } else { - silc_hmac_free(conn->hmac_receive); - conn->hmac_receive = conn->hmac_send; - } - /* Save the current sending encryption key */ if (!send) { memset(conn->rekey->send_enc_key, 0, conn->rekey->enc_key_len); diff --git a/lib/silccore/silcchannel.c b/lib/silccore/silcchannel.c index dab8a83b..1edd0bcf 100644 --- a/lib/silccore/silcchannel.c +++ b/lib/silccore/silcchannel.c @@ -334,7 +334,7 @@ SilcBuffer silc_channel_message_payload_encode(uint16 flags, { int i; SilcBuffer buffer; - uint32 len, pad_len, mac_len; + uint32 len, pad_len, mac_len, block_len; unsigned char pad[SILC_PACKET_MAX_PADLEN]; unsigned char mac[32]; @@ -343,8 +343,9 @@ SilcBuffer silc_channel_message_payload_encode(uint16 flags, /* Calculate length of padding. IV is not included into the calculation since it is not encrypted. */ mac_len = silc_hmac_len(hmac); + block_len = silc_cipher_get_block_len(cipher); len = 6 + data_len + mac_len; - pad_len = SILC_PACKET_PADLEN((len + 2)); + pad_len = SILC_PACKET_PADLEN(len, block_len); /* Allocate channel payload buffer */ len += pad_len + iv_len; diff --git a/lib/silccore/silcpacket.c b/lib/silccore/silcpacket.c index 28349d51..f21ae66a 100644 --- a/lib/silccore/silcpacket.c +++ b/lib/silccore/silcpacket.c @@ -76,7 +76,7 @@ int silc_packet_send(SilcSocketConnection sock, bool force_send) other process of HMAC computing and encryption is needed this function cannot be used. */ -void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, +void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, uint32 sequence, SilcBuffer buffer, uint32 len) { unsigned char mac[32]; @@ -86,20 +86,34 @@ void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, data area thus this uses the length found in buffer, not the length sent as argument. */ if (hmac) { + unsigned char psn[4]; + silc_hmac_init(hmac); + + /* XXX Backwards support for old MAC computation. + XXX Remove in 0.7.x */ + if (!silc_hmac_get_b(hmac)) { + SILC_PUT32_MSB(sequence, psn); + silc_hmac_update(hmac, psn, 4); + } + silc_hmac_update(hmac, buffer->data, buffer->len); silc_hmac_final(hmac, mac, &mac_len); silc_buffer_put_tail(buffer, mac, mac_len); memset(mac, 0, sizeof(mac)); } - /* Encrypt the data area of the packet. 2 bytes of the packet - are not encrypted. */ + /* Encrypt the data area of the packet. */ if (cipher) { - SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d (%d)", - cipher->cipher->name, len, len - 2)); - cipher->cipher->encrypt(cipher->context, buffer->data + 2, - buffer->data + 2, len - 2, cipher->iv); + SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d", + cipher->cipher->name, len)); + /* XXX Backwards support for 0.5.x + XXX Remove in 0.7.x */ + if (hmac && silc_hmac_get_b(hmac)) + silc_cipher_encrypt(cipher, buffer->data + 2, buffer->data + 2, + len - 1, cipher->iv); + else + silc_cipher_encrypt(cipher, buffer->data, buffer->data, len, cipher->iv); } /* Pull the HMAC into the visible data area in the buffer */ @@ -130,10 +144,10 @@ void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, ^ ^ Start of assembled packet - Packet construct is as follows (* = won't be encrypted): + Packet construct is as follows: n bytes SILC Header - 2 bytes Payload length (*) + 2 bytes Payload length 1 byte Flags 1 byte Packet type 2 bytes Source ID Length @@ -153,9 +167,10 @@ void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, */ -void silc_packet_assemble(SilcPacketContext *ctx) +void silc_packet_assemble(SilcPacketContext *ctx, SilcCipher cipher) { unsigned char tmppad[SILC_PACKET_MAX_PADLEN]; + int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0; int i; SILC_LOG_DEBUG(("Assembling outgoing packet")); @@ -168,11 +183,14 @@ void silc_packet_assemble(SilcPacketContext *ctx) ctx->src_id_len + ctx->dst_id_len; /* Calculate the length of the padding. The padding is calculated from - the data that will be encrypted. As protocol states 3 first bytes - of the packet are not encrypted they are not included in the - padding calculation. */ - if (!ctx->padlen) - ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen); + the data that will be encrypted. */ + if (!ctx->padlen) { + ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen, block_len); + /* XXX backwards support for 0.5.x + XXX remove in 0.7.x */ + if (cipher->back) + ctx->padlen = SILC_PACKET_PADLEN2(ctx->truelen, block_len); + } /* Put the start of the data section to the right place. */ silc_buffer_push(ctx->buffer, SILC_PACKET_HEADER_LEN + @@ -272,36 +290,92 @@ void silc_packet_send_prepare(SilcSocketConnection sock, ******************************************************************************/ -/* Processes the received data. This checks the received data and - calls parser callback that handles the actual packet decryption - and parsing. If more than one packet was received this calls the - parser multiple times. The parser callback will get context - SilcPacketParserContext that includes the packet and the `context' - sent to this function. */ +static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac, + uint32 sequence, SilcBuffer buffer, + bool normal); + +/* Receives packet from network and reads the data into connection's + incoming data buffer. If the data was read directly this returns the + read bytes, if error occured this returns -1, if the data could not + be read directly at this time this returns -2 in which case the data + should be read again at some later time, or If EOF occured this returns + 0. */ + +int silc_packet_receive(SilcSocketConnection sock) +{ + int ret; + + SILC_LOG_DEBUG(("Receiving packet from %s:%d [%s]", sock->hostname, + sock->port, + (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" : + sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" : + sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" : + "Router"))); + + /* Read some data from connection */ + ret = silc_socket_read(sock); + + return ret; +} + +/* Processes and decrypts the incmoing data, and calls parser callback + for each received packet that will handle the actual packet parsing. + If more than one packet was received this calls the parser multiple + times. The parser callback will get context SilcPacketParserContext + that includes the packet and the `parser_context' sent to this + function. + + The `local_is_router' indicates whether the caller is router server + in which case the receiving process of a certain packet types may + be special. Normal server and client must set it to FALSE. The + SilcPacketParserContext will indicate also whether the received + packet was normal or special packet. */ void silc_packet_receive_process(SilcSocketConnection sock, + bool local_is_router, SilcCipher cipher, SilcHmac hmac, + uint32 sequence, SilcPacketParserCallback parser, - void *context) + void *parser_context) { SilcPacketParserContext *parse_ctx; - int packetlen, paddedlen, count, mac_len = 0; + int packetlen, paddedlen, mac_len = 0; + int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0; - /* We need at least 2 bytes of data to be able to start processing - the packet. */ - if (sock->inbuf->len < 2) + if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN) return; if (hmac) mac_len = silc_hmac_len(hmac); /* Parse the packets from the data */ - count = 0; while (sock->inbuf->len > 0) { - SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen); - paddedlen += 2; - count++; + /* Decrypt first 16 bytes of the packet */ + if (!SILC_IS_INBUF_PENDING(sock) && cipher) { + /* XXX backwards support for 0.5.x + XXX remove in 0.7.x */ + if (cipher->back) + silc_cipher_decrypt(cipher, sock->inbuf->data + 2, + sock->inbuf->data + 2, + SILC_PACKET_MIN_HEADER_LEN, cipher->iv); + else + silc_cipher_decrypt(cipher, sock->inbuf->data, sock->inbuf->data, + SILC_PACKET_MIN_HEADER_LEN, cipher->iv); + } + + /* Get packet lenght and full packet length with padding */ + SILC_PACKET_LENGTH(sock->inbuf, packetlen); + /* XXX backwards support for 0.5.x + XXX remove in 0.7.x */ + if (cipher && cipher->back) { + paddedlen = packetlen + SILC_PACKET_PADLEN2(packetlen, block_len); + paddedlen += 2; + } else { + paddedlen = packetlen + SILC_PACKET_PADLEN(packetlen, block_len); + } + + /* Sanity checks */ if (packetlen < SILC_PACKET_MIN_LEN) { SILC_LOG_DEBUG(("Received invalid packet, dropped")); silc_buffer_clear(sock->inbuf); @@ -309,86 +383,96 @@ void silc_packet_receive_process(SilcSocketConnection sock, } if (sock->inbuf->len < paddedlen + mac_len) { - SILC_LOG_DEBUG(("Received partial packet, waiting for the rest")); + SILC_LOG_DEBUG(("Received partial packet, waiting for the rest" + "(%d < %d)", sock->inbuf->len, paddedlen + mac_len)); + SILC_SET_INBUF_PENDING(sock); return; } + SILC_UNSET_INBUF_PENDING(sock); parse_ctx = silc_calloc(1, sizeof(*parse_ctx)); parse_ctx->packet = silc_packet_context_alloc(); parse_ctx->packet->buffer = silc_buffer_alloc(paddedlen + mac_len); + parse_ctx->packet->sequence = sequence++; parse_ctx->sock = sock; - parse_ctx->context = context; + parse_ctx->context = parser_context; silc_buffer_pull_tail(parse_ctx->packet->buffer, SILC_BUFFER_END(parse_ctx->packet->buffer)); silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data, - paddedlen + mac_len); + paddedlen + mac_len); + + SILC_LOG_HEXDUMP(("Incoming packet (%d) (%d bytes decrypted), len %d", + sequence - 1, block_len, paddedlen + mac_len), + sock->inbuf->data, paddedlen + mac_len); + + /* Check whether this is normal or special packet */ + if (local_is_router) { + if (sock->inbuf->data[3] == SILC_PACKET_PRIVATE_MESSAGE && + (sock->inbuf->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) + parse_ctx->normal = FALSE; + else if (sock->inbuf->data[3] != SILC_PACKET_CHANNEL_MESSAGE || + (sock->inbuf->data[3] == SILC_PACKET_CHANNEL_MESSAGE && + sock->type == SILC_SOCKET_TYPE_ROUTER)) + parse_ctx->normal = TRUE; + } else { + if (sock->inbuf->data[3] == SILC_PACKET_PRIVATE_MESSAGE && + (sock->inbuf->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) + parse_ctx->normal = FALSE; + else if (sock->inbuf->data[3] != SILC_PACKET_CHANNEL_MESSAGE) + parse_ctx->normal = TRUE; + } - SILC_LOG_HEXDUMP(("Incoming packet, len %d", - parse_ctx->packet->buffer->len), - parse_ctx->packet->buffer->data, - parse_ctx->packet->buffer->len); + /* Decrypt rest of the packet */ + if (cipher) + silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence, + parse_ctx->packet->buffer, parse_ctx->normal); /* Call the parser */ if (parser) - (*parser)(parse_ctx); + (*parser)(parse_ctx, parser_context); /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */ - silc_buffer_pull(sock->inbuf, paddedlen); - if (hmac) - silc_buffer_pull(sock->inbuf, mac_len); + silc_buffer_pull(sock->inbuf, paddedlen + mac_len); } SILC_LOG_DEBUG(("Clearing inbound buffer")); silc_buffer_clear(sock->inbuf); } -/* Receives packet from network and reads the data into connection's - incoming data buffer. If the data was read directly this returns the - read bytes, if error occured this returns -1, if the data could not - be read directly at this time this returns -2 in which case the data - should be read again at some later time, or If EOF occured this returns - 0. */ - -int silc_packet_receive(SilcSocketConnection sock) -{ - int ret; - - SILC_LOG_DEBUG(("Receiving packet from %s:%d [%s]", sock->hostname, - sock->port, - (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" : - sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" : - sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" : - "Router"))); - - /* Read some data from connection */ - ret = silc_socket_read(sock); - - return ret; -} - /* Checks MAC in the packet. Returns TRUE if MAC is Ok. This is called after packet has been totally decrypted and parsed. */ -static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer) +static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer, + uint32 sequence) { /* Check MAC */ if (hmac) { - unsigned char mac[32]; + unsigned char mac[32], psn[4]; uint32 mac_len; SILC_LOG_DEBUG(("Verifying MAC")); /* Compute HMAC of packet */ + memset(mac, 0, sizeof(mac)); silc_hmac_init(hmac); + + /* XXX Backwards support for old MAC computation. + XXX Remove in 0.7.x */ + if (!silc_hmac_get_b(hmac)) { + SILC_PUT32_MSB(sequence, psn); + silc_hmac_update(hmac, psn, 4); + } + silc_hmac_update(hmac, buffer->data, buffer->len); silc_hmac_final(hmac, mac, &mac_len); /* Compare the HMAC's (buffer->tail has the packet's HMAC) */ if (memcmp(mac, buffer->tail, mac_len)) { SILC_LOG_ERROR(("MAC failed")); + assert(FALSE); return FALSE; } @@ -422,11 +506,17 @@ static int silc_packet_decrypt_rest(SilcCipher cipher, SilcHmac hmac, SILC_LOG_DEBUG(("Decrypting rest of the packet")); /* Decrypt rest of the packet */ - silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2); - cipher->cipher->decrypt(cipher->context, buffer->data + 2, - buffer->data + 2, buffer->len - 2, - cipher->iv); - silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2); + silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN); + /* XXX backwards support for 0.5.x + XXX remove in 0.7.x */ + if (cipher->back) + silc_cipher_decrypt(cipher, buffer->data + 2, buffer->data + 2, + buffer->len - 2, + cipher->iv); + else + silc_cipher_decrypt(cipher, buffer->data, buffer->data, buffer->len, + cipher->iv); + silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN); SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d", buffer->len), buffer->data, buffer->len); @@ -447,7 +537,7 @@ static int silc_packet_decrypt_rest_special(SilcCipher cipher, { /* Decrypt rest of the header plus padding */ if (cipher) { - uint16 truelen, len1, len2, padlen; + uint16 truelen, len1, len2, padlen, blocklen; /* Pull MAC from packet before decryption */ if (hmac) { @@ -464,21 +554,42 @@ static int silc_packet_decrypt_rest_special(SilcCipher cipher, SILC_GET16_MSB(len1, &buffer->data[4]); SILC_GET16_MSB(len2, &buffer->data[6]); + blocklen = silc_cipher_get_block_len(cipher); truelen = SILC_PACKET_HEADER_LEN + len1 + len2; - padlen = SILC_PACKET_PADLEN(truelen); - len1 = (truelen + padlen) - (SILC_PACKET_MIN_HEADER_LEN - 2); - silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2); - if (len1 - 2 > buffer->len) { - SILC_LOG_DEBUG(("Garbage in header of packet, bad packet length, " - "packet dropped")); - return FALSE; - } + /* XXX backwards support for 0.5.x + XXX remove in 0.7.x */ + if (cipher->back) { + padlen = SILC_PACKET_PADLEN2(truelen, blocklen); + len1 = (truelen + padlen) - (SILC_PACKET_MIN_HEADER_LEN); + + silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN); + + if (len1 - 2 > buffer->len) { + SILC_LOG_DEBUG(("Garbage in header of packet, bad packet length, " + "packet dropped")); + return FALSE; + } - cipher->cipher->decrypt(cipher->context, buffer->data + 2, - buffer->data + 2, len1 - 2, - cipher->iv); - silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2); + silc_cipher_decrypt(cipher, buffer->data + 2, buffer->data + 2, + len1 - 2, cipher->iv); + } else { + blocklen = silc_cipher_get_block_len(cipher); + truelen = SILC_PACKET_HEADER_LEN + len1 + len2; + padlen = SILC_PACKET_PADLEN(truelen, blocklen); + len1 = (truelen + padlen) - SILC_PACKET_MIN_HEADER_LEN; + + silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN); + + if (len1 > buffer->len) { + SILC_LOG_DEBUG(("Garbage in header of packet, bad packet length, " + "packet dropped")); + return FALSE; + } + + silc_cipher_decrypt(cipher, buffer->data, buffer->data, len1, cipher->iv); + } + silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN); } return TRUE; @@ -498,31 +609,19 @@ static int silc_packet_decrypt_rest_special(SilcCipher cipher, the callback return TRUE the packet is normal and FALSE if the packet is special and requires special procesing. */ -int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac, - SilcBuffer buffer, SilcPacketContext *packet, - SilcPacketCheckDecrypt check_packet, - void *context) +static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac, + uint32 sequence, SilcBuffer buffer, + bool normal) { - int check; - - /* Decrypt start of the packet header */ - if (cipher) - silc_cipher_decrypt(cipher, buffer->data + 2, buffer->data + 2, - SILC_PACKET_MIN_HEADER_LEN - 2, cipher->iv); - - /* Do packet checking, whether the packet is normal or special */ - check = check_packet((SilcPacketType)buffer->data[3], buffer, - packet, context); - /* If the packet type is not any special type lets decrypt rest of the packet here. */ - if (check == TRUE) { + if (normal == TRUE) { /* Normal packet, decrypt rest of the packet */ if (!silc_packet_decrypt_rest(cipher, hmac, buffer)) return -1; /* Check MAC */ - if (!silc_packet_check_mac(hmac, buffer)) + if (!silc_packet_check_mac(hmac, buffer, sequence)) return -1; return 0; @@ -533,7 +632,7 @@ int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac, return -1; /* Check MAC */ - if (!silc_packet_check_mac(hmac, buffer)) + if (!silc_packet_check_mac(hmac, buffer, sequence)) return -1; return 1; @@ -546,10 +645,11 @@ int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac, function returns the type of the packet. The data section of the buffer is parsed, not head or tail sections. */ -SilcPacketType silc_packet_parse(SilcPacketContext *ctx) +SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher) { SilcBuffer buffer = ctx->buffer; int len, ret; + int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0; SILC_LOG_DEBUG(("Parsing incoming packet")); @@ -573,12 +673,13 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx) if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN || ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) { - SILC_LOG_ERROR(("Bad ID lengths in packet")); + SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)", + ctx->src_id_len, ctx->dst_id_len)); return SILC_PACKET_NONE; } /* Calculate length of padding in packet */ - ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen); + ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen, block_len); silc_buffer_pull(buffer, len); ret = silc_buffer_unformat(buffer, @@ -592,6 +693,15 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx) if (ret == -1) return SILC_PACKET_NONE; + /* XXX backwards support for 0.5.x + XXX remove in 0.7.x */ + silc_buffer_pull(buffer, + ctx->src_id_len + 1 + ctx->dst_id_len + ctx->padlen); + SILC_LOG_DEBUG(("**************** %d", buffer->len)); + if (buffer->len == 2) + ctx->padlen += 2; + silc_buffer_push(buffer, ret); + silc_buffer_push(buffer, len); SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), @@ -612,10 +722,12 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx) the header in a way that it does not take the data area into account and parses the header and padding area only. */ -SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx) +SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx, + SilcCipher cipher) { SilcBuffer buffer = ctx->buffer; int len, tmplen, ret; + int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0; SILC_LOG_DEBUG(("Parsing incoming packet")); @@ -634,12 +746,15 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx) SILC_STR_UI_SHORT(&ctx->dst_id_len), SILC_STR_UI_CHAR(&ctx->src_id_type), SILC_STR_END); - if (len == -1) + if (len == -1) { + SILC_LOG_ERROR(("Malformed packet header, packet dropped")); return SILC_PACKET_NONE; + } if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN || ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) { - SILC_LOG_ERROR(("Bad ID lengths in packet")); + SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)", + ctx->src_id_len, ctx->dst_id_len)); return SILC_PACKET_NONE; } @@ -647,7 +762,12 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx) the data area is not used in the padding calculation as it won't be decrypted by the caller. */ tmplen = SILC_PACKET_HEADER_LEN + ctx->src_id_len + ctx->dst_id_len; - ctx->padlen = SILC_PACKET_PADLEN(tmplen); + /* XXX backwards support for 0.5.x + XXX remove in 0.7.x */ + if (ctx->back) + ctx->padlen = SILC_PACKET_PADLEN2(tmplen, block_len); + else + ctx->padlen = SILC_PACKET_PADLEN(tmplen, block_len); silc_buffer_pull(buffer, len); ret = silc_buffer_unformat(buffer, @@ -658,8 +778,10 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx) ctx->dst_id_len), SILC_STR_UI_XNSTRING(NULL, ctx->padlen), SILC_STR_END); - if (ret == -1) + if (ret == -1) { + SILC_LOG_ERROR(("Malformed packet header, packet dropped")); return SILC_PACKET_NONE; + } silc_buffer_push(buffer, len); diff --git a/lib/silccore/silcpacket.h b/lib/silccore/silcpacket.h index c8490b0b..1e70334d 100644 --- a/lib/silccore/silcpacket.h +++ b/lib/silccore/silcpacket.h @@ -35,12 +35,12 @@ #define SILC_PACKET_DEFAULT_SIZE SILC_SOCKET_BUF_SIZE /* Header length without source and destination ID's. */ -#define SILC_PACKET_HEADER_LEN 8 + 2 +#define SILC_PACKET_HEADER_LEN 10 /* Minimum length of SILC Packet Header. This much is decrypted always when packet is received to be able to get all the relevant data out from the header. */ -#define SILC_PACKET_MIN_HEADER_LEN 16 + 2 +#define SILC_PACKET_MIN_HEADER_LEN 16 /* Maximum padding length */ #define SILC_PACKET_MAX_PADLEN 16 @@ -227,6 +227,10 @@ typedef struct { int users; uint32 sequence; + + /* XXX backwards support for 0.5.c + XXX remove in 0.7.x */ + bool back; } SilcPacketContext; /****s* silccore/SilcPacketAPI/SilcPacketParserContext @@ -237,10 +241,11 @@ typedef struct { * * DESCRIPTION * - * This context is used in packet reception when silc_packet_receive_process - * function calls parser callback that performs the actual packet decryption - * and parsing. This context is sent as argument to the parser function. - * This context must be free'd by the parser callback function. + * This context is used in packet reception when the function + * silc_packet_receive_process calls parser callback that performs + * the actual packet decryption and parsing. This context is sent as + * argument to the parser function. This context must be free'd by + * the parser callback function. * * Following description of the fields: * @@ -250,6 +255,11 @@ typedef struct { * context is not parsed, only the packet->buffer is allocated and * it includes the raw packet data, which is encrypted. * + * bool normal + * + * Indicates whether the received packet is normal or special packet. + * If special the parsing process is special also. + * * SilcSocketConnection sock * * The associated connection. @@ -263,6 +273,7 @@ typedef struct { ***/ typedef struct { SilcPacketContext *packet; + bool normal; SilcSocketConnection sock; void *context; } SilcPacketParserContext; @@ -286,41 +297,7 @@ typedef struct { * ***/ typedef void (*SilcPacketParserCallback)(SilcPacketParserContext - *parse_context); - -/****f* silccore/SilcPacketAPI/SilcPacketCheckDecrypt - * - * SYNOPSIS - * - * typedef int (*SilcPacketCheckDecrypt)(SilcPacketType packet_type, - * SilcBuffer buffer, - * SilcPacketContext *packet, - * void *context); - * - * DESCRIPTION - * - * This callback function relates to the checking whether the packet is - * normal packet or special packet and how it should be processed. If - * the callback returns TRUE the packet is normal and FALSE if the packet - * is special and requires special procesing. Some of the packets in - * SILC are special (like channel message packets that are encrypted - * using channel specific keys) and requires special processing. That - * is the reason for this callback function. - * - * The library will call this function if provided for the - * silc_packet_decrypt function. The `packet_type' is the type of - * packet received (this is also actually the first time application - * receives information of the received packet, next time it receives - * it is when the SilcPacketParserCallback function is called), - * the `buffer' is the raw packet data the `packet' the allocated - * SilcPacketContext that is filled when parsing the packet and `context' - * is application specific user context. - * - ***/ -typedef int (*SilcPacketCheckDecrypt)(SilcPacketType packet_type, - SilcBuffer buffer, - SilcPacketContext *packet, - void *context); + *parse_context, void *context); /* Macros */ @@ -332,17 +309,15 @@ typedef int (*SilcPacketCheckDecrypt)(SilcPacketType packet_type, * * DESCRIPTION * - * Returns true length of the packet and padded length of the packet. - * This is primarily used by the libary in packet parsing phase but - * the application may use it as well if needed. + * Returns true length of the packet. This is primarily used by the + * libary in packet parsing phase but the application may use it as + * well if needed. * * SOURCE */ -#define SILC_PACKET_LENGTH(__packet, __ret_truelen, __ret_padlen) \ -do { \ - SILC_GET16_MSB((__ret_truelen), (__packet)->data); \ - (__ret_padlen) = (((__ret_truelen) - 2) + \ - SILC_PACKET_MAX_PADLEN) & ~(SILC_PACKET_MAX_PADLEN - 1); \ +#define SILC_PACKET_LENGTH(__packet, __ret_truelen) \ +do { \ + SILC_GET16_MSB((__ret_truelen), (__packet)->data); \ } while(0) /***/ @@ -359,10 +334,17 @@ do { \ * * SOURCE */ -#define SILC_PACKET_PADLEN(__packetlen) \ - SILC_PACKET_MAX_PADLEN - ((__packetlen) - 2) % SILC_PACKET_MAX_PADLEN; +#define SILC_PACKET_PADLEN(__packetlen, __blocklen) \ + SILC_PACKET_MAX_PADLEN - (__packetlen) % \ + ((__blocklen) ? (__blocklen) : SILC_PACKET_MAX_PADLEN) /***/ +/* XXX Backwards support for 0.5.x + XXX Remove in 0.7.x */ +#define SILC_PACKET_PADLEN2(__packetlen, __blocklen) \ + SILC_PACKET_MAX_PADLEN - ((__packetlen) - 2 ) % \ + ((__blocklen) ? (__blocklen) : SILC_PACKET_MAX_PADLEN) + /* Prototypes */ /****f* silccore/SilcPacketAPI/silc_packet_send @@ -401,7 +383,7 @@ int silc_packet_send(SilcSocketConnection sock, bool force_send); * cannot be used. * ***/ -void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, +void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, uint32 sequence, SilcBuffer buffer, uint32 len); /****f* silccore/SilcPacketAPI/silc_packet_assemble @@ -457,7 +439,7 @@ void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, * the packet. * ***/ -void silc_packet_assemble(SilcPacketContext *ctx); +void silc_packet_assemble(SilcPacketContext *ctx, SilcCipher cipher); /****f* silccore/SilcPacketAPI/silc_packet_send_prepare * @@ -499,60 +481,38 @@ void silc_packet_send_prepare(SilcSocketConnection sock, ***/ int silc_packet_receive(SilcSocketConnection sock); -/****f* silccore/SilcPacketAPI/silc_packet_decrypt - * - * SYNOPSIS - * - * int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac, - * SilcBuffer buffer, SilcPacketContext *packet, - * SilcPacketCheckDecrypt check_packet, - * void *context); - * - * DESCRIPTION - * - * Decrypts a packet. This assumes that typical SILC packet is the - * packet to be decrypted and thus checks for normal and special SILC - * packets and can handle both of them. This also computes and checks - * the HMAC of the packet. If any other special or customized decryption - * processing is required this function cannot be used. This returns - * -1 on error, 0 when packet is normal packet and 1 when the packet - * is special and requires special processing. - * - * The `check_packet' is a callback funtion that this function will - * call. The callback relates to the checking whether the packet is - * normal packet or special packet and how it should be processed. If - * the callback return TRUE the packet is normal and FALSE if the packet - * is special and requires special procesing. - * - ***/ -int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac, - SilcBuffer buffer, SilcPacketContext *packet, - SilcPacketCheckDecrypt check_packet, - void *context); - /****f* silccore/SilcPacketAPI/silc_packet_receive_process * * SYNOPSIS * * void silc_packet_receive_process(SilcSocketConnection sock, + * bool local_is_router, * SilcCipher cipher, SilcHmac hmac, * SilcPacketParserCallback parser, - * void *context); + * void *parser_context); * * DESCRIPTION * - * Processes the received data. This checks the received data and - * calls parser callback that handles the actual packet decryption - * and parsing. If more than one packet was received this calls the - * parser multiple times. The parser callback will get context - * SilcPacketParserContext that includes the packet and the `context' - * sent to this function. + * Processes and decrypts the incmoing data, and calls parser callback + * for each received packet that will handle the actual packet parsing. + * If more than one packet was received this calls the parser multiple + * times. The parser callback will get context SilcPacketParserContext + * that includes the packet and the `parser_context' sent to this + * function. + * + * The `local_is_router' indicates whether the caller is router server + * in which case the receiving process of a certain packet types may + * be special. Normal server and client must set it to FALSE. The + * SilcPacketParserContext will indicate also whether the received + * packet was normal or special packet. * ***/ void silc_packet_receive_process(SilcSocketConnection sock, + bool local_is_router, SilcCipher cipher, SilcHmac hmac, + uint32 sequence, SilcPacketParserCallback parser, - void *context); + void *parser_context); /****f* silccore/SilcPacketAPI/silc_packet_parse * @@ -569,7 +529,7 @@ void silc_packet_receive_process(SilcSocketConnection sock, * buffer is parsed, not head or tail sections. * ***/ -SilcPacketType silc_packet_parse(SilcPacketContext *ctx); +SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher); /****f* silccore/SilcPacketAPI/silc_packet_parse_special * @@ -586,7 +546,8 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx); * and parses the header and padding area only. * ***/ -SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx); +SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx, + SilcCipher cipher); /****f* silccore/SilcPacketAPI/silc_packet_context_alloc * diff --git a/lib/silccore/silcprivate.c b/lib/silccore/silcprivate.c index c828a8f7..64c6f4d9 100644 --- a/lib/silccore/silcprivate.c +++ b/lib/silccore/silcprivate.c @@ -90,7 +90,7 @@ SilcBuffer silc_private_message_payload_encode(uint16 flags, { int i; SilcBuffer buffer; - uint32 len, pad_len = 0; + uint32 len, pad_len = 0, block_len; unsigned char pad[SILC_PACKET_MAX_PADLEN]; SILC_LOG_DEBUG(("Encoding private message payload")); @@ -99,7 +99,8 @@ SilcBuffer silc_private_message_payload_encode(uint16 flags, if (cipher) { /* Calculate length of padding. */ - pad_len = SILC_PACKET_PADLEN((len + 2)); + block_len = silc_cipher_get_block_len(cipher); + pad_len = SILC_PACKET_PADLEN(len, block_len); len += pad_len; /* Generate padding */ diff --git a/lib/silccrypt/silccipher.h b/lib/silccrypt/silccipher.h index 709c8411..fb3ec257 100644 --- a/lib/silccrypt/silccipher.h +++ b/lib/silccrypt/silccipher.h @@ -64,6 +64,10 @@ typedef struct SilcCipherStruct { void *context; unsigned char iv[SILC_CIPHER_MAX_IV_SIZE]; + /* XXX Backwards support for 0.5.x + XXX Remove in 0.7.x */ + bool back; + void (*set_iv)(struct SilcCipherStruct *, const unsigned char *); void (*get_iv)(struct SilcCipherStruct *, unsigned char *); uint32 (*get_key_len)(struct SilcCipherStruct *); diff --git a/lib/silccrypt/silchmac.c b/lib/silccrypt/silchmac.c index 77dce315..6293cea6 100644 --- a/lib/silccrypt/silchmac.c +++ b/lib/silccrypt/silchmac.c @@ -32,6 +32,10 @@ struct SilcHmacStruct { unsigned char inner_pad[64]; unsigned char outer_pad[64]; void *hash_context; + + /* XXX backwards thingy for 0.5.x MAC computation. + XXX Remove in 0.7.x */ + bool backwards_support; }; /* List of dynamically registered HMACs. */ @@ -394,3 +398,13 @@ void silc_hmac_final(SilcHmac hmac, unsigned char *return_hash, if (return_len) *return_len = hmac->hmac->len; } + +void silc_hmac_set_b(SilcHmac hmac) +{ + hmac->backwards_support = TRUE; +} + +bool silc_hmac_get_b(SilcHmac hmac) +{ + return hmac->backwards_support; +} diff --git a/lib/silccrypt/silchmac.h b/lib/silccrypt/silchmac.h index 286ccdf8..a94d2b16 100644 --- a/lib/silccrypt/silchmac.h +++ b/lib/silccrypt/silchmac.h @@ -415,4 +415,7 @@ void silc_hmac_update(SilcHmac hmac, const unsigned char *data, void silc_hmac_final(SilcHmac hmac, unsigned char *return_hash, uint32 *return_len); +void silc_hmac_set_b(SilcHmac hmac); +bool silc_hmac_get_b(SilcHmac hmac); + #endif diff --git a/lib/silcske/silcske.c b/lib/silcske/silcske.c index cacdb3d6..0a56e96c 100644 --- a/lib/silcske/silcske.c +++ b/lib/silcske/silcske.c @@ -1813,13 +1813,19 @@ silc_ske_process_key_material_data(unsigned char *data, 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); @@ -1856,6 +1862,14 @@ SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, req_hmac_key_len, ske->prop->hash, key); + /* Backwards support for old MAC keys */ + /* XXX Remove in 0.7.x */ + if (ske->backward_version == 1) { + silc_free(key->receive_hmac_key); + key->receive_hmac_key = silc_calloc(1, sizeof(*key->receive_hmac_key)); + memcpy(key->receive_hmac_key, key->send_hmac_key, key->hmac_key_len); + } + memset(tmpbuf, 0, klen); silc_free(tmpbuf); silc_buffer_free(buf); @@ -1882,9 +1896,13 @@ void silc_ske_free_key_material(SilcSKEKeyMaterial *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); + 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); } diff --git a/lib/silcske/silcske.h b/lib/silcske/silcske.h index 62c221c0..85c78657 100644 --- a/lib/silcske/silcske.h +++ b/lib/silcske/silcske.h @@ -101,7 +101,8 @@ typedef struct { unsigned char *send_enc_key; unsigned char *receive_enc_key; uint32 enc_key_len; - unsigned char *hmac_key; + unsigned char *send_hmac_key; + unsigned char *receive_hmac_key; uint32 hmac_key_len; } SilcSKEKeyMaterial; @@ -178,6 +179,9 @@ struct SilcSKEStruct { /* SKE callbacks. */ SilcSKECallbacks callbacks; + + /* Backwards support version indicator */ + uint32 backward_version; }; /* Prototypes */ -- 2.24.0