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