Merge branch 'topic/mm-fixes' of git://208.110.73.182/silc into silc.1.1.branch
[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(SilcBuffer buffer,
516                                                void *value, void *context)
517 {
518   SilcMessageEncode *e = context;
519   SilcUInt32 mac_len;
520
521   if (!e->cipher || !e->hmac)
522     return 0;
523
524   mac_len = silc_hmac_len(e->hmac);
525   if (silc_unlikely(!silc_buffer_enlarge(buffer, mac_len)))
526     return -1;
527
528   if (silc_unlikely(!silc_message_payload_encrypt(buffer->head,
529                                                   e->payload_len,
530                                                   silc_buffer_headlen(buffer),
531                                                   e->iv, e->sid, e->rid,
532                                                   e->cipher, e->hmac)))
533     return -1;
534
535   return mac_len;
536 }
537
538 /* Compute message signature */
539
540 static int silc_message_payload_encode_sig(SilcBuffer buffer,
541                                            void *value, void *context)
542 {
543   SilcMessageEncode *e = context;
544   SilcBuffer sig;
545   int len;
546
547   if (!(e->flags & SILC_MESSAGE_FLAG_SIGNED))
548     return 0;
549
550   sig = silc_message_signed_payload_encode(buffer->head,
551                                            silc_buffer_headlen(buffer),
552                                            e->public_key, e->private_key,
553                                            e->hash);
554   if (silc_unlikely(!sig))
555     return -1;
556
557   len = silc_buffer_format(buffer,
558                            SILC_STR_DATA(silc_buffer_data(sig),
559                                          silc_buffer_len(sig)),
560                            SILC_STR_END);
561   if (silc_unlikely(len < 0)) {
562     silc_buffer_free(sig);
563     return -1;
564   }
565
566   silc_buffer_free(sig);
567   return len;
568 }
569
570 /* Encodes Message Payload into a buffer and returns it. */
571
572 SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
573                                        const unsigned char *data,
574                                        SilcUInt32 data_len,
575                                        SilcBool generate_iv,
576                                        SilcBool private_message,
577                                        SilcCipher cipher,
578                                        SilcHmac hmac,
579                                        SilcRng rng,
580                                        SilcPublicKey public_key,
581                                        SilcPrivateKey private_key,
582                                        SilcHash hash,
583                                        SilcID *sender_id,
584                                        SilcID *receiver_id,
585                                        SilcBuffer buffer)
586 {
587   SilcUInt32 pad_len = 0, mac_len = 0, iv_len = 0;
588   unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE];
589   SilcBuffer buf = NULL;
590   SilcMessageEncode e;
591   int i;
592
593   SILC_LOG_DEBUG(("Encoding Message Payload"));
594
595   if (silc_unlikely(!data_len))
596     return NULL;
597   if (silc_unlikely(!private_message && (!cipher || !hmac)))
598     return NULL;
599
600   if (!buffer) {
601     buf = buffer = silc_buffer_alloc(0);
602     if (silc_unlikely(!buf))
603       return NULL;
604   }
605   silc_buffer_reset(buffer);
606
607   /* For channel messages IV is always generated */
608   if (!private_message && !generate_iv)
609     generate_iv = TRUE;
610
611   /* Generate IV */
612   if (cipher && generate_iv) {
613     iv_len = silc_cipher_get_block_len(cipher);
614     if (rng) {
615       for (i = 0; i < iv_len; i++) iv[i] = silc_rng_get_byte_fast(rng);
616     } else {
617       for (i = 0; i < iv_len; i++) iv[i] = silc_rng_global_get_byte_fast();
618     }
619   }
620
621   if (hmac)
622     mac_len = silc_hmac_len(hmac);
623   data_len = silc_message_payload_datalen(data_len, mac_len + iv_len, flags,
624                                           public_key, private_key);
625
626   /* Calculate length of padding. IV is not included into the calculation
627      since it is not encrypted. */
628   pad_len = SILC_MESSAGE_PAD(6 + data_len);
629
630   /* Generate padding */
631   if (cipher) {
632     if (rng) {
633       for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
634     } else {
635       for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
636     }
637   }
638
639   e.flags = flags;
640   e.public_key = public_key;
641   e.private_key = private_key;
642   e.hash = hash;
643   e.cipher = cipher;
644   e.hmac = hmac;
645   e.sid = sender_id;
646   e.rid = receiver_id;
647   e.iv = iv_len ? iv : NULL;
648   e.payload_len = 6 + data_len + pad_len;
649
650   /* Encode the Message Payload */
651   if (silc_buffer_format(buffer,
652                          SILC_STR_UI_SHORT(flags),
653                          SILC_STR_UI_SHORT(data_len),
654                          SILC_STR_DATA(data, data_len),
655                          SILC_STR_UI_SHORT(pad_len),
656                          SILC_STR_DATA(pad, pad_len),
657                          SILC_STR_FUNC(silc_message_payload_encode_sig,
658                                        NULL, &e),
659                          SILC_STR_DATA(iv, iv_len),
660                          SILC_STR_FUNC(silc_message_payload_encode_encrypt,
661                                        NULL, &e),
662                          SILC_STR_END) < 0) {
663     silc_buffer_free(buf);
664     return NULL;
665   }
666
667   return buffer;
668 }
669
670 /* Free's Message Payload */
671
672 void silc_message_payload_free(SilcMessagePayload payload)
673 {
674   silc_message_signed_payload_free(&payload->sig);
675   if (payload->data) {
676     memset(payload->data, 0, payload->data_len);
677     if (payload->allocated)
678       silc_free(payload->data);
679   }
680   if (payload->allocated) {
681     silc_free(payload->pad);
682     silc_free(payload);
683   }
684 }
685
686 /* Return flags */
687
688 SilcMessageFlags silc_message_get_flags(SilcMessagePayload payload)
689 {
690   return payload->flags;
691 }
692
693 /* Return data */
694
695 unsigned char *silc_message_get_data(SilcMessagePayload payload,
696                                      SilcUInt32 *data_len)
697 {
698   if (data_len)
699     *data_len = payload->data_len;
700   return payload->data;
701 }
702
703 /* Return MAC. The caller knows the length of the MAC */
704
705 unsigned char *silc_message_get_mac(SilcMessagePayload payload)
706 {
707   return payload->mac;
708 }
709
710 /* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */
711
712 SilcAuthResult silc_message_signed_verify(SilcMessagePayload message,
713                                           SilcPublicKey remote_public_key,
714                                           SilcHash hash)
715 {
716   int ret = SILC_AUTH_FAILED;
717   SilcBuffer sign, tmp;
718   SilcMessageSignedPayload sig = &message->sig;
719
720   if (!(message->flags & SILC_MESSAGE_FLAG_SIGNED) ||
721       !sig->sign_len || !remote_public_key || !hash)
722     return ret;
723
724   /* Generate the signature verification data, the Message Payload */
725   tmp = silc_buffer_alloc_size(6 + message->data_len + message->pad_len);
726   silc_buffer_format(tmp,
727                      SILC_STR_UI_SHORT(message->flags),
728                      SILC_STR_UI_SHORT(message->data_len),
729                      SILC_STR_UI_XNSTRING(message->data, message->data_len),
730                      SILC_STR_UI_SHORT(message->pad_len),
731                      SILC_STR_UI_XNSTRING(message->pad, message->pad_len),
732                      SILC_STR_END);
733   sign = silc_message_signed_encode_data(tmp->data, silc_buffer_len(tmp),
734                                          sig->pk_data, sig->pk_len,
735                                          sig->pk_type);
736   silc_buffer_clear(tmp);
737   silc_buffer_free(tmp);
738
739   if (!sign)
740     return ret;
741
742   /* Verify the authentication data */
743   if (!silc_pkcs_verify(remote_public_key, sig->sign_data, sig->sign_len,
744                         silc_buffer_data(sign), silc_buffer_len(sign), hash)) {
745     silc_buffer_clear(sign);
746     silc_buffer_free(sign);
747     SILC_LOG_DEBUG(("Signature verification failed"));
748     return ret;
749   }
750
751   ret = SILC_AUTH_OK;
752
753   silc_buffer_clear(sign);
754   silc_buffer_free(sign);
755
756   SILC_LOG_DEBUG(("Signature verification successful"));
757
758   return ret;
759 }
760
761 /* Return the public key from the payload */
762
763 SilcPublicKey
764 silc_message_signed_get_public_key(SilcMessagePayload payload,
765                                    const unsigned char **pk_data,
766                                    SilcUInt32 *pk_data_len)
767 {
768   SilcPublicKey pk;
769   SilcMessageSignedPayload sig = &payload->sig;
770
771   if (!sig->pk_data)
772     return NULL;
773
774   if (!silc_pkcs_public_key_alloc(sig->pk_type, sig->pk_data,
775                                   sig->pk_len, &pk))
776     return NULL;
777
778   if (pk_data)
779     *pk_data = sig->pk_data;
780   if (pk_data_len)
781     *pk_data_len = sig->pk_len;
782
783   return pk;
784 }