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