1 /*
2
3 silcmessage.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 1997 - 2007 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* Implementation of the Message Payload used as channel messages and
20 private messages. */
21 /* $Id: silcmessage.c,v 1.30 2007/07/21 17:18:20 priikone Exp $ */
22
23 #include "silc.h"
24 #include "silcmessage.h"
25
26 /*************************** Types and definitions **************************/
27
28 /* Calculates padding length for message payload */
29 #define SILC_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16))
30
31 /* Header length plus maximum padding length */
32 #define SILC_MESSAGE_HLEN 6 + 16
33
34 /* Maximum message length */
35 #define SILC_MESSAGE_MAX_LEN SILC_PACKET_MAX_LEN - SILC_MESSAGE_HLEN - 16
36
37 /* Payload encoding context */
38 typedef struct {
39 SilcBuffer buffer;
40 SilcBuffer sign;
41 SilcStack stack;
42 SilcMessagePayloadEncoded encoded;
43 void *context;
44 SilcMessageFlags flags;
45 SilcPublicKey public_key;
46 SilcPrivateKey private_key;
47 SilcRng rng;
48 SilcHash hash;
49 SilcCipher cipher;
50 SilcHmac hmac;
51 unsigned char *iv;
52 unsigned char *pk;
53 SilcUInt16 pk_len;
54 SilcUInt16 iv_len;
55 SilcUInt16 payload_len;
56 SilcID sid;
57 SilcID rid;
58 } SilcMessageEncode;
59
60
61 /************************* Static utility functions *************************/
62
63 static void
64 silc_message_payload_encode_final(SilcBuffer buffer,
65 SilcMessageFlags flags,
66 SilcCipher cipher,
67 SilcHmac hmac,
68 unsigned char *iv,
69 SilcUInt32 iv_len,
70 SilcUInt32 payload_len,
71 SilcID *sender_id,
72 SilcID *receiver_id,
73 SilcStack stack,
74 SilcBuffer signature,
75 SilcMessagePayloadEncoded encoded,
76 void *context);
77
78 /* Returns the data length that fits to the packet. If data length is too
79 big it will be truncated to fit to the payload. */
80
81 static inline
82 SilcUInt32 silc_message_payload_datalen(SilcUInt32 data_len,
83 SilcUInt32 header_len,
84 SilcUInt32 flags,
85 SilcPublicKey public_key,
86 SilcPrivateKey private_key)
87 {
88 SilcUInt32 pklen = (flags & SILC_MESSAGE_FLAG_SIGNED && public_key ?
89 silc_pkcs_public_key_get_len(public_key) : 0);
90 SilcUInt32 prlen = (flags & SILC_MESSAGE_FLAG_SIGNED ?
91 silc_pkcs_private_key_get_len(private_key) / 8 : 0);
92 SilcUInt32 dlen = data_len + SILC_MESSAGE_HLEN + header_len + pklen + prlen;
93
94 if (silc_unlikely(dlen > SILC_MESSAGE_MAX_LEN))
95 data_len -= (dlen - SILC_MESSAGE_MAX_LEN);
96
97 return data_len;
98 }
99
100 /* Free signed payload */
101
102 static void silc_message_signed_payload_free(SilcMessageSignedPayload sig)
103 {
104 if (sig->sign_data) {
105 memset(sig->sign_data, 0, sig->sign_len);
106 silc_free(sig->sign_data);
107 }
108 silc_free(sig->pk_data);
109 }
110
111 /* Parses the SILC_MESSAGE_FLAG_SIGNED Payload */
112
113 static SilcBool
114 silc_message_signed_payload_parse(const unsigned char *data,
115 SilcUInt32 data_len,
116 SilcMessageSignedPayload sig)
117 {
118 SilcBufferStruct buffer;
119 int ret;
120
121 SILC_LOG_DEBUG(("Parsing SILC_MESSAGE_FLAG_SIGNED Payload"));
122
123 SILC_LOG_HEXDUMP(("sig payload"), (unsigned char *)data, data_len);
124
125 silc_buffer_set(&buffer, (unsigned char *)data, data_len);
126
127 /* Parse the payload */
128 ret = silc_buffer_unformat(&buffer,
129 SILC_STR_UI_SHORT(&sig->pk_len),
130 SILC_STR_UI_SHORT(&sig->pk_type),
131 SILC_STR_END);
132 if (ret == -1 || sig->pk_len > data_len - 4) {
133 SILC_LOG_DEBUG(("Malformed public key in SILC_MESSAGE_FLAG_SIGNED "
134 "Payload"));
135 return FALSE;
136 }
137
138 silc_buffer_pull(&buffer, 4);
139 ret = silc_buffer_unformat(&buffer,
140 SILC_STR_UI_XNSTRING_ALLOC(&sig->pk_data,
141 sig->pk_len),
142 SILC_STR_UI16_NSTRING_ALLOC(&sig->sign_data,
143 &sig->sign_len),
144 SILC_STR_END);
145 if (ret == -1 || sig->sign_len > silc_buffer_len(&buffer) -
146 sig->pk_len - 2) {
147 silc_message_signed_payload_free(sig);
148 SILC_LOG_DEBUG(("Malformed SILC_MESSAGE_FLAG_SIGNED Payload"));
149 return FALSE;
150 }
151 silc_buffer_push(&buffer, 4);
152
153 /* Signature must be provided */
154 if (sig->sign_len < 1) {
155 SILC_LOG_DEBUG(("Malformed signature in SILC_MESSAGE_SIGNED_PAYLOAD "
156 "Payload"));
157 silc_message_signed_payload_free(sig);
158 return FALSE;
159 }
160
161 return TRUE;
162 }
163
164 /* Encodes the data to be signed to SILC_MESSAGE_FLAG_SIGNED Payload */
165
166 static SilcBuffer
167 silc_message_signed_encode_data(SilcStack stack,
168 const unsigned char *message_payload,
169 SilcUInt32 message_payload_len,
170 unsigned char *pk,
171 SilcUInt32 pk_len, SilcUInt32 pk_type)
172 {
173 SilcBuffer sign;
174
175 sign = silc_buffer_salloc_size(stack, message_payload_len + 4 + pk_len);
176 if (!sign)
177 return NULL;
178
179 silc_buffer_sformat(stack, sign,
180 SILC_STR_DATA(message_payload, message_payload_len),
181 SILC_STR_UI_SHORT(pk_len),
182 SILC_STR_UI_SHORT(pk_type),
183 SILC_STR_END);
184
185 if (pk && pk_len) {
186 silc_buffer_pull(sign, message_payload_len + 4);
187 silc_buffer_sformat(stack, sign,
188 SILC_STR_UI_XNSTRING(pk, pk_len),
189 SILC_STR_END);
190 silc_buffer_push(sign, message_payload_len + 4);
191 }
192
193 return sign;
194 }
195
196 /* Signature callback */
197
198 void silc_message_signed_payload_encode_cb(SilcBool success,
199 const unsigned char *signature,
200 SilcUInt32 signature_len,
201 void *context)
202 {
203 SilcMessageEncode *e = context;
204 SilcPKCSType pk_type;
205 SilcStack stack = e->stack;
206 SilcBuffer buffer, payload;
207 SilcMessageFlags flags;
208 SilcCipher cipher;
209 SilcHmac hmac;
210 unsigned char *iv;
211 SilcUInt32 iv_len, payload_len;
212 SilcID *sid, *rid;
213 SilcMessagePayloadEncoded encoded;
214 void *encoded_context;
215
216 if (!success) {
217 e->encoded(NULL, e->context);
218 silc_buffer_sfree(stack, e->sign);
219 silc_sfree(stack, e->pk);
220 silc_sfree(stack, e);
221 silc_stack_free(stack);
222 return;
223 }
224
225 pk_type = silc_pkcs_get_type(e->private_key);
226
227 /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */
228 buffer = silc_buffer_salloc_size(stack, 4 + e->pk_len + 2 + signature_len);
229 if (!buffer) {
230 e->encoded(NULL, e->context);
231 silc_buffer_sfree(stack, e->sign);
232 silc_sfree(stack, e->pk);
233 silc_sfree(stack, e);
234 silc_stack_free(stack);
235 return;
236 }
237
238 silc_buffer_sformat(stack, buffer,
239 SILC_STR_UI_SHORT(e->pk_len),
240 SILC_STR_UI_SHORT(pk_type),
241 SILC_STR_END);
242
243 if (e->pk_len && e->pk) {
244 silc_buffer_pull(buffer, 4);
245 silc_buffer_sformat(stack, buffer,
246 SILC_STR_DATA(e->pk, e->pk_len),
247 SILC_STR_END);
248 silc_buffer_push(buffer, 4);
249 }
250
251 silc_buffer_pull(buffer, 4 + e->pk_len);
252 silc_buffer_sformat(stack, buffer,
253 SILC_STR_UI_SHORT(signature_len),
254 SILC_STR_DATA(signature, signature_len),
255 SILC_STR_END);
256 silc_buffer_push(buffer, 4 + e->pk_len);
257
258 SILC_LOG_HEXDUMP(("SIG payload"), buffer->data, silc_buffer_len(buffer));
259
260 payload = e->buffer;
261 flags = e->flags;
262 cipher = e->cipher;
263 hmac = e->hmac;
264 iv = e->iv;
265 iv_len = e->iv_len;
266 payload_len = e->payload_len;
267 sid = &e->sid;
268 rid = &e->rid;
269 encoded = e->encoded;
270 encoded_context = e->context;
271
272 silc_sfree(stack, e->pk);
273 silc_buffer_sfree(stack, e->sign);
274 silc_sfree(stack, e);
275
276 /* Finalize message payload encoding */
277 silc_message_payload_encode_final(payload, flags, cipher, hmac,
278 iv, iv_len, payload_len,
279 sid, rid, stack, buffer,
280 encoded, encoded_context);
281 }
282
283 /* Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the digital
284 signature. */
285
286 static SilcAsyncOperation
287 silc_message_signed_payload_encode(SilcBuffer payload,
288 SilcMessageEncode *e)
289 {
290 SilcAsyncOperation op;
291 SilcBuffer sign;
292 unsigned char *pk = NULL;
293 SilcUInt32 pk_len = 0;
294 SilcUInt16 pk_type;
295 SilcStack stack = e->stack;
296 SilcRng rng = e->rng;
297 SilcHash hash = e->hash;
298 SilcPublicKey public_key = e->public_key;
299 SilcPrivateKey private_key = e->private_key;
300 unsigned char *message_payload;
301 SilcUInt16 message_payload_len;
302
303 message_payload = payload->head;
304 message_payload_len = silc_buffer_headlen(payload);
305
306 if (!message_payload || !message_payload_len || !private_key || !hash) {
307 e->encoded(NULL, e->context);
308 silc_sfree(stack, e);
309 silc_stack_free(stack);
310 return NULL;
311 }
312
313 if (public_key) {
314 e->pk = pk = silc_pkcs_public_key_encode(stack, public_key, &pk_len);
315 if (!pk) {
316 e->encoded(NULL, e->context);
317 silc_sfree(stack, e);
318 silc_stack_free(stack);
319 return NULL;
320 }
321 e->pk_len = pk_len;
322 }
323 pk_type = silc_pkcs_get_type(private_key);
324
325 /* Encode the data to be signed */
326 e->sign = sign = silc_message_signed_encode_data(stack, message_payload,
327 message_payload_len,
328 pk, pk_len, pk_type);
329 if (!sign) {
330 e->encoded(NULL, e->context);
331 silc_sfree(stack, pk);
332 silc_sfree(stack, e);
333 silc_stack_free(stack);
334 return NULL;
335 }
336
337 /* Compute signature */
338 op = silc_pkcs_sign(private_key, sign->data, silc_buffer_len(sign),
339 TRUE, hash, rng,
340 silc_message_signed_payload_encode_cb, e);
341
342 return op;
343 }
344
345 /***************************** Payload parsing ******************************/
346
347 /* Decrypts the Message Payload. The `data' is the actual Message Payload. */
348
349 SilcBool silc_message_payload_decrypt(unsigned char *data,
350 size_t data_len,
351 SilcBool private_message,
352 SilcBool static_key,
353 SilcCipher cipher,
354 SilcHmac hmac,
355 unsigned char *sender_id,
356 SilcUInt32 sender_id_len,
357 unsigned char *receiver_id,
358 SilcUInt32 receiver_id_len,
359 SilcBool check_mac)
360 {
361 SilcUInt32 mac_len, iv_len = 0, block_len;
362 SilcUInt16 len, totlen;
363 unsigned char mac[32], *ivp;
364
365 mac_len = silc_hmac_len(hmac);
366 block_len = silc_cipher_get_block_len(cipher);
367
368 /* IV is present for all channel messages, and private messages when
369 static key (pre-shared key) is used. */
370 if (!private_message || (private_message && static_key))
371 iv_len = block_len;
372
373 if (silc_unlikely(data_len < (mac_len + iv_len + block_len)))
374 return FALSE;
375
376 if (silc_likely(check_mac)) {
377 /* Check the MAC of the message */
378 SILC_LOG_DEBUG(("Checking message MAC"));
379 silc_hmac_init(hmac);
380 silc_hmac_update(hmac, data, data_len - mac_len);
381 silc_hmac_update(hmac, sender_id, sender_id_len);
382 silc_hmac_update(hmac, receiver_id, receiver_id_len);
383 silc_hmac_final(hmac, mac, &mac_len);
384 if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) {
385 /* Check for old style (version 1.2) message MAC. Remove this check
386 at some point. */
387 silc_hmac_init(hmac);
388 silc_hmac_update(hmac, data, data_len - mac_len);
389 silc_hmac_final(hmac, mac, &mac_len);
390 if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) {
391 SILC_LOG_DEBUG(("Message MAC does not match"));
392 return FALSE;
393 }
394 }
395 SILC_LOG_DEBUG(("MAC is Ok"));
396 }
397
398 /* Decrypt first only one block to get the header and then rest of
399 the data. This is done because there might be unencrypted data at
400 the end and we don't know the encrypted length yet. */
401
402 /* Get pointer to the IV */
403 ivp = (iv_len ? data + (data_len - iv_len - mac_len) :
404 silc_cipher_get_iv(cipher));
405
406 /* Decrypt block */
407 if (silc_unlikely(!silc_cipher_decrypt(cipher, data, data, block_len,
408 ivp))) {
409 SILC_ASSERT(FALSE);
410 return FALSE;
411 }
412
413 /* Get the payload length and decrypt rest */
414 totlen = 2;
415 SILC_GET16_MSB(len, data + totlen);
416 totlen += 2 + len;
417 if (silc_unlikely(totlen + iv_len + mac_len + 2 > data_len))
418 return FALSE;
419 totlen += 2;
420 if (totlen >= block_len)
421 if (silc_unlikely(!silc_cipher_decrypt(cipher, data + block_len,
422 data + block_len,
423 (totlen - block_len) +
424 SILC_MESSAGE_PAD(totlen), ivp))) {
425 SILC_ASSERT(FALSE);
426 return FALSE;
427 }
428
429 return TRUE;
430 }
431
432 /* Parses Message Payload returning new payload structure. This also
433 decrypts it and checks the MAC. */
434
435 SilcMessagePayload
436 silc_message_payload_parse(unsigned char *payload,
437 SilcUInt32 payload_len,
438 SilcBool private_message,
439 SilcBool static_key,
440 SilcCipher cipher,
441 SilcHmac hmac,
442 unsigned char *sender_id,
443 SilcUInt32 sender_id_len,
444 unsigned char *receiver_id,
445 SilcUInt32 receiver_id_len,
446 SilcStack stack,
447 SilcBool no_allocation,
448 SilcMessagePayload message)
449 {
450 SilcBufferStruct buffer;
451 SilcMessagePayload newp = NULL;
452 int ret;
453 SilcUInt32 mac_len = 0, iv_len = 0;
454
455 SILC_LOG_DEBUG(("Parsing Message Payload"));
456
457 silc_buffer_set(&buffer, payload, payload_len);
458
459 /* Decrypt the payload */
460 if (silc_likely(cipher)) {
461 ret = silc_message_payload_decrypt(buffer.data, silc_buffer_len(&buffer),
462 private_message, static_key,
463 cipher, hmac, sender_id,
464 sender_id_len, receiver_id,
465 receiver_id_len, TRUE);
466 if (silc_unlikely(ret == FALSE))
467 return NULL;
468 }
469
470 if (silc_likely(hmac))
471 mac_len = silc_hmac_len(hmac);
472
473 /* IV is present for all channel messages, and private messages when
474 static key (pre-shared key) is used. */
475 if (cipher && (!private_message || (private_message && static_key)))
476 iv_len = silc_cipher_get_block_len(cipher);
477
478 if (!message) {
479 newp = message = silc_calloc(1, sizeof(*newp));
480 if (silc_unlikely(!newp))
481 return NULL;
482 }
483 memset(message, 0, sizeof(*message));
484 message->allocated = (stack || no_allocation ? FALSE : TRUE);
485
486 /* Parse the Message Payload. */
487 if (!no_allocation)
488 ret = silc_buffer_sunformat(stack, &buffer,
489 SILC_STR_UI_SHORT(&message->flags),
490 SILC_STR_UI16_NSTRING_ALLOC(&message->data,
491 &message->data_len),
492 SILC_STR_UI16_NSTRING_ALLOC(&message->pad,
493 &message->pad_len),
494 SILC_STR_END);
495 else
496 ret = silc_buffer_unformat(&buffer,
497 SILC_STR_UI_SHORT(&message->flags),
498 SILC_STR_UI16_NSTRING(&message->data,
499 &message->data_len),
500 SILC_STR_UI16_NSTRING(&message->pad,
501 &message->pad_len),
502 SILC_STR_END);
503 if (silc_unlikely(ret == -1))
504 goto err;
505
506 if (silc_unlikely((message->data_len > silc_buffer_len(&buffer) -
507 6 - mac_len - iv_len) ||
508 (message->pad_len + message->data_len >
509 silc_buffer_len(&buffer) - 6 - mac_len - iv_len))) {
510 SILC_LOG_ERROR(("Incorrect Message Payload in packet"));
511 goto err;
512 }
513
514 /* Parse Signed Message Payload if provided */
515 if (message->flags & SILC_MESSAGE_FLAG_SIGNED &&
516 message->data_len + message->pad_len + 6 + mac_len +
517 iv_len < silc_buffer_len(&buffer)) {
518 if (!silc_message_signed_payload_parse(buffer.data + 6 +
519 message->data_len +
520 message->pad_len,
521 silc_buffer_len(&buffer) -
522 iv_len - mac_len - 6 -
523 message->data_len -
524 message->pad_len,
525 &message->sig))
526 goto err;
527 }
528
529 /* Parse MAC from the payload */
530 if (mac_len)
531 message->mac = buffer.data + (silc_buffer_len(&buffer) - mac_len);
532
533 return newp;
534
535 err:
536 if (newp)
537 silc_message_payload_free(newp);
538 return NULL;
539 }
540
541
542 /***************************** Payload encoding *****************************/
543
544 /* This function is used to encrypt the Messsage Payload which is
545 the `data' and `data_len'. This is used internally by the Message
546 Payload encoding routines but application may call this too if needed.
547 The `true_len' is the data length which is used to create MAC out of. */
548
549 SilcBool silc_message_payload_encrypt(unsigned char *data,
550 SilcUInt32 data_len,
551 SilcUInt32 true_len,
552 unsigned char *iv,
553 SilcID *sender_id,
554 SilcID *receiver_id,
555 SilcCipher cipher,
556 SilcHmac hmac)
557 {
558 unsigned char sid[32], rid[32];
559 SilcUInt32 sid_len = 0, rid_len = 0;
560
561 /* Encrypt payload of the packet */
562 if (silc_unlikely(!silc_cipher_encrypt(cipher, data, data, data_len, iv)))
563 return FALSE;
564
565 /* Encode IDs */
566 silc_id_id2str(&sender_id->u.client_id, SILC_ID_CLIENT, sid, sizeof(sid),
567 &sid_len);
568 if (receiver_id->type == SILC_ID_CLIENT)
569 silc_id_id2str(&receiver_id->u.client_id, SILC_ID_CLIENT, rid,
570 sizeof(rid), &rid_len);
571 else if (receiver_id->type == SILC_ID_CHANNEL)
572 silc_id_id2str(&receiver_id->u.channel_id, SILC_ID_CHANNEL, rid,
573 sizeof(rid), &rid_len);
574
575 /* Compute the MAC of the encrypted message data */
576 silc_hmac_init(hmac);
577 silc_hmac_update(hmac, data, true_len);
578 silc_hmac_update(hmac, sid, sid_len);
579 silc_hmac_update(hmac, rid, rid_len);
580 silc_hmac_final(hmac, data + true_len, NULL);
581
582 return TRUE;
583 }
584
585 /* Encrypt message payload */
586
587 static int silc_message_payload_encode_encrypt(SilcStack stack,
588 SilcBuffer buffer,
589 void *value, void *context)
590 {
591 SilcMessageEncode *e = context;
592 SilcUInt32 mac_len;
593
594 if (!e->cipher || !e->hmac)
595 return 0;
596
597 mac_len = silc_hmac_len(e->hmac);
598 if (silc_unlikely(!silc_buffer_enlarge(buffer, mac_len)))
599 return -1;
600
601 if (silc_unlikely(!silc_message_payload_encrypt(buffer->head,
602 e->payload_len,
603 silc_buffer_headlen(buffer),
604 e->iv, &e->sid, &e->rid,
605 e->cipher, e->hmac)))
606 return -1;
607
608 return mac_len;
609 }
610
611 /* Finalize message payload encoding */
612
613 static void
614 silc_message_payload_encode_final(SilcBuffer buffer,
615 SilcMessageFlags flags,
616 SilcCipher cipher,
617 SilcHmac hmac,
618 unsigned char *iv,
619 SilcUInt32 iv_len,
620 SilcUInt32 payload_len,
621 SilcID *sender_id,
622 SilcID *receiver_id,
623 SilcStack stack,
624 SilcBuffer signature,
625 SilcMessagePayloadEncoded encoded,
626 void *context)
627 {
628 SilcMessageEncode e;
629
630 e.flags = flags;
631 e.cipher = cipher;
632 e.hmac = hmac;
633 e.sid = *sender_id;
634 e.rid = *receiver_id;
635 e.iv = iv;
636 e.payload_len = payload_len;
637
638 /* Encrypt */
639 if (silc_buffer_format(buffer,
640 SILC_STR_DATA(signature ?
641 silc_buffer_data(signature) : NULL,
642 signature ?
643 silc_buffer_len(signature) : 0),
644 SILC_STR_DATA(iv, iv_len),
645 SILC_STR_FUNC(silc_message_payload_encode_encrypt,
646 NULL, &e),
647 SILC_STR_END) < 0) {
648 silc_buffer_sfree(stack, buffer);
649 encoded(NULL, context);
650 return;
651 }
652
653 /* Deliver message payload */
654 silc_buffer_start(buffer);
655 encoded(buffer, context);
656
657 silc_buffer_sfree(stack, buffer);
658 silc_buffer_sfree(stack, signature);
659 silc_stack_free(stack);
660 }
661
662 /* Encodes Message Payload into a buffer and returns it. */
663
664 SilcAsyncOperation
665 silc_message_payload_encode(SilcMessageFlags flags,
666 const unsigned char *data,
667 SilcUInt32 data_len,
668 SilcBool generate_iv,
669 SilcBool private_message,
670 SilcCipher cipher,
671 SilcHmac hmac,
672 SilcRng rng,
673 SilcPublicKey public_key,
674 SilcPrivateKey private_key,
675 SilcHash hash,
676 SilcID *sender_id,
677 SilcID *receiver_id,
678 SilcStack stack,
679 SilcMessagePayloadEncoded encoded,
680 void *context)
681 {
682 SilcUInt32 pad_len = 0, mac_len = 0, iv_len = 0;
683 unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE];
684 SilcBuffer buffer;
685 int i;
686
687 SILC_LOG_DEBUG(("Encoding Message Payload"));
688
689 if (silc_unlikely(!data_len)) {
690 encoded(NULL, context);
691 return NULL;
692 }
693 if (silc_unlikely(!private_message && (!cipher || !hmac))) {
694 encoded(NULL, context);
695 return NULL;
696 }
697
698 stack = silc_stack_alloc(0, stack ? stack : silc_crypto_stack());
699
700 buffer = silc_buffer_salloc(stack, 0);
701 if (silc_unlikely(!buffer)) {
702 encoded(NULL, context);
703 silc_stack_free(stack);
704 return NULL;
705 }
706
707 /* For channel messages IV is always generated */
708 if (!private_message && !generate_iv)
709 generate_iv = TRUE;
710
711 /* Generate IV */
712 if (cipher && generate_iv) {
713 iv_len = silc_cipher_get_block_len(cipher);
714 if (rng) {
715 for (i = 0; i < iv_len; i++) iv[i] = silc_rng_get_byte_fast(rng);
716 } else {
717 for (i = 0; i < iv_len; i++) iv[i] = silc_rng_global_get_byte_fast();
718 }
719 }
720
721 if (hmac)
722 mac_len = silc_hmac_len(hmac);
723 data_len = silc_message_payload_datalen(data_len, mac_len + iv_len, flags,
724 public_key, private_key);
725
726 /* Calculate length of padding. IV is not included into the calculation
727 since it is not encrypted. */
728 pad_len = SILC_MESSAGE_PAD(6 + data_len);
729
730 /* Generate padding */
731 if (cipher) {
732 if (rng) {
733 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
734 } else {
735 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
736 }
737 }
738
739 /* Encode the Message Payload */
740 if (silc_buffer_format(buffer,
741 SILC_STR_ADVANCE,
742 SILC_STR_UI_SHORT(flags),
743 SILC_STR_UI_SHORT(data_len),
744 SILC_STR_DATA(data, data_len),
745 SILC_STR_UI_SHORT(pad_len),
746 SILC_STR_DATA(pad, pad_len),
747 SILC_STR_END) < 0) {
748 silc_buffer_sfree(stack, buffer);
749 encoded(NULL, context);
750 silc_stack_free(stack);
751 return NULL;
752 }
753
754 if (flags & SILC_MESSAGE_FLAG_SIGNED) {
755 SilcMessageEncode *e = silc_scalloc(stack, 1, sizeof(*e));
756 if (!e) {
757 silc_buffer_sfree(stack, buffer);
758 encoded(NULL, context);
759 silc_stack_free(stack);
760 return NULL;
761 }
762
763 e->stack = stack;
764 e->buffer = buffer;
765 e->flags = flags;
766 e->public_key = public_key;
767 e->private_key = private_key;
768 e->rng = rng;
769 e->hash = hash;
770 e->cipher = cipher;
771 e->hmac = hmac;
772 e->sid = *sender_id;
773 e->rid = *receiver_id;
774 e->iv = iv_len ? iv : NULL;
775 e->iv_len = iv_len;
776 e->payload_len = 6 + data_len + pad_len;
777 e->encoded = encoded;
778 e->context = context;
779
780 /* Compute signature */
781 return silc_message_signed_payload_encode(buffer, e);
782 }
783
784 /* Finalize */
785 silc_message_payload_encode_final(buffer, flags, cipher, hmac,
786 iv_len ? iv : NULL, iv_len,
787 6 + data_len + pad_len,
788 sender_id, receiver_id, stack, NULL,
789 encoded, context);
790 return NULL;
791 }
792
793 /* Free's Message Payload */
794
795 void silc_message_payload_free(SilcMessagePayload payload)
796 {
797 silc_message_signed_payload_free(&payload->sig);
798 if (payload->data) {
799 memset(payload->data, 0, payload->data_len);
800 if (payload->allocated)
801 silc_free(payload->data);
802 }
803 if (payload->allocated) {
804 silc_free(payload->pad);
805 silc_free(payload);
806 }
807 }
808
809 /* Return flags */
810
811 SilcMessageFlags silc_message_get_flags(SilcMessagePayload payload)
812 {
813 return payload->flags;
814 }
815
816 /* Return data */
817
818 unsigned char *silc_message_get_data(SilcMessagePayload payload,
819 SilcUInt32 *data_len)
820 {
821 if (data_len)
822 *data_len = payload->data_len;
823 return payload->data;
824 }
825
826 /* Return MAC. The caller knows the length of the MAC */
827
828 unsigned char *silc_message_get_mac(SilcMessagePayload payload)
829 {
830 return payload->mac;
831 }
832
833 /* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */
834
835 SilcAsyncOperation
836 silc_message_signed_verify(SilcMessagePayload message,
837 SilcPublicKey remote_public_key,
838 SilcHash hash,
839 SilcAuthResultCb result,
840 void *context)
841 {
842 SilcAsyncOperation op;
843 SilcBuffer sign, tmp;
844 SilcStack stack = NULL;
845 SilcMessageSignedPayload sig = &message->sig;
846
847 if (!(message->flags & SILC_MESSAGE_FLAG_SIGNED) ||
848 !sig->sign_len || !remote_public_key || !hash) {
849 result(FALSE, context);
850 return NULL;
851 }
852
853 if (silc_crypto_stack())
854 stack = silc_stack_alloc(0, silc_crypto_stack());
855
856 /* Generate the signature verification data, the Message Payload */
857 tmp = silc_buffer_salloc_size(stack,
858 6 + message->data_len + message->pad_len);
859 silc_buffer_sformat(stack, tmp,
860 SILC_STR_UI_SHORT(message->flags),
861 SILC_STR_UI_SHORT(message->data_len),
862 SILC_STR_DATA(message->data, message->data_len),
863 SILC_STR_UI_SHORT(message->pad_len),
864 SILC_STR_DATA(message->pad, message->pad_len),
865 SILC_STR_END);
866 sign = silc_message_signed_encode_data(stack, tmp->data, silc_buffer_len(tmp),
867 sig->pk_data, sig->pk_len,
868 sig->pk_type);
869 silc_buffer_clear(tmp);
870 silc_buffer_sfree(stack, tmp);
871
872 if (!sign) {
873 result(FALSE, context);
874 silc_stack_free(stack);
875 return NULL;
876 }
877
878 /* Verify the authentication data */
879 op = silc_pkcs_verify(remote_public_key, sig->sign_data, sig->sign_len,
880 silc_buffer_data(sign), silc_buffer_len(sign),
881 hash, result, context);
882
883 silc_buffer_clear(sign);
884 silc_buffer_sfree(stack, sign);
885 silc_stack_free(stack);
886
887 return op;
888 }
889
890 /* Return the public key from the payload */
891
892 SilcPublicKey
893 silc_message_signed_get_public_key(SilcMessagePayload payload,
894 const unsigned char **pk_data,
895 SilcUInt32 *pk_data_len)
896 {
897 SilcPublicKey pk;
898 SilcMessageSignedPayload sig = &payload->sig;
899
900 if (!sig->pk_data)
901 return NULL;
902
903 if (!silc_pkcs_public_key_alloc(sig->pk_type, sig->pk_data,
904 sig->pk_len, &pk))
905 return NULL;
906
907 if (pk_data)
908 *pk_data = sig->pk_data;
909 if (pk_data_len)
910 *pk_data_len = sig->pk_len;
911
912 return pk;
913 }
914
This page was automatically generated by the LXR engine.
Free-text search provided by Glimpse