5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
19 /* Implementation of the Message Payload used as channel messages and
23 #include "silcincludes.h"
24 #include "silcmessage.h"
26 /******************************************************************************
30 ******************************************************************************/
32 /* Calculates padding length for message payload */
33 #define SILC_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16))
35 /* Header length plus maximum padding length */
36 #define SILC_MESSAGE_HLEN 6 + 16
38 /* Returns the data length that fits to the packet. If data length is too
39 big it will be truncated to fit to the payload. */
40 #define SILC_MESSAGE_DATALEN(data_len, header_len) \
41 ((data_len + SILC_MESSAGE_HLEN + header_len) > \
42 SILC_PACKET_MAX_LEN ? \
43 data_len - ((data_len + SILC_MESSAGE_HLEN + header_len) - \
44 SILC_PACKET_MAX_LEN) : data_len)
46 /* Message Payload structure. Contents of this structure is parsed
48 struct SilcMessagePayloadStruct {
49 SilcMessageFlags flags;
57 SilcMessageSignedPayload sig;
60 /* Decrypts the Message Payload. The `data' is the actual Message Payload */
62 bool silc_message_payload_decrypt(unsigned char *data,
70 SilcUInt32 mac_len, iv_len = 0, block_len, pad_len;
71 unsigned char mac[32];
75 mac_len = silc_hmac_len(hmac);
76 block_len = silc_cipher_get_block_len(cipher);
78 /* IV is present for all channel messages, and private messages when
79 static key (pre-shared key) is used. */
80 if (!private_message || (private_message && static_key))
81 iv_len = silc_cipher_get_block_len(cipher);
83 if (data_len < mac_len)
87 /* Check the MAC of the message */
88 SILC_LOG_DEBUG(("Checking message MAC"));
90 silc_hmac_update(hmac, data, data_len - mac_len);
91 silc_hmac_final(hmac, mac, &mac_len);
92 if (memcmp(data + (data_len - mac_len), mac, mac_len)) {
93 SILC_LOG_DEBUG(("Message MAC does not match"));
96 SILC_LOG_DEBUG(("MAC is Ok"));
99 /* Get pointer to the IV */
100 ivp = (iv_len ? data + (data_len - iv_len - mac_len) :
101 silc_cipher_get_iv(cipher));
103 /* Decrypt first block to get data length. We need to do this since
104 there might be extra data at the end of the payload which is not
105 encrypted (like the signature payload). */
106 silc_cipher_decrypt(cipher, data, data, block_len, ivp);
108 /* Decrypt rest of the message according to the length of data */
109 SILC_GET16_MSB(len, data + 2);
110 pad_len = SILC_MESSAGE_PAD(6 + len);
111 if (6 + len + pad_len > block_len &&
112 6 + len + pad_len + mac_len + iv_len <= data_len)
113 silc_cipher_decrypt(cipher, data + block_len, data + block_len,
114 (6 + len + pad_len) - block_len, ivp);
119 /* Parses Message Payload returning new payload structure. This also
120 decrypts it and checks the MAC. */
123 silc_message_payload_parse(unsigned char *payload,
124 SilcUInt32 payload_len,
125 bool private_message,
130 SilcBufferStruct buffer;
131 SilcMessagePayload newp;
133 SilcUInt32 mac_len = 0, iv_len = 0;
135 SILC_LOG_DEBUG(("Parsing Message Payload"));
137 silc_buffer_set(&buffer, payload, payload_len);
139 /* Decrypt the payload */
141 ret = silc_message_payload_decrypt(buffer.data, buffer.len,
142 private_message, static_key,
149 mac_len = silc_hmac_len(hmac);
151 /* IV is present for all channel messages, and private messages when
152 static key (pre-shared key) is used. */
153 if (cipher && (!private_message || (private_message && static_key)))
154 iv_len = silc_cipher_get_block_len(cipher);
156 newp = silc_calloc(1, sizeof(*newp));
160 /* Parse the Message Payload. */
161 ret = silc_buffer_unformat(&buffer,
162 SILC_STR_UI_SHORT(&newp->flags),
163 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
165 SILC_STR_UI16_NSTRING_ALLOC(&newp->pad,
171 if ((newp->data_len > buffer.len - 6 - mac_len - iv_len) ||
172 (newp->pad_len + newp->data_len > buffer.len - 6 - mac_len - iv_len)) {
173 SILC_LOG_ERROR(("Incorrect Message Payload in packet"));
177 /* Parse Signed Message Payload if provided */
178 if (newp->flags & SILC_MESSAGE_FLAG_SIGNED &&
179 newp->data_len + newp->pad_len + 6 + mac_len + iv_len < buffer.len) {
181 silc_message_signed_payload_parse(buffer.data + 6 + newp->data_len +
183 buffer.len - iv_len - mac_len);
186 /* Parse IV and MAC from the payload */
188 newp->iv = buffer.data + (buffer.len - iv_len - mac_len);
189 newp->iv_len = iv_len;
192 newp->mac = buffer.data + (buffer.len - mac_len);
197 silc_message_payload_free(newp);
201 /* This function is used to encrypt the Messsage Payload which is
202 the `data' and `data_len'. This is used internally by the Message
203 Payload encoding routines but application may call this too if needed.
204 The `true_len' is the data length which is used to create MAC out of. */
206 bool silc_message_payload_encrypt(unsigned char *data,
214 unsigned char mac[32];
216 SilcBufferStruct buf;
218 /* Encrypt payload of the packet. If the IV is added to packet do
220 silc_cipher_encrypt(cipher, data, data, data_len, iv_len ? iv : NULL);
222 /* Compute the MAC of the encrypted message data */
223 silc_hmac_init(hmac);
224 silc_hmac_update(hmac, data, true_len);
225 silc_hmac_final(hmac, mac, &mac_len);
227 /* Put rest of the data to the payload */
228 silc_buffer_set(&buf, data, true_len + mac_len);
229 silc_buffer_pull(&buf, true_len);
230 silc_buffer_put(&buf, mac, mac_len);
235 /* Encodes Message Payload into a buffer and returns it. */
237 SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
238 const unsigned char *data,
241 bool private_message,
245 SilcPublicKey public_key,
246 SilcPrivateKey private_key,
251 SilcUInt32 len, pad_len = 0, mac_len = 0, iv_len = 0;
252 unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE];
253 SilcBuffer sig = NULL;
255 SILC_LOG_DEBUG(("Encoding Message Payload"));
260 /* For channel messages IV is always generated */
261 if (!private_message && !generate_iv)
265 if (cipher && generate_iv) {
266 iv_len = silc_cipher_get_block_len(cipher);
268 for (i = 0; i < iv_len; i++) iv[i] = silc_rng_get_byte_fast(rng);
270 for (i = 0; i < iv_len; i++) iv[i] = silc_rng_global_get_byte_fast();
275 mac_len = silc_hmac_len(hmac);
276 data_len = SILC_MESSAGE_DATALEN(data_len, mac_len + iv_len);
278 /* Calculate length of padding. IV is not included into the calculation
279 since it is not encrypted. */
281 pad_len = SILC_MESSAGE_PAD(len);
283 /* Allocate payload buffer */
284 len += pad_len + iv_len + mac_len;
285 buffer = silc_buffer_alloc(len);
289 /* Generate padding */
292 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
294 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
298 /* Encode the Message Payload */
299 silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
300 silc_buffer_format(buffer,
301 SILC_STR_UI_SHORT(flags),
302 SILC_STR_UI_SHORT(data_len),
303 SILC_STR_UI_XNSTRING(data, data_len),
304 SILC_STR_UI_SHORT(pad_len),
305 SILC_STR_UI_XNSTRING(pad, pad_len),
308 memset(pad, 0, sizeof(pad));
310 /* Sign the message if wanted */
311 if (flags & SILC_MESSAGE_FLAG_SIGNED && private_key && hash) {
312 sig = silc_message_signed_payload_encode(buffer->data, buffer->len,
313 public_key, private_key, hash);
315 buffer = silc_buffer_realloc(buffer, buffer->truelen + sig->len);
317 silc_buffer_pull(buffer, 6 + data_len + pad_len);
318 silc_buffer_pull_tail(buffer, sig->len);
319 silc_buffer_put(buffer, sig->data, sig->len);
320 silc_buffer_push(buffer, 6 + data_len + pad_len);
326 silc_buffer_pull(buffer, 6 + data_len + pad_len + (sig ? sig->len : 0));
327 silc_buffer_pull_tail(buffer, iv_len);
328 silc_buffer_format(buffer,
329 SILC_STR_UI_XNSTRING(iv, iv_len),
331 silc_buffer_push(buffer, 6 + data_len + pad_len + (sig ? sig->len : 0));
333 SILC_LOG_HEXDUMP(("foo"), buffer->data, buffer->len);
335 /* Now encrypt the Message Payload and compute MAC */
337 if (!silc_message_payload_encrypt(buffer->data,
338 buffer->len - iv_len -
339 (sig ? sig->len : 0),
340 buffer->len, iv, iv_len,
342 silc_buffer_free(buffer);
343 silc_buffer_free(sig);
347 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
349 silc_buffer_free(sig);
353 /* Free's Message Payload */
355 void silc_message_payload_free(SilcMessagePayload payload)
358 memset(payload->data, 0, payload->data_len);
359 silc_free(payload->data);
362 silc_message_signed_payload_free(payload->sig);
363 silc_free(payload->pad);
369 SilcMessageFlags silc_message_get_flags(SilcMessagePayload payload)
371 return payload->flags;
376 unsigned char *silc_message_get_data(SilcMessagePayload payload,
377 SilcUInt32 *data_len)
380 *data_len = payload->data_len;
381 return payload->data;
384 /* Return MAC. The caller knows the length of the MAC */
386 unsigned char *silc_message_get_mac(SilcMessagePayload payload)
391 /* Return IV. The caller knows the length of the IV */
393 unsigned char *silc_message_get_iv(SilcMessagePayload payload)
398 /* Return signature of the message */
400 const SilcMessageSignedPayload
401 silc_message_get_signature(SilcMessagePayload payload)
403 return (const SilcMessageSignedPayload)payload->sig;
406 /******************************************************************************
408 SILC_MESSAGE_FLAG_SIGNED Payload
410 ******************************************************************************/
412 /* The SILC_MESSAGE_FLAG_SIGNED Payload */
413 struct SilcMessageSignedPayloadStruct {
417 unsigned char *pk_data;
418 unsigned char *sign_data;
421 /* Encodes the data to be signed to SILC_MESSAGE_FLAG_SIGNED Payload */
424 silc_message_signed_encode_data(const unsigned char *message_payload,
425 SilcUInt32 message_payload_len,
427 SilcUInt32 pk_len, SilcUInt32 pk_type)
431 sign = silc_buffer_alloc_size(message_payload_len + 4 + pk_len);
435 silc_buffer_format(sign,
436 SILC_STR_UI_XNSTRING(message_payload,
437 message_payload_len),
438 SILC_STR_UI_SHORT(pk_len),
439 SILC_STR_UI_SHORT(pk_type),
443 silc_buffer_pull(sign, message_payload_len + 4);
444 silc_buffer_format(sign,
445 SILC_STR_UI_XNSTRING(pk, pk_len),
447 silc_buffer_push(sign, message_payload_len + 4);
453 /* Parses the SILC_MESSAGE_FLAG_SIGNED Payload */
455 SilcMessageSignedPayload
456 silc_message_signed_payload_parse(const unsigned char *data,
459 SilcMessageSignedPayload sig;
460 SilcBufferStruct buffer;
463 SILC_LOG_DEBUG(("Parsing SILC_MESSAGE_FLAG_SIGNED Payload"));
465 SILC_LOG_HEXDUMP(("sig payload"), (unsigned char *)data, data_len);
467 silc_buffer_set(&buffer, (unsigned char *)data, data_len);
468 sig = silc_calloc(1, sizeof(*sig));
472 /* Parse the payload */
473 ret = silc_buffer_unformat(&buffer,
474 SILC_STR_UI_SHORT(&sig->pk_len),
475 SILC_STR_UI_SHORT(&sig->pk_type),
477 if (ret == -1 || sig->pk_len > data_len - 4) {
478 silc_message_signed_payload_free(sig);
479 SILC_LOG_DEBUG(("Malformed public key in SILC_MESSAGE_FLAG_SIGNED "
484 silc_buffer_pull(&buffer, 4);
485 ret = silc_buffer_unformat(&buffer,
486 SILC_STR_UI_XNSTRING_ALLOC(&sig->pk_data,
488 SILC_STR_UI16_NSTRING_ALLOC(&sig->sign_data,
492 silc_message_signed_payload_free(sig);
493 SILC_LOG_DEBUG(("Malformed SILC_MESSAGE_FLAG_SIGNED Payload"));
496 silc_buffer_push(&buffer, 4);
498 /* Signature must be provided */
499 if (sig->sign_len < 1) {
500 SILC_LOG_DEBUG(("Malformed signature in SILC_MESSAGE_SIGNED_PAYLOAD "
502 silc_message_signed_payload_free(sig);
509 /* Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the digital
513 silc_message_signed_payload_encode(const unsigned char *message_payload,
514 SilcUInt32 message_payload_len,
515 SilcPublicKey public_key,
516 SilcPrivateKey private_key,
519 SilcBuffer buffer, sign;
521 unsigned char auth_data[2048];
523 unsigned char *pk = NULL;
524 SilcUInt32 pk_len = 0;
527 if (!message_payload || !message_payload_len || !private_key || !hash)
531 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
533 /* Now we support only SILC style public key */
534 pk_type = SILC_SKE_PK_TYPE_SILC;
536 /* Encode the data to be signed */
537 sign = silc_message_signed_encode_data(message_payload,
539 pk, pk_len, pk_type);
545 /* Sign the buffer */
547 /* Allocate PKCS object */
548 if (!silc_pkcs_alloc(private_key->name, &pkcs)) {
549 SILC_LOG_ERROR(("Could not allocated PKCS"));
550 silc_buffer_clear(sign);
551 silc_buffer_free(sign);
555 silc_pkcs_private_key_set(pkcs, private_key);
557 /* Compute the hash and the signature. */
558 if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
559 !silc_pkcs_sign_with_hash(pkcs, hash, sign->data, sign->len, auth_data,
561 SILC_LOG_ERROR(("Could not compute signature"));
562 silc_buffer_clear(sign);
563 silc_buffer_free(sign);
564 silc_pkcs_free(pkcs);
569 /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */
571 buffer = silc_buffer_alloc_size(4 + pk_len + 2 + auth_len);
573 silc_buffer_clear(sign);
574 silc_buffer_free(sign);
575 silc_pkcs_free(pkcs);
576 memset(auth_data, 0, sizeof(auth_data));
581 silc_buffer_format(buffer,
582 SILC_STR_UI_SHORT(pk_len),
583 SILC_STR_UI_SHORT(pk_type),
587 silc_buffer_pull(buffer, 4);
588 silc_buffer_format(buffer,
589 SILC_STR_UI_XNSTRING(pk, pk_len),
591 silc_buffer_push(buffer, 4);
594 silc_buffer_pull(buffer, 4 + pk_len);
595 silc_buffer_format(buffer,
596 SILC_STR_UI_SHORT(auth_len),
597 SILC_STR_UI_XNSTRING(auth_data, auth_len),
599 silc_buffer_push(buffer, 4 + pk_len);
601 SILC_LOG_HEXDUMP(("sig payload"), buffer->data, buffer->len);
603 memset(auth_data, 0, sizeof(auth_data));
604 silc_pkcs_free(pkcs);
605 silc_buffer_clear(sign);
606 silc_buffer_free(sign);
612 /* Free the payload */
614 void silc_message_signed_payload_free(SilcMessageSignedPayload sig)
616 memset(sig->sign_data, 0, sig->sign_len);
617 silc_free(sig->sign_data);
618 silc_free(sig->pk_data);
622 /* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */
624 int silc_message_signed_verify(SilcMessageSignedPayload sig,
625 SilcMessagePayload message,
626 SilcPublicKey remote_public_key,
629 int ret = SILC_AUTH_FAILED;
634 if (!sig || !remote_public_key || !hash)
637 /* Generate the signature verification data, the Message Payload */
638 tmp = silc_buffer_alloc_size(6 + message->data_len + message->pad_len);
639 silc_buffer_format(tmp,
640 SILC_STR_UI_SHORT(message->flags),
641 SILC_STR_UI_SHORT(message->data_len),
642 SILC_STR_UI_XNSTRING(message->data, message->data_len),
643 SILC_STR_UI_SHORT(message->pad_len),
644 SILC_STR_UI_XNSTRING(message->pad, message->pad_len),
646 sign = silc_message_signed_encode_data(tmp->data, tmp->len,
647 sig->pk_data, sig->pk_len,
649 silc_buffer_clear(tmp);
650 silc_buffer_free(tmp);
655 /* Allocate PKCS object */
656 if (!silc_pkcs_alloc(remote_public_key->name, &pkcs)) {
657 silc_buffer_clear(sign);
658 silc_buffer_free(sign);
661 silc_pkcs_public_key_set(pkcs, remote_public_key);
663 /* Verify the authentication data */
664 if (!silc_pkcs_verify_with_hash(pkcs, hash, sig->sign_data,
666 sign->data, sign->len)) {
668 silc_buffer_clear(sign);
669 silc_buffer_free(sign);
670 silc_pkcs_free(pkcs);
671 SILC_LOG_DEBUG(("Signature verification failed"));
677 silc_buffer_clear(sign);
678 silc_buffer_free(sign);
679 silc_pkcs_free(pkcs);
681 SILC_LOG_DEBUG(("Signature verification successful"));
686 /* Return the public key from the payload */
689 silc_message_signed_get_public_key(SilcMessageSignedPayload sig)
693 if (!sig->pk_data || !silc_pkcs_public_key_decode(sig->pk_data,