Enable higher security messages MACs
[silc.git] / lib / silccore / silcmessage.c
1 /*
2
3   silcmessage.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2014 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[65536 + 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 1 /* Check for old style message MAC.  Remove this check at some point. */
304       silc_hmac_init(hmac);
305       silc_hmac_update(hmac, data, data_len - mac_len);
306       silc_hmac_final(hmac, mac, &mac_len);
307       if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) {
308         SILC_LOG_DEBUG(("Message MAC does not match"));
309         return FALSE;
310       }
311 #else
312       SILC_LOG_DEBUG(("Message MAC does not match"));
313       return FALSE;
314 #endif /* 0 */
315     }
316     SILC_LOG_DEBUG(("MAC is Ok"));
317   }
318
319   /* Decrypt first only one block to get the header and then rest of
320      the data.  This is done because there might be unencrypted data at
321      the end and we don't know the encrypted length yet. */
322
323   /* Get pointer to the IV */
324   ivp = (iv_len ? data + (data_len - iv_len - mac_len) :
325          silc_cipher_get_iv(cipher));
326
327   /* Decrypt block */
328   if (silc_unlikely(!silc_cipher_decrypt(cipher, data, data, block_len,
329                                          ivp))) {
330     SILC_ASSERT(FALSE);
331     return FALSE;
332   }
333
334   /* Get the payload length and decrypt rest */
335   totlen = 2;
336   SILC_GET16_MSB(len, data + totlen);
337   totlen += 2 + len;
338   if (silc_unlikely(totlen + iv_len + mac_len + 2 > data_len))
339     return FALSE;
340   totlen += 2;
341   if (totlen >= block_len)
342     if (silc_unlikely(!silc_cipher_decrypt(cipher, data + block_len,
343                                            data + block_len,
344                                            (totlen - block_len) +
345                                            SILC_MESSAGE_PAD(totlen), ivp))) {
346       SILC_ASSERT(FALSE);
347       return FALSE;
348     }
349
350   return TRUE;
351 }
352
353 /* Parses Message Payload returning new payload structure.  This also
354    decrypts it and checks the MAC. */
355
356 SilcMessagePayload
357 silc_message_payload_parse(unsigned char *payload,
358                            SilcUInt32 payload_len,
359                            SilcBool private_message,
360                            SilcBool static_key,
361                            SilcCipher cipher,
362                            SilcHmac hmac,
363                            unsigned char *sender_id,
364                            SilcUInt32 sender_id_len,
365                            unsigned char *receiver_id,
366                            SilcUInt32 receiver_id_len,
367                            SilcStack stack,
368                            SilcBool no_allocation,
369                            SilcMessagePayload message)
370 {
371   SilcBufferStruct buffer;
372   SilcMessagePayload newp = NULL;
373   int ret;
374   SilcUInt32 mac_len = 0, iv_len = 0;
375
376   SILC_LOG_DEBUG(("Parsing Message Payload"));
377
378   silc_buffer_set(&buffer, payload, payload_len);
379
380   /* Decrypt the payload */
381   if (silc_likely(cipher)) {
382     ret = silc_message_payload_decrypt(buffer.data, silc_buffer_len(&buffer),
383                                        private_message, static_key,
384                                        cipher, hmac, sender_id,
385                                        sender_id_len, receiver_id,
386                                        receiver_id_len, TRUE);
387     if (silc_unlikely(ret == FALSE))
388       return NULL;
389   }
390
391   if (silc_likely(hmac))
392     mac_len = silc_hmac_len(hmac);
393
394   /* IV is present for all channel messages, and private messages when
395      static key (pre-shared key) is used. */
396   if (cipher && (!private_message || (private_message && static_key)))
397     iv_len = silc_cipher_get_block_len(cipher);
398
399   if (!message) {
400     newp = message = silc_calloc(1, sizeof(*newp));
401     if (silc_unlikely(!newp))
402       return NULL;
403   }
404   memset(message, 0, sizeof(*message));
405   message->allocated = (stack || no_allocation ? FALSE : TRUE);
406
407   /* Parse the Message Payload. */
408   if (!no_allocation)
409     ret = silc_buffer_sunformat(stack, &buffer,
410                           SILC_STR_UI_SHORT(&message->flags),
411                           SILC_STR_UI16_NSTRING_ALLOC(&message->data,
412                                                       &message->data_len),
413                           SILC_STR_UI16_NSTRING_ALLOC(&message->pad,
414                                                       &message->pad_len),
415                           SILC_STR_END);
416   else
417     ret = silc_buffer_unformat(&buffer,
418                                SILC_STR_UI_SHORT(&message->flags),
419                                SILC_STR_UI16_NSTRING(&message->data,
420                                                      &message->data_len),
421                                SILC_STR_UI16_NSTRING(&message->pad,
422                                                      &message->pad_len),
423                                SILC_STR_END);
424   if (silc_unlikely(ret == -1))
425     goto err;
426
427   if (silc_unlikely((message->data_len > silc_buffer_len(&buffer) -
428                      6 - mac_len - iv_len) ||
429                     (message->pad_len + message->data_len >
430                      silc_buffer_len(&buffer) - 6 - mac_len - iv_len))) {
431     SILC_LOG_ERROR(("Incorrect Message Payload in packet"));
432     goto err;
433   }
434
435   /* Parse Signed Message Payload if provided */
436   if (message->flags & SILC_MESSAGE_FLAG_SIGNED &&
437       message->data_len + message->pad_len + 6 + mac_len +
438       iv_len < silc_buffer_len(&buffer)) {
439     if (!silc_message_signed_payload_parse(buffer.data + 6 +
440                                            message->data_len +
441                                            message->pad_len,
442                                            silc_buffer_len(&buffer) -
443                                            iv_len - mac_len - 6 -
444                                            message->data_len -
445                                            message->pad_len,
446                                            &message->sig))
447       goto err;
448   }
449
450   /* Parse MAC from the payload */
451   if (mac_len)
452     message->mac = buffer.data + (silc_buffer_len(&buffer) - mac_len);
453
454   return newp;
455
456  err:
457   if (newp)
458     silc_message_payload_free(newp);
459   return NULL;
460 }
461
462
463 /***************************** Payload encoding *****************************/
464
465 /* This function is used to encrypt the Messsage Payload which is
466    the `data' and `data_len'.  This is used internally by the Message
467    Payload encoding routines but application may call this too if needed.
468    The `true_len' is the data length which is used to create MAC out of. */
469
470 SilcBool silc_message_payload_encrypt(unsigned char *data,
471                                       SilcUInt32 data_len,
472                                       SilcUInt32 true_len,
473                                       unsigned char *iv,
474                                       SilcID *sender_id,
475                                       SilcID *receiver_id,
476                                       SilcCipher cipher,
477                                       SilcHmac hmac)
478 {
479   unsigned char sid[32], rid[32];
480   SilcUInt32 sid_len = 0, rid_len = 0;
481
482   /* Encrypt payload of the packet */
483   if (silc_unlikely(!silc_cipher_encrypt(cipher, data, data, data_len, iv)))
484     return FALSE;
485
486   /* Encode IDs */
487   silc_id_id2str(&sender_id->u.client_id, SILC_ID_CLIENT, sid, sizeof(sid),
488                  &sid_len);
489   if (receiver_id->type == SILC_ID_CLIENT)
490     silc_id_id2str(&receiver_id->u.client_id, SILC_ID_CLIENT, rid,
491                    sizeof(rid), &rid_len);
492   else if (receiver_id->type == SILC_ID_CHANNEL)
493     silc_id_id2str(&receiver_id->u.channel_id, SILC_ID_CHANNEL, rid,
494                    sizeof(rid), &rid_len);
495
496   /* Compute the MAC of the encrypted message data */
497   silc_hmac_init(hmac);
498   silc_hmac_update(hmac, data, true_len);
499   silc_hmac_update(hmac, sid, sid_len);
500   silc_hmac_update(hmac, rid, rid_len);
501   silc_hmac_final(hmac, data + true_len, NULL);
502
503   return TRUE;
504 }
505
506 /* Encrypt message payload */
507
508 static int silc_message_payload_encode_encrypt(SilcBuffer buffer,
509                                                void *value, void *context)
510 {
511   SilcMessageEncode *e = context;
512   SilcUInt32 mac_len;
513
514   if (!e->cipher || !e->hmac)
515     return 0;
516
517   mac_len = silc_hmac_len(e->hmac);
518   if (silc_unlikely(!silc_buffer_enlarge(buffer, mac_len)))
519     return -1;
520
521   if (silc_unlikely(!silc_message_payload_encrypt(buffer->head,
522                                                   e->payload_len,
523                                                   silc_buffer_headlen(buffer),
524                                                   e->iv, e->sid, e->rid,
525                                                   e->cipher, e->hmac)))
526     return -1;
527
528   return mac_len;
529 }
530
531 /* Compute message signature */
532
533 static int silc_message_payload_encode_sig(SilcBuffer buffer,
534                                            void *value, void *context)
535 {
536   SilcMessageEncode *e = context;
537   SilcBuffer sig;
538   int len;
539
540   if (!(e->flags & SILC_MESSAGE_FLAG_SIGNED))
541     return 0;
542
543   sig = silc_message_signed_payload_encode(buffer->head,
544                                            silc_buffer_headlen(buffer),
545                                            e->public_key, e->private_key,
546                                            e->hash);
547   if (silc_unlikely(!sig))
548     return -1;
549
550   len = silc_buffer_format(buffer,
551                            SILC_STR_DATA(silc_buffer_data(sig),
552                                          silc_buffer_len(sig)),
553                            SILC_STR_END);
554   if (silc_unlikely(len < 0)) {
555     silc_buffer_free(sig);
556     return -1;
557   }
558
559   silc_buffer_free(sig);
560   return len;
561 }
562
563 /* Encodes Message Payload into a buffer and returns it. */
564
565 SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
566                                        const unsigned char *data,
567                                        SilcUInt32 data_len,
568                                        SilcBool generate_iv,
569                                        SilcBool private_message,
570                                        SilcCipher cipher,
571                                        SilcHmac hmac,
572                                        SilcRng rng,
573                                        SilcPublicKey public_key,
574                                        SilcPrivateKey private_key,
575                                        SilcHash hash,
576                                        SilcID *sender_id,
577                                        SilcID *receiver_id,
578                                        SilcBuffer buffer)
579 {
580   SilcUInt32 pad_len = 0, mac_len = 0, iv_len = 0;
581   unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE];
582   SilcBuffer buf = NULL;
583   SilcMessageEncode e;
584   int i;
585
586   SILC_LOG_DEBUG(("Encoding Message Payload"));
587
588   if (silc_unlikely(!data_len))
589     return NULL;
590   if (silc_unlikely(!private_message && (!cipher || !hmac)))
591     return NULL;
592
593   if (!buffer) {
594     buf = buffer = silc_buffer_alloc(0);
595     if (silc_unlikely(!buf))
596       return NULL;
597   }
598   silc_buffer_reset(buffer);
599
600   /* For channel messages IV is always generated */
601   if (!private_message && !generate_iv)
602     generate_iv = TRUE;
603
604   /* Generate IV */
605   if (cipher && generate_iv) {
606     iv_len = silc_cipher_get_block_len(cipher);
607     if (rng) {
608       for (i = 0; i < iv_len; i++) iv[i] = silc_rng_get_byte_fast(rng);
609     } else {
610       for (i = 0; i < iv_len; i++) iv[i] = silc_rng_global_get_byte_fast();
611     }
612   }
613
614   if (hmac)
615     mac_len = silc_hmac_len(hmac);
616   data_len = silc_message_payload_datalen(data_len, mac_len + iv_len, flags,
617                                           public_key, private_key);
618
619   /* Calculate length of padding. IV is not included into the calculation
620      since it is not encrypted. */
621   pad_len = SILC_MESSAGE_PAD(6 + data_len);
622
623   /* Generate padding */
624   if (cipher) {
625     if (rng) {
626       for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
627     } else {
628       for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
629     }
630   }
631
632   e.flags = flags;
633   e.public_key = public_key;
634   e.private_key = private_key;
635   e.hash = hash;
636   e.cipher = cipher;
637   e.hmac = hmac;
638   e.sid = sender_id;
639   e.rid = receiver_id;
640   e.iv = iv_len ? iv : NULL;
641   e.payload_len = 6 + data_len + pad_len;
642
643   /* Encode the Message Payload */
644   if (silc_buffer_format(buffer,
645                          SILC_STR_UI_SHORT(flags),
646                          SILC_STR_UI_SHORT(data_len),
647                          SILC_STR_DATA(data, data_len),
648                          SILC_STR_UI_SHORT(pad_len),
649                          SILC_STR_DATA(pad, pad_len),
650                          SILC_STR_FUNC(silc_message_payload_encode_sig,
651                                        NULL, &e),
652                          SILC_STR_DATA(iv, iv_len),
653                          SILC_STR_FUNC(silc_message_payload_encode_encrypt,
654                                        NULL, &e),
655                          SILC_STR_END) < 0) {
656     silc_buffer_free(buf);
657     return NULL;
658   }
659
660   return buffer;
661 }
662
663 /* Free's Message Payload */
664
665 void silc_message_payload_free(SilcMessagePayload payload)
666 {
667   silc_message_signed_payload_free(&payload->sig);
668   if (payload->data) {
669     memset(payload->data, 0, payload->data_len);
670     if (payload->allocated)
671       silc_free(payload->data);
672   }
673   if (payload->allocated) {
674     silc_free(payload->pad);
675     silc_free(payload);
676   }
677 }
678
679 /* Return flags */
680
681 SilcMessageFlags silc_message_get_flags(SilcMessagePayload payload)
682 {
683   return payload->flags;
684 }
685
686 /* Return data */
687
688 unsigned char *silc_message_get_data(SilcMessagePayload payload,
689                                      SilcUInt32 *data_len)
690 {
691   if (data_len)
692     *data_len = payload->data_len;
693   return payload->data;
694 }
695
696 /* Return MAC. The caller knows the length of the MAC */
697
698 unsigned char *silc_message_get_mac(SilcMessagePayload payload)
699 {
700   return payload->mac;
701 }
702
703 /* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */
704
705 SilcAuthResult silc_message_signed_verify(SilcMessagePayload message,
706                                           SilcPublicKey remote_public_key,
707                                           SilcHash hash)
708 {
709   int ret = SILC_AUTH_FAILED;
710   SilcBuffer sign, tmp;
711   SilcMessageSignedPayload sig = &message->sig;
712
713   if (!(message->flags & SILC_MESSAGE_FLAG_SIGNED) ||
714       !sig->sign_len || !remote_public_key || !hash)
715     return ret;
716
717   /* Generate the signature verification data, the Message Payload */
718   tmp = silc_buffer_alloc_size(6 + message->data_len + message->pad_len);
719   silc_buffer_format(tmp,
720                      SILC_STR_UI_SHORT(message->flags),
721                      SILC_STR_UI_SHORT(message->data_len),
722                      SILC_STR_UI_XNSTRING(message->data, message->data_len),
723                      SILC_STR_UI_SHORT(message->pad_len),
724                      SILC_STR_UI_XNSTRING(message->pad, message->pad_len),
725                      SILC_STR_END);
726   sign = silc_message_signed_encode_data(tmp->data, silc_buffer_len(tmp),
727                                          sig->pk_data, sig->pk_len,
728                                          sig->pk_type);
729   silc_buffer_clear(tmp);
730   silc_buffer_free(tmp);
731
732   if (!sign)
733     return ret;
734
735   /* Verify the authentication data */
736   if (!silc_pkcs_verify(remote_public_key, sig->sign_data, sig->sign_len,
737                         silc_buffer_data(sign), silc_buffer_len(sign), hash)) {
738     silc_buffer_clear(sign);
739     silc_buffer_free(sign);
740     SILC_LOG_DEBUG(("Signature verification failed"));
741     return ret;
742   }
743
744   ret = SILC_AUTH_OK;
745
746   silc_buffer_clear(sign);
747   silc_buffer_free(sign);
748
749   SILC_LOG_DEBUG(("Signature verification successful"));
750
751   return ret;
752 }
753
754 /* Return the public key from the payload */
755
756 SilcPublicKey
757 silc_message_signed_get_public_key(SilcMessagePayload payload,
758                                    const unsigned char **pk_data,
759                                    SilcUInt32 *pk_data_len)
760 {
761   SilcPublicKey pk;
762   SilcMessageSignedPayload sig = &payload->sig;
763
764   if (!sig->pk_data)
765     return NULL;
766
767   if (!silc_pkcs_public_key_alloc(sig->pk_type, sig->pk_data,
768                                   sig->pk_len, &pk))
769     return NULL;
770
771   if (pk_data)
772     *pk_data = sig->pk_data;
773   if (pk_data_len)
774     *pk_data_len = sig->pk_len;
775
776   return pk;
777 }