silc_pkcs_sign API change, requires hash pointer as argument.
[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 } 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,
211                       TRUE, hash)) {
212     SILC_LOG_ERROR(("Could not compute signature"));
213     silc_buffer_clear(sign);
214     silc_buffer_free(sign);
215     silc_free(pk);
216     return NULL;
217   }
218
219   /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */
220
221   buffer = silc_buffer_alloc_size(4 + pk_len + 2 + auth_len);
222   if (!buffer) {
223     silc_buffer_clear(sign);
224     silc_buffer_free(sign);
225     memset(auth_data, 0, sizeof(auth_data));
226     silc_free(pk);
227     return NULL;
228   }
229
230   silc_buffer_format(buffer,
231                      SILC_STR_UI_SHORT(pk_len),
232                      SILC_STR_UI_SHORT(pk_type),
233                      SILC_STR_END);
234
235   if (pk_len && pk) {
236     silc_buffer_pull(buffer, 4);
237     silc_buffer_format(buffer,
238                        SILC_STR_UI_XNSTRING(pk, pk_len),
239                        SILC_STR_END);
240     silc_buffer_push(buffer, 4);
241   }
242
243   silc_buffer_pull(buffer, 4 + pk_len);
244   silc_buffer_format(buffer,
245                      SILC_STR_UI_SHORT(auth_len),
246                      SILC_STR_UI_XNSTRING(auth_data, auth_len),
247                      SILC_STR_END);
248   silc_buffer_push(buffer, 4 + pk_len);
249
250   SILC_LOG_HEXDUMP(("sig payload"), buffer->data, silc_buffer_len(buffer));
251
252   memset(auth_data, 0, sizeof(auth_data));
253   silc_buffer_clear(sign);
254   silc_buffer_free(sign);
255   silc_free(pk);
256
257   return buffer;
258 }
259
260
261 /***************************** Payload parsing ******************************/
262
263 /* Decrypts the Message Payload. The `data' is the actual Message Payload. */
264
265 SilcBool silc_message_payload_decrypt(unsigned char *data,
266                                       size_t data_len,
267                                       SilcBool private_message,
268                                       SilcBool static_key,
269                                       SilcCipher cipher,
270                                       SilcHmac hmac,
271                                       SilcBool check_mac)
272 {
273   SilcUInt32 mac_len, iv_len = 0, block_len;
274   SilcUInt16 len, totlen;
275   unsigned char mac[32], *ivp;
276
277   mac_len = silc_hmac_len(hmac);
278   block_len = silc_cipher_get_block_len(cipher);
279
280   /* IV is present for all channel messages, and private messages when
281      static key (pre-shared key) is used. */
282   if (!private_message || (private_message && static_key))
283     iv_len = block_len;
284
285   if (silc_unlikely(data_len < (mac_len + iv_len + block_len)))
286     return FALSE;
287
288   if (silc_likely(check_mac)) {
289     /* Check the MAC of the message */
290     SILC_LOG_DEBUG(("Checking message MAC"));
291     silc_hmac_init(hmac);
292     silc_hmac_update(hmac, data, data_len - mac_len);
293     silc_hmac_final(hmac, mac, &mac_len);
294     if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) {
295       SILC_LOG_DEBUG(("Message MAC does not match"));
296       return FALSE;
297     }
298     SILC_LOG_DEBUG(("MAC is Ok"));
299   }
300
301   /* Decrypt first only one block to get the header and then rest of
302      the data.  This is done because there might be unencrypted data at
303      the end and we don't know the encrypted length yet. */
304
305   /* Get pointer to the IV */
306   ivp = (iv_len ? data + (data_len - iv_len - mac_len) :
307          silc_cipher_get_iv(cipher));
308
309   /* Decrypt block */
310   if (silc_unlikely(!silc_cipher_decrypt(cipher, data, data, block_len,
311                                          ivp))) {
312     SILC_ASSERT(FALSE);
313     return FALSE;
314   }
315
316   /* Get the payload length and decrypt rest */
317   totlen = 2;
318   SILC_GET16_MSB(len, data + totlen);
319   totlen += 2 + len;
320   if (silc_unlikely(totlen + iv_len + mac_len + 2 > data_len))
321     return FALSE;
322   totlen += 2;
323   if (totlen >= block_len)
324     if (silc_unlikely(!silc_cipher_decrypt(cipher, data + block_len,
325                                            data + block_len,
326                                            (totlen - block_len) +
327                                            SILC_MESSAGE_PAD(totlen), ivp))) {
328       SILC_ASSERT(FALSE);
329       return FALSE;
330     }
331
332   return TRUE;
333 }
334
335 /* Parses Message Payload returning new payload structure.  This also
336    decrypts it and checks the MAC. */
337
338 SilcMessagePayload
339 silc_message_payload_parse(unsigned char *payload,
340                            SilcUInt32 payload_len,
341                            SilcBool private_message,
342                            SilcBool static_key,
343                            SilcCipher cipher,
344                            SilcHmac hmac,
345                            SilcStack stack,
346                            SilcBool no_allocation,
347                            SilcMessagePayload message)
348 {
349   SilcBufferStruct buffer;
350   SilcMessagePayload newp = NULL;
351   int ret;
352   SilcUInt32 mac_len = 0, iv_len = 0;
353
354   SILC_LOG_DEBUG(("Parsing Message Payload"));
355
356   silc_buffer_set(&buffer, payload, payload_len);
357
358   /* Decrypt the payload */
359   if (silc_likely(cipher)) {
360     ret = silc_message_payload_decrypt(buffer.data, silc_buffer_len(&buffer),
361                                        private_message, static_key,
362                                        cipher, hmac, TRUE);
363     if (silc_unlikely(ret == FALSE))
364       return NULL;
365   }
366
367   if (silc_likely(hmac))
368     mac_len = silc_hmac_len(hmac);
369
370   /* IV is present for all channel messages, and private messages when
371      static key (pre-shared key) is used. */
372   if (cipher && (!private_message || (private_message && static_key)))
373     iv_len = silc_cipher_get_block_len(cipher);
374
375   if (!message) {
376     newp = message = silc_calloc(1, sizeof(*newp));
377     if (silc_unlikely(!newp))
378       return NULL;
379   }
380   memset(message, 0, sizeof(*message));
381   message->allocated = (stack || no_allocation ? FALSE : TRUE);
382
383   /* Parse the Message Payload. */
384   if (!no_allocation)
385     ret = silc_buffer_sunformat(stack, &buffer,
386                           SILC_STR_UI_SHORT(&message->flags),
387                           SILC_STR_UI16_NSTRING_ALLOC(&message->data,
388                                                       &message->data_len),
389                           SILC_STR_UI16_NSTRING_ALLOC(&message->pad,
390                                                       &message->pad_len),
391                           SILC_STR_END);
392   else
393     ret = silc_buffer_unformat(&buffer,
394                                SILC_STR_UI_SHORT(&message->flags),
395                                SILC_STR_UI16_NSTRING(&message->data,
396                                                      &message->data_len),
397                                SILC_STR_UI16_NSTRING(&message->pad,
398                                                      &message->pad_len),
399                                SILC_STR_END);
400   if (silc_unlikely(ret == -1))
401     goto err;
402
403   if (silc_unlikely((message->data_len > silc_buffer_len(&buffer) -
404                      6 - mac_len - iv_len) ||
405                     (message->pad_len + message->data_len >
406                      silc_buffer_len(&buffer) - 6 - mac_len - iv_len))) {
407     SILC_LOG_ERROR(("Incorrect Message Payload in packet"));
408     goto err;
409   }
410
411   /* Parse Signed Message Payload if provided */
412   if (message->flags & SILC_MESSAGE_FLAG_SIGNED &&
413       message->data_len + message->pad_len + 6 + mac_len +
414       iv_len < silc_buffer_len(&buffer)) {
415     if (!silc_message_signed_payload_parse(buffer.data + 6 +
416                                            message->data_len +
417                                            message->pad_len,
418                                            silc_buffer_len(&buffer) -
419                                            iv_len - mac_len - 6 -
420                                            message->data_len -
421                                            message->pad_len,
422                                            &message->sig))
423       goto err;
424   }
425
426   /* Parse MAC from the payload */
427   if (mac_len)
428     message->mac = buffer.data + (silc_buffer_len(&buffer) - mac_len);
429
430   return newp;
431
432  err:
433   if (newp)
434     silc_message_payload_free(newp);
435   return NULL;
436 }
437
438
439 /***************************** Payload encoding *****************************/
440
441 /* This function is used to encrypt the Messsage Payload which is
442    the `data' and `data_len'.  This is used internally by the Message
443    Payload encoding routines but application may call this too if needed.
444    The `true_len' is the data length which is used to create MAC out of. */
445
446 SilcBool silc_message_payload_encrypt(unsigned char *data,
447                                       SilcUInt32 data_len,
448                                       SilcUInt32 true_len,
449                                       unsigned char *iv,
450                                       SilcCipher cipher,
451                                       SilcHmac hmac)
452 {
453   /* Encrypt payload of the packet */
454   if (silc_unlikely(!silc_cipher_encrypt(cipher, data, data, data_len, iv)))
455     return FALSE;
456
457   /* Compute the MAC of the encrypted message data */
458   silc_hmac_init(hmac);
459   silc_hmac_update(hmac, data, true_len);
460   silc_hmac_final(hmac, data + true_len, NULL);
461
462   return TRUE;
463 }
464
465 /* Encrypt message payload */
466
467 static int silc_message_payload_encode_encrypt(SilcBuffer buffer,
468                                                void *value, void *context)
469 {
470   SilcMessageEncode *e = context;
471   SilcUInt32 mac_len;
472
473   if (!e->cipher || !e->hmac)
474     return 0;
475
476   mac_len = silc_hmac_len(e->hmac);
477   if (silc_unlikely(!silc_buffer_enlarge(buffer, mac_len)))
478     return -1;
479
480   if (silc_unlikely(!silc_message_payload_encrypt(buffer->head,
481                                                   e->payload_len,
482                                                   silc_buffer_headlen(buffer),
483                                                   e->iv, e->cipher, e->hmac)))
484     return -1;
485
486   return mac_len;
487 }
488
489 /* Compute message signature */
490
491 static int silc_message_payload_encode_sig(SilcBuffer buffer,
492                                            void *value, void *context)
493 {
494   SilcMessageEncode *e = context;
495   SilcBuffer sig;
496   int len;
497
498   if (!(e->flags & SILC_MESSAGE_FLAG_SIGNED))
499     return 0;
500
501   sig = silc_message_signed_payload_encode(buffer->head,
502                                            silc_buffer_headlen(buffer),
503                                            e->public_key, e->private_key,
504                                            e->hash);
505   if (silc_unlikely(!sig))
506     return -1;
507
508   len = silc_buffer_format(buffer,
509                            SILC_STR_DATA(silc_buffer_data(sig),
510                                          silc_buffer_len(sig)),
511                            SILC_STR_END);
512   if (silc_unlikely(len < 0)) {
513     silc_buffer_free(sig);
514     return -1;
515   }
516
517   silc_buffer_free(sig);
518   return len;
519 }
520
521 /* Encodes Message Payload into a buffer and returns it. */
522
523 SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
524                                        const unsigned char *data,
525                                        SilcUInt32 data_len,
526                                        SilcBool generate_iv,
527                                        SilcBool private_message,
528                                        SilcCipher cipher,
529                                        SilcHmac hmac,
530                                        SilcRng rng,
531                                        SilcPublicKey public_key,
532                                        SilcPrivateKey private_key,
533                                        SilcHash hash,
534                                        SilcBuffer buffer)
535 {
536   SilcUInt32 pad_len = 0, mac_len = 0, iv_len = 0;
537   unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE];
538   SilcBuffer buf = NULL;
539   SilcMessageEncode e;
540   int i;
541
542   SILC_LOG_DEBUG(("Encoding Message Payload"));
543
544   if (silc_unlikely(!data_len))
545     return NULL;
546   if (silc_unlikely(!private_message && (!cipher || !hmac)))
547     return NULL;
548
549   if (!buffer) {
550     buf = buffer = silc_buffer_alloc(0);
551     if (silc_unlikely(!buf))
552       return NULL;
553   }
554   silc_buffer_reset(buffer);
555
556   /* For channel messages IV is always generated */
557   if (!private_message && !generate_iv)
558     generate_iv = TRUE;
559
560   /* Generate IV */
561   if (cipher && generate_iv) {
562     iv_len = silc_cipher_get_block_len(cipher);
563     if (rng) {
564       for (i = 0; i < iv_len; i++) iv[i] = silc_rng_get_byte_fast(rng);
565     } else {
566       for (i = 0; i < iv_len; i++) iv[i] = silc_rng_global_get_byte_fast();
567     }
568   }
569
570   if (hmac)
571     mac_len = silc_hmac_len(hmac);
572   data_len = silc_message_payload_datalen(data_len, mac_len + iv_len, flags,
573                                           public_key, private_key);
574
575   /* Calculate length of padding. IV is not included into the calculation
576      since it is not encrypted. */
577   pad_len = SILC_MESSAGE_PAD(6 + data_len);
578
579   /* Generate padding */
580   if (cipher) {
581     if (rng) {
582       for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
583     } else {
584       for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
585     }
586   }
587
588   e.flags = flags;
589   e.public_key = public_key;
590   e.private_key = private_key;
591   e.hash = hash;
592   e.cipher = cipher;
593   e.hmac = hmac;
594   e.iv = iv_len ? iv : NULL;
595   e.payload_len = 6 + data_len + pad_len;
596
597   /* Encode the Message Payload */
598   if (silc_buffer_format(buffer,
599                          SILC_STR_UI_SHORT(flags),
600                          SILC_STR_UI_SHORT(data_len),
601                          SILC_STR_DATA(data, data_len),
602                          SILC_STR_UI_SHORT(pad_len),
603                          SILC_STR_DATA(pad, pad_len),
604                          SILC_STR_FUNC(silc_message_payload_encode_sig,
605                                        NULL, &e),
606                          SILC_STR_DATA(iv, iv_len),
607                          SILC_STR_FUNC(silc_message_payload_encode_encrypt,
608                                        NULL, &e),
609                          SILC_STR_END) < 0) {
610     silc_buffer_free(buf);
611     return NULL;
612   }
613
614   return buffer;
615 }
616
617 /* Free's Message Payload */
618
619 void silc_message_payload_free(SilcMessagePayload payload)
620 {
621   if (payload->data) {
622     memset(payload->data, 0, payload->data_len);
623     if (payload->allocated)
624       silc_free(payload->data);
625   }
626   if (payload->allocated) {
627     silc_free(payload->pad);
628     silc_free(payload);
629   }
630   silc_message_signed_payload_free(&payload->sig);
631 }
632
633 /* Return flags */
634
635 SilcMessageFlags silc_message_get_flags(SilcMessagePayload payload)
636 {
637   return payload->flags;
638 }
639
640 /* Return data */
641
642 unsigned char *silc_message_get_data(SilcMessagePayload payload,
643                                      SilcUInt32 *data_len)
644 {
645   if (data_len)
646     *data_len = payload->data_len;
647   return payload->data;
648 }
649
650 /* Return MAC. The caller knows the length of the MAC */
651
652 unsigned char *silc_message_get_mac(SilcMessagePayload payload)
653 {
654   return payload->mac;
655 }
656
657 /* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */
658
659 SilcAuthResult silc_message_signed_verify(SilcMessagePayload message,
660                                           SilcPublicKey remote_public_key,
661                                           SilcHash hash)
662 {
663   int ret = SILC_AUTH_FAILED;
664   SilcBuffer sign, tmp;
665   SilcMessageSignedPayload sig = &message->sig;
666
667   if (!(message->flags & SILC_MESSAGE_FLAG_SIGNED) ||
668       !sig->sign_len || !remote_public_key || !hash)
669     return ret;
670
671   /* Generate the signature verification data, the Message Payload */
672   tmp = silc_buffer_alloc_size(6 + message->data_len + message->pad_len);
673   silc_buffer_format(tmp,
674                      SILC_STR_UI_SHORT(message->flags),
675                      SILC_STR_UI_SHORT(message->data_len),
676                      SILC_STR_UI_XNSTRING(message->data, message->data_len),
677                      SILC_STR_UI_SHORT(message->pad_len),
678                      SILC_STR_UI_XNSTRING(message->pad, message->pad_len),
679                      SILC_STR_END);
680   sign = silc_message_signed_encode_data(tmp->data, silc_buffer_len(tmp),
681                                          sig->pk_data, sig->pk_len,
682                                          sig->pk_type);
683   silc_buffer_clear(tmp);
684   silc_buffer_free(tmp);
685
686   if (!sign)
687     return ret;
688
689   /* Verify the authentication data */
690   if (!silc_pkcs_verify(remote_public_key, sig->sign_data, sig->sign_len,
691                         silc_buffer_data(sign), silc_buffer_len(sign), hash)) {
692     silc_buffer_clear(sign);
693     silc_buffer_free(sign);
694     SILC_LOG_DEBUG(("Signature verification failed"));
695     return ret;
696   }
697
698   ret = SILC_AUTH_OK;
699
700   silc_buffer_clear(sign);
701   silc_buffer_free(sign);
702
703   SILC_LOG_DEBUG(("Signature verification successful"));
704
705   return ret;
706 }
707
708 /* Return the public key from the payload */
709
710 SilcPublicKey
711 silc_message_signed_get_public_key(SilcMessagePayload payload,
712                                    const unsigned char **pk_data,
713                                    SilcUInt32 *pk_data_len)
714 {
715   SilcPublicKey pk;
716   SilcMessageSignedPayload sig = &payload->sig;
717
718   if (!sig->pk_data)
719     return NULL;
720
721   if (!silc_pkcs_public_key_alloc(sig->pk_type, sig->pk_data,
722                                   sig->pk_len, &pk))
723     return NULL;
724
725   if (pk_data)
726     *pk_data = sig->pk_data;
727   if (pk_data_len)
728     *pk_data_len = sig->pk_len;
729
730   return pk;
731 }