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