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