+Tue Oct 16 20:45:49 EDT 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * 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 <priikone@silcnet.org>
* Allow backup router to announce servers. All servers
}
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);
}
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 */
/* 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
/* 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
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);
/* 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
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))
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;
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,
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 */
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));
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;
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,
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 */
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 */
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 */
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 +
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 */
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. */
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);
}
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);
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);
}
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. */
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);
}
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);
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);
}
SilcSocketConnection dst_sock,
SilcCipher cipher,
SilcHmac hmac,
+ uint32 sequence,
SilcPacketContext *packet)
{
SilcBuffer buffer = packet->buffer;
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);
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);
uint32 data_len;
bool force_send = FALSE;
va_list ap;
+ int block_len;
SILC_LOG_DEBUG(("Start"));
/* 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);
/* 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);
SilcSocketConnection dst_sock,
SilcCipher cipher,
SilcHmac hmac,
+ uint32 sequence,
SilcPacketContext *packet,
bool force_send)
{
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);
SilcSocketConnection dst_sock,
SilcCipher cipher,
SilcHmac hmac,
+ uint32 sequence,
SilcPacketContext *packet);
void silc_server_send_motd(SilcServer server,
SilcSocketConnection sock);
SilcSocketConnection dst_sock,
SilcCipher cipher,
SilcHmac hmac,
+ uint32 sequence,
SilcPacketContext *packet,
bool force_send);
void silc_server_send_connection_auth_request(SilcServer server,
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);
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);
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));
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;
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;
}
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);
SilcIDListData idata;
SilcCipher cipher = NULL;
SilcHmac hmac = NULL;
+ uint32 sequence = 0;
int ret;
if (!sock)
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. */
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 &&
/* 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:
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);
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 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
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
.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
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.
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.
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.
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);
/* 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)
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;
/* 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,
int force_send)
{
SilcPacketContext packetdata;
+ int block_len;
+ uint32 sequence = 0;
if (!sock)
return;
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;
}
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,
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);
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)
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
SilcHmac hmac;
unsigned char *id_string;
uint32 iv_len;
+ int block_len;
SILC_LOG_DEBUG(("Sending packet to channel"));
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')
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,
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);
SilcPacketContext packetdata;
SilcCipher cipher;
SilcHmac hmac;
+ int block_len;
SILC_LOG_DEBUG(("Sending private message"));
/* 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;
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,
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);
/* 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));
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);
}
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);
{
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];
/* 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;
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];
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 */
^ ^
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
*/
-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"));
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 +
******************************************************************************/
-/* 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);
}
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;
}
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);
{
/* 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) {
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;
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;
return -1;
/* Check MAC */
- if (!silc_packet_check_mac(hmac, buffer))
+ if (!silc_packet_check_mac(hmac, buffer, sequence))
return -1;
return 1;
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"));
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,
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),
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"));
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;
}
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,
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);
#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
int users;
uint32 sequence;
+
+ /* XXX backwards support for 0.5.c
+ XXX remove in 0.7.x */
+ bool back;
} SilcPacketContext;
/****s* silccore/SilcPacketAPI/SilcPacketParserContext
*
* 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:
*
* 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.
***/
typedef struct {
SilcPacketContext *packet;
+ bool normal;
SilcSocketConnection sock;
void *context;
} SilcPacketParserContext;
*
***/
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 */
*
* 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)
/***/
*
* 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
* 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
* the packet.
*
***/
-void silc_packet_assemble(SilcPacketContext *ctx);
+void silc_packet_assemble(SilcPacketContext *ctx, SilcCipher cipher);
/****f* silccore/SilcPacketAPI/silc_packet_send_prepare
*
***/
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
*
* 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
*
* 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
*
{
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"));
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 */
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 *);
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. */
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;
+}
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
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);
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);
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);
}
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;
/* SKE callbacks. */
SilcSKECallbacks callbacks;
+
+ /* Backwards support version indicator */
+ uint32 backward_version;
};
/* Prototypes */