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 = 0, iv_len = 0;
71 unsigned char *mac, mac2[32];
73 mac_len = silc_hmac_len(hmac);
75 /* IV is present for channel messages and private messages when static
76 key (pre-shared key) is used. */
77 if (!private_message || (private_message && static_key))
78 iv_len = silc_cipher_get_block_len(cipher);
80 if (data_len < mac_len)
85 mac = data + (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, mac2, &mac_len);
92 if (memcmp(mac, mac2, mac_len)) {
93 SILC_LOG_DEBUG(("Message MAC does not match"));
96 SILC_LOG_DEBUG(("MAC is Ok"));
99 /* Decrypt the message */
100 silc_cipher_decrypt(cipher, data, data, data_len - iv_len - mac_len,
101 (iv_len ? data + (data_len - iv_len - mac_len) : NULL));
105 /* Parses Message Payload returning new payload structure. This also
106 decrypts it and checks the MAC. */
109 silc_message_payload_parse(unsigned char *payload,
110 SilcUInt32 payload_len,
111 bool private_message,
116 SilcBufferStruct buffer;
117 SilcMessagePayload newp;
119 SilcUInt32 mac_len = 0, iv_len = 0;
121 SILC_LOG_DEBUG(("Parsing Message Payload"));
123 silc_buffer_set(&buffer, payload, payload_len);
125 /* Decrypt the payload */
127 ret = silc_message_payload_decrypt(buffer.data, buffer.len,
128 private_message, static_key,
135 mac_len = silc_hmac_len(hmac);
137 /* IV is present for channel messages and private messages when static
138 key (pre-shared key) is used. */
139 if (cipher && (!private_message || (private_message && static_key)))
140 iv_len = silc_cipher_get_block_len(cipher);
142 newp = silc_calloc(1, sizeof(*newp));
146 /* Parse the Message Payload. */
147 ret = silc_buffer_unformat(&buffer,
148 SILC_STR_UI_SHORT(&newp->flags),
149 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
151 SILC_STR_UI16_NSTRING_ALLOC(&newp->pad,
153 SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
154 SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
159 if ((newp->data_len > buffer.len - 6 - mac_len - iv_len) ||
160 (newp->pad_len + newp->data_len > buffer.len - 6 - mac_len - iv_len)) {
161 SILC_LOG_ERROR(("Incorrect Message Payload in packet"));
165 newp->iv_len = iv_len;
170 silc_message_payload_free(newp);
174 /* This function is used to encrypt the Messsage Payload which is
175 the `data' and `data_len'. This is used internally by the Message
176 Payload encoding routines but application may call this too if needed.
177 The `data_len' is the data lenght which is used to create MAC out of. */
179 bool silc_message_payload_encrypt(unsigned char *data,
186 unsigned char mac[32];
188 SilcBufferStruct buf;
190 /* Encrypt payload of the packet. If the IV is added to packet do
192 silc_cipher_encrypt(cipher, data, data, data_len - iv_len,
195 /* Compute the MAC of the encrypted message data */
196 silc_hmac_init(hmac);
197 silc_hmac_update(hmac, data, data_len);
198 silc_hmac_final(hmac, mac, &mac_len);
200 /* Put rest of the data to the payload */
201 silc_buffer_set(&buf, data, data_len + mac_len);
202 silc_buffer_pull(&buf, data_len);
203 silc_buffer_put(&buf, mac, mac_len);
208 /* Encodes Message Payload into a buffer and returns it. */
210 SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
211 const unsigned char *data,
214 bool private_message,
221 SilcUInt32 len, pad_len = 0, mac_len = 0, iv_len = 0;
222 unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE];
224 SILC_LOG_DEBUG(("Encoding Message Payload"));
229 /* For channel messages IV is always generated */
230 if (!private_message && !generate_iv)
234 if (cipher && generate_iv) {
235 iv_len = silc_cipher_get_block_len(cipher);
237 for (i = 0; i < iv_len; i++) iv[i] = silc_rng_get_byte_fast(rng);
239 for (i = 0; i < iv_len; i++) iv[i] = silc_rng_global_get_byte_fast();
244 mac_len = silc_hmac_len(hmac);
245 data_len = SILC_MESSAGE_DATALEN(data_len, mac_len + iv_len);
247 /* Calculate length of padding. IV is not included into the calculation
248 since it is not encrypted. */
250 pad_len = SILC_MESSAGE_PAD(len);
252 /* Allocate payload buffer */
253 len += pad_len + iv_len + mac_len;
254 buffer = silc_buffer_alloc(len);
258 /* Generate padding */
261 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
263 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
267 /* Encode the Message Payload */
268 silc_buffer_pull_tail(buffer, 6 + data_len + pad_len + iv_len);
269 silc_buffer_format(buffer,
270 SILC_STR_UI_SHORT(flags),
271 SILC_STR_UI_SHORT(data_len),
272 SILC_STR_UI_XNSTRING(data, data_len),
273 SILC_STR_UI_SHORT(pad_len),
274 SILC_STR_UI_XNSTRING(pad, pad_len),
275 SILC_STR_UI_XNSTRING(iv, iv_len),
278 memset(pad, 0, sizeof(pad));
280 /* Now encrypt the Message Payload */
282 if (!silc_message_payload_encrypt(buffer->data, buffer->len,
283 iv, iv_len, cipher, hmac)) {
284 silc_buffer_free(buffer);
288 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
293 /* Free's Message Payload */
295 void silc_message_payload_free(SilcMessagePayload payload)
298 memset(payload->data, 0, payload->data_len);
299 silc_free(payload->data);
301 silc_free(payload->pad);
307 SilcMessageFlags silc_message_get_flags(SilcMessagePayload payload)
309 return payload->flags;
314 unsigned char *silc_message_get_data(SilcMessagePayload payload,
315 SilcUInt32 *data_len)
318 *data_len = payload->data_len;
319 return payload->data;
322 /* Return MAC. The caller knows the length of the MAC */
324 unsigned char *silc_message_get_mac(SilcMessagePayload payload)
329 /* Return IV. The caller knows the length of the IV */
331 unsigned char *silc_message_get_iv(SilcMessagePayload payload)
336 /******************************************************************************
338 SILC_MESSAGE_FLAG_SIGNED Payload
340 ******************************************************************************/
342 /* The SILC_MESSAGE_FLAG_SIGNED Payload */
343 struct SilcMessageSignedPayloadStruct {
347 unsigned char *pk_data;
348 unsigned char *sign_data;
351 /* Encodes the data to be signed to SILC_MESSAGE_FLAG_SIGNED Payload */
354 silc_message_signed_encode_data(const unsigned char *message_payload,
355 SilcUInt32 message_payload_len,
357 SilcUInt32 pk_len, SilcUInt32 pk_type)
361 sign = silc_buffer_alloc_size(message_payload_len + 4 + pk_len);
365 silc_buffer_format(sign,
366 SILC_STR_UI_XNSTRING(message_payload,
367 message_payload_len),
368 SILC_STR_UI_SHORT(pk_len),
369 SILC_STR_UI_SHORT(pk_type),
373 silc_buffer_pull(sign, message_payload_len + 4);
374 silc_buffer_format(sign,
375 SILC_STR_UI_XNSTRING(pk, pk_len),
377 silc_buffer_push(sign, message_payload_len + 4);
383 /* Parses the SILC_MESSAGE_FLAG_SIGNED Payload */
385 SilcMessageSignedPayload
386 silc_message_signed_payload_parse(const unsigned char *data,
389 SilcMessageSignedPayload sig;
390 SilcBufferStruct buffer;
393 SILC_LOG_DEBUG(("Parsing SILC_MESSAGE_FLAG_SIGNED Payload"));
395 silc_buffer_set(&buffer, (unsigned char *)data, data_len);
396 sig = silc_calloc(1, sizeof(*sig));
400 /* Parse the payload */
401 ret = silc_buffer_unformat(&buffer,
402 SILC_STR_UI_SHORT(&sig->pk_len),
403 SILC_STR_UI_SHORT(&sig->pk_type),
405 if (ret == -1 || sig->pk_len > data_len - 4) {
406 silc_message_signed_payload_free(sig);
410 silc_buffer_pull(&buffer, 4);
411 ret = silc_buffer_unformat(&buffer,
412 SILC_STR_UI_XNSTRING_ALLOC(&sig->pk_data,
414 SILC_STR_UI16_NSTRING_ALLOC(&sig->sign_data,
418 silc_message_signed_payload_free(sig);
421 silc_buffer_push(&buffer, 4);
423 /* Signature must be provided */
424 if (sig->sign_len < 1) {
425 silc_message_signed_payload_free(sig);
432 /* Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the digital
436 silc_message_signed_payload_encode(const unsigned char *message_payload,
437 SilcUInt32 message_payload_len,
438 SilcPublicKey public_key,
439 SilcPrivateKey private_key,
441 bool include_public_key)
443 SilcBuffer buffer, sign;
445 unsigned char auth_data[2048];
447 unsigned char *pk = NULL;
448 SilcUInt32 pk_len = 0;
451 if (!message_payload || !message_payload_len || !private_key || !hash)
453 if (include_public_key && !public_key)
456 if (include_public_key)
457 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
459 /* Now we support only SILC style public key */
460 pk_type = SILC_SKE_PK_TYPE_SILC;
462 /* Encode the data to be signed */
463 sign = silc_message_signed_encode_data(message_payload,
465 pk, pk_len, pk_type);
471 /* Sign the buffer */
473 /* Allocate PKCS object */
474 if (!silc_pkcs_alloc(private_key->name, &pkcs)) {
475 silc_buffer_clear(sign);
476 silc_buffer_free(sign);
480 silc_pkcs_private_key_set(pkcs, private_key);
482 /* Compute the hash and the signature. */
483 if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
484 !silc_pkcs_sign_with_hash(pkcs, hash, sign->data, sign->len, auth_data,
486 silc_buffer_clear(sign);
487 silc_buffer_free(sign);
488 silc_pkcs_free(pkcs);
493 /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */
495 buffer = silc_buffer_alloc_size(4 + pk_len + 2 + auth_len);
497 silc_buffer_clear(sign);
498 silc_buffer_free(sign);
499 silc_pkcs_free(pkcs);
500 memset(auth_data, 0, sizeof(auth_data));
505 silc_buffer_format(sign,
506 SILC_STR_UI_SHORT(pk_len),
507 SILC_STR_UI_SHORT(pk_type),
511 silc_buffer_pull(sign, 4);
512 silc_buffer_format(sign,
513 SILC_STR_UI_XNSTRING(pk, pk_len),
515 silc_buffer_push(sign, 4);
518 silc_buffer_pull(sign, 4 + pk_len);
519 silc_buffer_format(sign,
520 SILC_STR_UI_SHORT(auth_len),
521 SILC_STR_UI_XNSTRING(auth_data, auth_len),
523 silc_buffer_push(sign, 4 + pk_len);
525 memset(auth_data, 0, sizeof(auth_data));
526 silc_pkcs_free(pkcs);
527 silc_buffer_clear(sign);
528 silc_buffer_free(sign);
534 /* Free the payload */
536 void silc_message_signed_payload_free(SilcMessageSignedPayload sig)
539 memset(sig->sign_data, 0, sig->sign_len);
540 silc_free(sig->sign_data);
541 silc_free(sig->pk_data);
546 /* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */
548 int silc_message_signed_verify(SilcMessageSignedPayload sig,
549 SilcMessagePayload message,
550 SilcPublicKey remote_public_key,
553 int ret = SILC_AUTH_FAILED;
558 if (!sig || !remote_public_key || !hash)
561 /* Generate the signature verification data, the Message Payload */
562 tmp = silc_buffer_alloc_size(6 + message->data_len + message->pad_len +
564 silc_buffer_format(tmp,
565 SILC_STR_UI_SHORT(message->flags),
566 SILC_STR_UI_SHORT(message->data_len),
567 SILC_STR_UI_XNSTRING(message->data, message->data_len),
568 SILC_STR_UI_SHORT(message->pad_len),
569 SILC_STR_UI_XNSTRING(message->pad, message->pad_len),
570 SILC_STR_UI_XNSTRING(message->iv, message->iv_len),
572 sign = silc_message_signed_encode_data(tmp->data, tmp->len,
573 sig->pk_data, sig->pk_len,
575 silc_buffer_clear(tmp);
576 silc_buffer_free(tmp);
581 /* Allocate PKCS object */
582 if (!silc_pkcs_alloc(remote_public_key->name, &pkcs)) {
583 silc_buffer_clear(sign);
584 silc_buffer_free(sign);
587 silc_pkcs_public_key_set(pkcs, remote_public_key);
589 /* Verify the authentication data */
590 if (!silc_pkcs_verify_with_hash(pkcs, hash, sig->sign_data,
592 sign->data, sign->len)) {
594 silc_buffer_clear(sign);
595 silc_buffer_free(sign);
596 silc_pkcs_free(pkcs);
597 SILC_LOG_DEBUG(("Signature verification failed"));
603 silc_buffer_clear(sign);
604 silc_buffer_free(sign);
605 silc_pkcs_free(pkcs);
607 SILC_LOG_DEBUG(("Signature verification successful"));
612 /* Return the public key from the payload */
615 silc_message_signed_get_public_key(SilcMessageSignedPayload sig)
619 if (!sig->pk_data || !silc_pkcs_public_key_decode(sig->pk_data,