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