Tizen 2.0 Release
[external/libgnutls26.git] / lib / openpgp / pgp.c
1 /*
2  * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
3  * Free Software Foundation, Inc.
4  *
5  * Author: Timo Schulz, Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * The GnuTLS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301, USA
23  *
24  */
25
26 /* Functions on OpenPGP key parsing
27  */
28
29 #include <gnutls_int.h>
30 #include <gnutls_datum.h>
31 #include <gnutls_global.h>
32 #include <gnutls_errors.h>
33 #include <openpgp_int.h>
34 #include <gnutls_str.h>
35 #include <gnutls_num.h>
36 #include <x509/common.h>
37
38 /**
39  * gnutls_openpgp_crt_init:
40  * @key: The structure to be initialized
41  *
42  * This function will initialize an OpenPGP key structure.
43  *
44  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
45  **/
46 int
47 gnutls_openpgp_crt_init (gnutls_openpgp_crt_t * key)
48 {
49   *key = gnutls_calloc (1, sizeof (gnutls_openpgp_crt_int));
50
51   if (*key)
52     return 0;                   /* success */
53   return GNUTLS_E_MEMORY_ERROR;
54 }
55
56 /**
57  * gnutls_openpgp_crt_deinit:
58  * @key: The structure to be initialized
59  *
60  * This function will deinitialize a key structure.
61  **/
62 void
63 gnutls_openpgp_crt_deinit (gnutls_openpgp_crt_t key)
64 {
65   if (!key)
66     return;
67
68   if (key->knode)
69     {
70       cdk_kbnode_release (key->knode);
71       key->knode = NULL;
72     }
73
74   gnutls_free (key);
75 }
76
77 /**
78  * gnutls_openpgp_crt_import:
79  * @key: The structure to store the parsed key.
80  * @data: The RAW or BASE64 encoded key.
81  * @format: One of gnutls_openpgp_crt_fmt_t elements.
82  *
83  * This function will convert the given RAW or Base64 encoded key to
84  * the native #gnutls_openpgp_crt_t format. The output will be stored
85  * in 'key'.
86  *
87  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
88  **/
89 int
90 gnutls_openpgp_crt_import (gnutls_openpgp_crt_t key,
91                            const gnutls_datum_t * data,
92                            gnutls_openpgp_crt_fmt_t format)
93 {
94   cdk_stream_t inp;
95   cdk_packet_t pkt;
96   int rc;
97
98   if (data->data == NULL || data->size == 0)
99     {
100       gnutls_assert ();
101       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
102     }
103
104   if (format == GNUTLS_OPENPGP_FMT_RAW)
105     {
106       rc = cdk_kbnode_read_from_mem (&key->knode, data->data, data->size);
107       if (rc)
108         {
109           rc = _gnutls_map_cdk_rc (rc);
110           gnutls_assert ();
111           return rc;
112         }
113     }
114   else
115     {
116       rc = cdk_stream_tmp_from_mem (data->data, data->size, &inp);
117       if (rc)
118         {
119           rc = _gnutls_map_cdk_rc (rc);
120           gnutls_assert ();
121           return rc;
122         }
123       if (cdk_armor_filter_use (inp))
124         rc = cdk_stream_set_armor_flag (inp, 0);
125       if (!rc)
126         rc = cdk_keydb_get_keyblock (inp, &key->knode);
127       cdk_stream_close (inp);
128       if (rc)
129         {
130           if (rc == CDK_Inv_Packet)
131             rc = GNUTLS_E_OPENPGP_GETKEY_FAILED;
132           else
133             rc = _gnutls_map_cdk_rc (rc);
134           gnutls_assert ();
135           return rc;
136         }
137     }
138
139   /* Test if the import was successful. */
140   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
141   if (pkt == NULL)
142     {
143       gnutls_assert ();
144       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
145     }
146
147   return 0;
148 }
149
150 /* internal version of export
151  */
152 int
153 _gnutls_openpgp_export (cdk_kbnode_t node,
154                         gnutls_openpgp_crt_fmt_t format,
155                         void *output_data,
156                         size_t * output_data_size, int private)
157 {
158   size_t input_data_size = *output_data_size;
159   size_t calc_size;
160   int rc;
161
162   rc = cdk_kbnode_write_to_mem (node, output_data, output_data_size);
163   if (rc)
164     {
165       rc = _gnutls_map_cdk_rc (rc);
166       gnutls_assert ();
167       return rc;
168     }
169
170   /* If the caller uses output_data == NULL then return what he expects.
171    */
172   if (!output_data)
173     {
174       gnutls_assert ();
175       return GNUTLS_E_SHORT_MEMORY_BUFFER;
176     }
177
178   if (format == GNUTLS_OPENPGP_FMT_BASE64)
179     {
180       unsigned char *in = gnutls_calloc (1, *output_data_size);
181       memcpy (in, output_data, *output_data_size);
182
183       /* Calculate the size of the encoded data and check if the provided
184          buffer is large enough. */
185       rc = cdk_armor_encode_buffer (in, *output_data_size,
186                                     NULL, 0, &calc_size,
187                                     private ? CDK_ARMOR_SECKEY :
188                                     CDK_ARMOR_PUBKEY);
189       if (rc || calc_size > input_data_size)
190         {
191           gnutls_free (in);
192           *output_data_size = calc_size;
193           gnutls_assert ();
194           return GNUTLS_E_SHORT_MEMORY_BUFFER;
195         }
196
197       rc = cdk_armor_encode_buffer (in, *output_data_size,
198                                     output_data, input_data_size, &calc_size,
199                                     private ? CDK_ARMOR_SECKEY :
200                                     CDK_ARMOR_PUBKEY);
201       gnutls_free (in);
202       *output_data_size = calc_size;
203
204       if (rc)
205         {
206           rc = _gnutls_map_cdk_rc (rc);
207           gnutls_assert ();
208           return rc;
209         }
210     }
211
212   return 0;
213
214 }
215
216 /**
217  * gnutls_openpgp_crt_export:
218  * @key: Holds the key.
219  * @format: One of gnutls_openpgp_crt_fmt_t elements.
220  * @output_data: will contain the key base64 encoded or raw
221  * @output_data_size: holds the size of output_data (and will
222  *   be replaced by the actual size of parameters)
223  *
224  * This function will convert the given key to RAW or Base64 format.
225  * If the buffer provided is not long enough to hold the output, then
226  * %GNUTLS_E_SHORT_MEMORY_BUFFER will be returned.
227  *
228  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
229  **/
230 int
231 gnutls_openpgp_crt_export (gnutls_openpgp_crt_t key,
232                            gnutls_openpgp_crt_fmt_t format,
233                            void *output_data, size_t * output_data_size)
234 {
235   return _gnutls_openpgp_export (key->knode, format, output_data,
236                                  output_data_size, 0);
237 }
238
239 /**
240  * gnutls_openpgp_crt_get_fingerprint:
241  * @key: the raw data that contains the OpenPGP public key.
242  * @fpr: the buffer to save the fingerprint, must hold at least 20 bytes.
243  * @fprlen: the integer to save the length of the fingerprint.
244  *
245  * Get key fingerprint.  Depending on the algorithm, the fingerprint
246  * can be 16 or 20 bytes.
247  *
248  * Returns: On success, 0 is returned.  Otherwise, an error code.
249  **/
250 int
251 gnutls_openpgp_crt_get_fingerprint (gnutls_openpgp_crt_t key,
252                                     void *fpr, size_t * fprlen)
253 {
254   cdk_packet_t pkt;
255   cdk_pkt_pubkey_t pk = NULL;
256
257   if (!fpr || !fprlen)
258     {
259       gnutls_assert ();
260       return GNUTLS_E_INVALID_REQUEST;
261     }
262
263   *fprlen = 0;
264
265   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
266   if (!pkt)
267     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
268
269   pk = pkt->pkt.public_key;
270   *fprlen = 20;
271
272   /* FIXME: Check if the draft allows old PGP keys. */
273   if (is_RSA (pk->pubkey_algo) && pk->version < 4)
274     *fprlen = 16;
275   cdk_pk_get_fingerprint (pk, fpr);
276
277   return 0;
278 }
279
280 static int
281 _gnutls_openpgp_count_key_names (gnutls_openpgp_crt_t key)
282 {
283   cdk_kbnode_t p, ctx;
284   cdk_packet_t pkt;
285   int nuids;
286
287   if (key == NULL)
288     {
289       gnutls_assert ();
290       return 0;
291     }
292
293   ctx = NULL;
294   nuids = 0;
295   while ((p = cdk_kbnode_walk (key->knode, &ctx, 0)))
296     {
297       pkt = cdk_kbnode_get_packet (p);
298       if (pkt->pkttype == CDK_PKT_USER_ID)
299         nuids++;
300     }
301
302   return nuids;
303 }
304
305
306 /**
307  * gnutls_openpgp_crt_get_name:
308  * @key: the structure that contains the OpenPGP public key.
309  * @idx: the index of the ID to extract
310  * @buf: a pointer to a structure to hold the name, may be %NULL
311  *       to only get the @sizeof_buf.
312  * @sizeof_buf: holds the maximum size of @buf, on return hold the
313  *   actual/required size of @buf.
314  *
315  * Extracts the userID from the parsed OpenPGP key.
316  *
317  * Returns: %GNUTLS_E_SUCCESS on success, and if the index of the ID
318  *   does not exist %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE, or an
319  *   error code.
320  **/
321 int
322 gnutls_openpgp_crt_get_name (gnutls_openpgp_crt_t key,
323                              int idx, char *buf, size_t * sizeof_buf)
324 {
325   cdk_kbnode_t ctx = NULL, p;
326   cdk_packet_t pkt = NULL;
327   cdk_pkt_userid_t uid = NULL;
328   int pos = 0;
329
330   if (!key)
331     {
332       gnutls_assert ();
333       return GNUTLS_E_INVALID_REQUEST;
334     }
335
336   if (idx < 0 || idx >= _gnutls_openpgp_count_key_names (key))
337     return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
338
339   pos = 0;
340   while ((p = cdk_kbnode_walk (key->knode, &ctx, 0)))
341     {
342       pkt = cdk_kbnode_get_packet (p);
343       if (pkt->pkttype == CDK_PKT_USER_ID)
344         {
345           if (pos == idx)
346             break;
347           pos++;
348         }
349     }
350
351   if (!pkt)
352     {
353       gnutls_assert ();
354       return GNUTLS_E_INTERNAL_ERROR;
355     }
356
357   uid = pkt->pkt.user_id;
358   if (uid->len >= *sizeof_buf)
359     {
360       gnutls_assert ();
361       *sizeof_buf = uid->len + 1;
362       return GNUTLS_E_SHORT_MEMORY_BUFFER;
363     }
364
365   if (buf)
366     {
367       memcpy (buf, uid->name, uid->len);
368       buf[uid->len] = '\0';     /* make sure it's a string */
369     }
370   *sizeof_buf = uid->len + 1;
371
372   if (uid->is_revoked)
373     return GNUTLS_E_OPENPGP_UID_REVOKED;
374
375   return 0;
376 }
377
378 /**
379  * gnutls_openpgp_crt_get_pk_algorithm:
380  * @key: is an OpenPGP key
381  * @bits: if bits is non null it will hold the size of the parameters' in bits
382  *
383  * This function will return the public key algorithm of an OpenPGP
384  * certificate.
385  *
386  * If bits is non null, it should have enough size to hold the parameters
387  * size in bits. For RSA the bits returned is the modulus.
388  * For DSA the bits returned are of the public exponent.
389  *
390  * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
391  *   success, or GNUTLS_PK_UNKNOWN on error.
392  **/
393 gnutls_pk_algorithm_t
394 gnutls_openpgp_crt_get_pk_algorithm (gnutls_openpgp_crt_t key,
395                                      unsigned int *bits)
396 {
397   cdk_packet_t pkt;
398   int algo;
399
400   if (!key)
401     {
402       gnutls_assert ();
403       return GNUTLS_PK_UNKNOWN;
404     }
405
406   algo = 0;
407   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
408   if (pkt)
409     {
410       if (bits)
411         *bits = cdk_pk_get_nbits (pkt->pkt.public_key);
412       algo = _gnutls_openpgp_get_algo (pkt->pkt.public_key->pubkey_algo);
413     }
414
415   return algo;
416 }
417
418
419 /**
420  * gnutls_openpgp_crt_get_version:
421  * @key: the structure that contains the OpenPGP public key.
422  *
423  * Extract the version of the OpenPGP key.
424  *
425  * Returns: the version number is returned, or a negative value on errors.
426  **/
427 int
428 gnutls_openpgp_crt_get_version (gnutls_openpgp_crt_t key)
429 {
430   cdk_packet_t pkt;
431   int version;
432
433   if (!key)
434     return -1;
435
436   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
437   if (pkt)
438     version = pkt->pkt.public_key->version;
439   else
440     version = 0;
441
442   return version;
443 }
444
445
446 /**
447  * gnutls_openpgp_crt_get_creation_time:
448  * @key: the structure that contains the OpenPGP public key.
449  *
450  * Get key creation time.
451  *
452  * Returns: the timestamp when the OpenPGP key was created.
453  **/
454 time_t
455 gnutls_openpgp_crt_get_creation_time (gnutls_openpgp_crt_t key)
456 {
457   cdk_packet_t pkt;
458   time_t timestamp;
459
460   if (!key)
461     return (time_t) - 1;
462
463   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
464   if (pkt)
465     timestamp = pkt->pkt.public_key->timestamp;
466   else
467     timestamp = 0;
468
469   return timestamp;
470 }
471
472
473 /**
474  * gnutls_openpgp_crt_get_expiration_time:
475  * @key: the structure that contains the OpenPGP public key.
476  *
477  * Get key expiration time.  A value of '0' means that the key doesn't
478  * expire at all.
479  *
480  * Returns: the time when the OpenPGP key expires.
481  **/
482 time_t
483 gnutls_openpgp_crt_get_expiration_time (gnutls_openpgp_crt_t key)
484 {
485   cdk_packet_t pkt;
486   time_t expiredate;
487
488   if (!key)
489     return (time_t) - 1;
490
491   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
492   if (pkt)
493     expiredate = pkt->pkt.public_key->expiredate;
494   else
495     expiredate = 0;
496
497   return expiredate;
498 }
499
500 /**
501  * gnutls_openpgp_crt_get_key_id:
502  * @key: the structure that contains the OpenPGP public key.
503  * @keyid: the buffer to save the keyid.
504  *
505  * Get key id string.
506  *
507  * Returns: the 64-bit keyID of the OpenPGP key.
508  *
509  * Since: 2.4.0
510  **/
511 int
512 gnutls_openpgp_crt_get_key_id (gnutls_openpgp_crt_t key,
513                                gnutls_openpgp_keyid_t keyid)
514 {
515   cdk_packet_t pkt;
516   uint32_t kid[2];
517
518   if (!key || !keyid)
519     {
520       gnutls_assert ();
521       return GNUTLS_E_INVALID_REQUEST;
522     }
523
524   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
525   if (!pkt)
526     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
527
528   cdk_pk_get_keyid (pkt->pkt.public_key, kid);
529   _gnutls_write_uint32 (kid[0], keyid);
530   _gnutls_write_uint32 (kid[1], keyid + 4);
531
532   return 0;
533 }
534
535 /**
536  * gnutls_openpgp_crt_get_revoked_status:
537  * @key: the structure that contains the OpenPGP public key.
538  *
539  * Get revocation status of key.
540  *
541  * Returns: true (1) if the key has been revoked, or false (0) if it
542  *   has not.
543  *
544  * Since: 2.4.0
545  **/
546 int
547 gnutls_openpgp_crt_get_revoked_status (gnutls_openpgp_crt_t key)
548 {
549   cdk_packet_t pkt;
550
551   if (!key)
552     {
553       gnutls_assert ();
554       return GNUTLS_E_INVALID_REQUEST;
555     }
556
557   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
558   if (!pkt)
559     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
560
561   if (pkt->pkt.public_key->is_revoked != 0)
562     return 1;
563   return 0;
564 }
565
566 /**
567  * gnutls_openpgp_crt_check_hostname:
568  * @key: should contain a #gnutls_openpgp_crt_t structure
569  * @hostname: A null terminated string that contains a DNS name
570  *
571  * This function will check if the given key's owner matches the
572  * given hostname. This is a basic implementation of the matching
573  * described in RFC2818 (HTTPS), which takes into account wildcards.
574  *
575  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
576  **/
577 int
578 gnutls_openpgp_crt_check_hostname (gnutls_openpgp_crt_t key,
579                                    const char *hostname)
580 {
581   char dnsname[MAX_CN];
582   size_t dnsnamesize;
583   int ret = 0;
584   int i;
585
586   /* Check through all included names. */
587   for (i = 0; !(ret < 0); i++)
588     {
589       dnsnamesize = sizeof (dnsname);
590       ret = gnutls_openpgp_crt_get_name (key, i, dnsname, &dnsnamesize);
591
592       if (ret == 0)
593         {
594           /* Length returned by gnutls_openpgp_crt_get_name includes
595              the terminating zero. */
596           dnsnamesize--;
597
598           if (_gnutls_hostname_compare (dnsname, dnsnamesize, hostname, 0))
599             return 1;
600         }
601     }
602
603   /* not found a matching name */
604   return 0;
605 }
606
607 unsigned int
608 _gnutls_get_pgp_key_usage (unsigned int cdk_usage)
609 {
610   unsigned int usage = 0;
611
612   if (cdk_usage & CDK_KEY_USG_CERT_SIGN)
613     usage |= GNUTLS_KEY_KEY_CERT_SIGN;
614   if (cdk_usage & CDK_KEY_USG_DATA_SIGN)
615     usage |= GNUTLS_KEY_DIGITAL_SIGNATURE;
616   if (cdk_usage & CDK_KEY_USG_COMM_ENCR)
617     usage |= GNUTLS_KEY_KEY_ENCIPHERMENT;
618   if (cdk_usage & CDK_KEY_USG_STORAGE_ENCR)
619     usage |= GNUTLS_KEY_DATA_ENCIPHERMENT;
620   if (cdk_usage & CDK_KEY_USG_AUTH)
621     usage |= GNUTLS_KEY_KEY_AGREEMENT;
622
623   return usage;
624 }
625
626 /**
627  * gnutls_openpgp_crt_get_key_usage:
628  * @key: should contain a gnutls_openpgp_crt_t structure
629  * @key_usage: where the key usage bits will be stored
630  *
631  * This function will return certificate's key usage, by checking the
632  * key algorithm. The key usage value will ORed values of the:
633  * %GNUTLS_KEY_DIGITAL_SIGNATURE, %GNUTLS_KEY_KEY_ENCIPHERMENT.
634  *
635  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
636  */
637 int
638 gnutls_openpgp_crt_get_key_usage (gnutls_openpgp_crt_t key,
639                                   unsigned int *key_usage)
640 {
641   cdk_packet_t pkt;
642
643   if (!key)
644     {
645       gnutls_assert ();
646       return GNUTLS_E_INVALID_REQUEST;
647     }
648
649   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_PUBLIC_KEY);
650   if (!pkt)
651     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
652
653   *key_usage = _gnutls_get_pgp_key_usage (pkt->pkt.public_key->pubkey_usage);
654
655   return 0;
656 }
657
658 /**
659  * gnutls_openpgp_crt_get_subkey_count:
660  * @key: is an OpenPGP key
661  *
662  * This function will return the number of subkeys present in the
663  * given OpenPGP certificate.
664  *
665  * Returns: the number of subkeys, or a negative value on error.
666  *
667  * Since: 2.4.0
668  **/
669 int
670 gnutls_openpgp_crt_get_subkey_count (gnutls_openpgp_crt_t key)
671 {
672   cdk_kbnode_t p, ctx;
673   cdk_packet_t pkt;
674   int subkeys;
675
676   if (key == NULL)
677     {
678       gnutls_assert ();
679       return 0;
680     }
681
682   ctx = NULL;
683   subkeys = 0;
684   while ((p = cdk_kbnode_walk (key->knode, &ctx, 0)))
685     {
686       pkt = cdk_kbnode_get_packet (p);
687       if (pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
688         subkeys++;
689     }
690
691   return subkeys;
692 }
693
694 /* returns the subkey with the given index */
695 static cdk_packet_t
696 _get_public_subkey (gnutls_openpgp_crt_t key, unsigned int indx)
697 {
698   cdk_kbnode_t p, ctx;
699   cdk_packet_t pkt;
700   unsigned int subkeys;
701
702   if (key == NULL)
703     {
704       gnutls_assert ();
705       return NULL;
706     }
707
708   ctx = NULL;
709   subkeys = 0;
710   while ((p = cdk_kbnode_walk (key->knode, &ctx, 0)))
711     {
712       pkt = cdk_kbnode_get_packet (p);
713       if (pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY && indx == subkeys++)
714         return pkt;
715     }
716
717   return NULL;
718 }
719
720 /* returns the key with the given keyid. It can be either key or subkey.
721  * depending on what requested:
722  *   pkt->pkt.secret_key;
723  *   pkt->pkt.public_key;
724  */
725 cdk_packet_t
726 _gnutls_openpgp_find_key (cdk_kbnode_t knode, uint32_t keyid[2],
727                           unsigned int priv)
728 {
729   cdk_kbnode_t p, ctx;
730   cdk_packet_t pkt;
731   uint32_t local_keyid[2];
732
733   ctx = NULL;
734   while ((p = cdk_kbnode_walk (knode, &ctx, 0)))
735     {
736       pkt = cdk_kbnode_get_packet (p);
737
738       if ((priv == 0
739            && (pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY
740                || pkt->pkttype == CDK_PKT_PUBLIC_KEY)) || (priv != 0
741                                                            && (pkt->pkttype ==
742                                                                CDK_PKT_SECRET_SUBKEY
743                                                                || pkt->pkttype
744                                                                ==
745                                                                CDK_PKT_SECRET_KEY)))
746         {
747           if (priv == 0)
748             cdk_pk_get_keyid (pkt->pkt.public_key, local_keyid);
749           else
750             cdk_pk_get_keyid (pkt->pkt.secret_key->pk, local_keyid);
751
752           if (local_keyid[0] == keyid[0] && local_keyid[1] == keyid[1])
753             {
754               return pkt;
755             }
756         }
757     }
758
759   gnutls_assert ();
760   return NULL;
761 }
762
763 /* returns the key with the given keyid
764  * depending on what requested:
765  *   pkt->pkt.secret_key;
766  *   pkt->pkt.public_key;
767  */
768 int
769 _gnutls_openpgp_find_subkey_idx (cdk_kbnode_t knode, uint32_t keyid[2],
770                                  unsigned int priv)
771 {
772   cdk_kbnode_t p, ctx;
773   cdk_packet_t pkt;
774   int i = 0;
775   uint32_t local_keyid[2];
776
777   _gnutls_hard_log ("Looking keyid: %x.%x\n", keyid[0], keyid[1]);
778
779   ctx = NULL;
780   while ((p = cdk_kbnode_walk (knode, &ctx, 0)))
781     {
782       pkt = cdk_kbnode_get_packet (p);
783
784       if ((priv == 0 && (pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)) ||
785           (priv != 0 && (pkt->pkttype == CDK_PKT_SECRET_SUBKEY)))
786         {
787           if (priv == 0)
788             cdk_pk_get_keyid (pkt->pkt.public_key, local_keyid);
789           else
790             cdk_pk_get_keyid (pkt->pkt.secret_key->pk, local_keyid);
791
792           _gnutls_hard_log ("Found keyid: %x.%x\n", local_keyid[0],
793                             local_keyid[1]);
794           if (local_keyid[0] == keyid[0] && local_keyid[1] == keyid[1])
795             {
796               return i;
797             }
798           i++;
799         }
800     }
801
802   gnutls_assert ();
803   return GNUTLS_E_OPENPGP_SUBKEY_ERROR;
804 }
805
806 /**
807  * gnutls_openpgp_crt_get_subkey_revoked_status:
808  * @key: the structure that contains the OpenPGP public key.
809  * @idx: is the subkey index
810  *
811  * Get subkey revocation status.  A negative value indicates an error.
812  *
813  * Returns: true (1) if the key has been revoked, or false (0) if it
814  *   has not.
815  *
816  * Since: 2.4.0
817  **/
818 int
819 gnutls_openpgp_crt_get_subkey_revoked_status (gnutls_openpgp_crt_t key,
820                                               unsigned int idx)
821 {
822   cdk_packet_t pkt;
823
824   if (!key)
825     {
826       gnutls_assert ();
827       return GNUTLS_E_INVALID_REQUEST;
828     }
829
830   pkt = _get_public_subkey (key, idx);
831   if (!pkt)
832     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
833
834   if (pkt->pkt.public_key->is_revoked != 0)
835     return 1;
836   return 0;
837 }
838
839 /**
840  * gnutls_openpgp_crt_get_subkey_pk_algorithm:
841  * @key: is an OpenPGP key
842  * @idx: is the subkey index
843  * @bits: if bits is non null it will hold the size of the parameters' in bits
844  *
845  * This function will return the public key algorithm of a subkey of an OpenPGP
846  * certificate.
847  *
848  * If bits is non null, it should have enough size to hold the
849  * parameters size in bits.  For RSA the bits returned is the modulus.
850  * For DSA the bits returned are of the public exponent.
851  *
852  * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
853  *   success, or GNUTLS_PK_UNKNOWN on error.
854  *
855  * Since: 2.4.0
856  **/
857 gnutls_pk_algorithm_t
858 gnutls_openpgp_crt_get_subkey_pk_algorithm (gnutls_openpgp_crt_t key,
859                                             unsigned int idx,
860                                             unsigned int *bits)
861 {
862   cdk_packet_t pkt;
863   int algo;
864
865   if (!key)
866     {
867       gnutls_assert ();
868       return GNUTLS_PK_UNKNOWN;
869     }
870
871   pkt = _get_public_subkey (key, idx);
872
873   algo = 0;
874   if (pkt)
875     {
876       if (bits)
877         *bits = cdk_pk_get_nbits (pkt->pkt.public_key);
878       algo = _gnutls_openpgp_get_algo (pkt->pkt.public_key->pubkey_algo);
879     }
880
881   return algo;
882 }
883
884 /**
885  * gnutls_openpgp_crt_get_subkey_creation_time:
886  * @key: the structure that contains the OpenPGP public key.
887  * @idx: the subkey index
888  *
889  * Get subkey creation time.
890  *
891  * Returns: the timestamp when the OpenPGP sub-key was created.
892  *
893  * Since: 2.4.0
894  **/
895 time_t
896 gnutls_openpgp_crt_get_subkey_creation_time (gnutls_openpgp_crt_t key,
897                                              unsigned int idx)
898 {
899   cdk_packet_t pkt;
900   time_t timestamp;
901
902   if (!key)
903     return (time_t) - 1;
904
905   pkt = _get_public_subkey (key, idx);
906   if (pkt)
907     timestamp = pkt->pkt.public_key->timestamp;
908   else
909     timestamp = 0;
910
911   return timestamp;
912 }
913
914
915 /**
916  * gnutls_openpgp_crt_get_subkey_expiration_time:
917  * @key: the structure that contains the OpenPGP public key.
918  * @idx: the subkey index
919  *
920  * Get subkey expiration time.  A value of '0' means that the key
921  * doesn't expire at all.
922  *
923  * Returns: the time when the OpenPGP key expires.
924  *
925  * Since: 2.4.0
926  **/
927 time_t
928 gnutls_openpgp_crt_get_subkey_expiration_time (gnutls_openpgp_crt_t key,
929                                                unsigned int idx)
930 {
931   cdk_packet_t pkt;
932   time_t expiredate;
933
934   if (!key)
935     return (time_t) - 1;
936
937   pkt = _get_public_subkey (key, idx);
938   if (pkt)
939     expiredate = pkt->pkt.public_key->expiredate;
940   else
941     expiredate = 0;
942
943   return expiredate;
944 }
945
946 /**
947  * gnutls_openpgp_crt_get_subkey_id:
948  * @key: the structure that contains the OpenPGP public key.
949  * @idx: the subkey index
950  * @keyid: the buffer to save the keyid.
951  *
952  * Get the subkey's key-id.
953  *
954  * Returns: the 64-bit keyID of the OpenPGP key.
955  **/
956 int
957 gnutls_openpgp_crt_get_subkey_id (gnutls_openpgp_crt_t key,
958                                   unsigned int idx,
959                                   gnutls_openpgp_keyid_t keyid)
960 {
961   cdk_packet_t pkt;
962   uint32_t kid[2];
963
964   if (!key || !keyid)
965     {
966       gnutls_assert ();
967       return GNUTLS_E_INVALID_REQUEST;
968     }
969
970   pkt = _get_public_subkey (key, idx);
971   if (!pkt)
972     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
973
974   cdk_pk_get_keyid (pkt->pkt.public_key, kid);
975   _gnutls_write_uint32 (kid[0], keyid);
976   _gnutls_write_uint32 (kid[1], keyid + 4);
977
978   return 0;
979 }
980
981 /**
982  * gnutls_openpgp_crt_get_subkey_fingerprint:
983  * @key: the raw data that contains the OpenPGP public key.
984  * @idx: the subkey index
985  * @fpr: the buffer to save the fingerprint, must hold at least 20 bytes.
986  * @fprlen: the integer to save the length of the fingerprint.
987  *
988  * Get key fingerprint of a subkey.  Depending on the algorithm, the
989  * fingerprint can be 16 or 20 bytes.
990  *
991  * Returns: On success, 0 is returned.  Otherwise, an error code.
992  *
993  * Since: 2.4.0
994  **/
995 int
996 gnutls_openpgp_crt_get_subkey_fingerprint (gnutls_openpgp_crt_t key,
997                                            unsigned int idx,
998                                            void *fpr, size_t * fprlen)
999 {
1000   cdk_packet_t pkt;
1001   cdk_pkt_pubkey_t pk = NULL;
1002
1003   if (!fpr || !fprlen)
1004     {
1005       gnutls_assert ();
1006       return GNUTLS_E_INVALID_REQUEST;
1007     }
1008
1009   *fprlen = 0;
1010
1011   pkt = _get_public_subkey (key, idx);
1012   if (!pkt)
1013     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
1014
1015   pk = pkt->pkt.public_key;
1016   *fprlen = 20;
1017
1018   /* FIXME: Check if the draft allows old PGP keys. */
1019   if (is_RSA (pk->pubkey_algo) && pk->version < 4)
1020     *fprlen = 16;
1021   cdk_pk_get_fingerprint (pk, fpr);
1022
1023   return 0;
1024 }
1025
1026 /**
1027  * gnutls_openpgp_crt_get_subkey_idx:
1028  * @key: the structure that contains the OpenPGP public key.
1029  * @keyid: the keyid.
1030  *
1031  * Get subkey's index.
1032  *
1033  * Returns: the index of the subkey or a negative error value.
1034  *
1035  * Since: 2.4.0
1036  **/
1037 int
1038 gnutls_openpgp_crt_get_subkey_idx (gnutls_openpgp_crt_t key,
1039                                    const gnutls_openpgp_keyid_t keyid)
1040 {
1041   int ret;
1042   uint32_t kid[2];
1043
1044   if (!key)
1045     {
1046       gnutls_assert ();
1047       return GNUTLS_E_INVALID_REQUEST;
1048     }
1049
1050   KEYID_IMPORT (kid, keyid);
1051   ret = _gnutls_openpgp_find_subkey_idx (key->knode, kid, 0);
1052
1053   if (ret < 0)
1054     {
1055       gnutls_assert ();
1056     }
1057
1058   return ret;
1059 }
1060
1061 /**
1062  * gnutls_openpgp_crt_get_subkey_usage:
1063  * @key: should contain a gnutls_openpgp_crt_t structure
1064  * @idx: the subkey index
1065  * @key_usage: where the key usage bits will be stored
1066  *
1067  * This function will return certificate's key usage, by checking the
1068  * key algorithm.  The key usage value will ORed values of
1069  * %GNUTLS_KEY_DIGITAL_SIGNATURE or %GNUTLS_KEY_KEY_ENCIPHERMENT.
1070  *
1071  * A negative value may be returned in case of parsing error.
1072  *
1073  * Returns: key usage value.
1074  *
1075  * Since: 2.4.0
1076  */
1077 int
1078 gnutls_openpgp_crt_get_subkey_usage (gnutls_openpgp_crt_t key,
1079                                      unsigned int idx,
1080                                      unsigned int *key_usage)
1081 {
1082   cdk_packet_t pkt;
1083
1084   if (!key)
1085     {
1086       gnutls_assert ();
1087       return GNUTLS_E_INVALID_REQUEST;
1088     }
1089
1090   pkt = _get_public_subkey (key, idx);
1091   if (!pkt)
1092     return GNUTLS_E_OPENPGP_SUBKEY_ERROR;
1093
1094   *key_usage = _gnutls_get_pgp_key_usage (pkt->pkt.public_key->pubkey_usage);
1095
1096   return 0;
1097 }
1098
1099 int
1100 _gnutls_read_pgp_mpi (cdk_packet_t pkt, unsigned int priv, size_t idx,
1101                       bigint_t * m)
1102 {
1103   size_t buf_size = 512;
1104   opaque *buf = gnutls_malloc (buf_size);
1105   int err;
1106   unsigned int max_pub_params = 0;
1107
1108   if (priv != 0)
1109     max_pub_params = cdk_pk_get_npkey (pkt->pkt.secret_key->pk->pubkey_algo);
1110
1111   if (buf == NULL)
1112     {
1113       gnutls_assert ();
1114       return GNUTLS_E_MEMORY_ERROR;
1115     }
1116
1117   /* FIXME: Note that opencdk doesn't like the buf to be NULL.
1118    */
1119   if (priv == 0)
1120     err =
1121       cdk_pk_get_mpi (pkt->pkt.public_key, idx, buf, buf_size, &buf_size,
1122                       NULL);
1123   else
1124     {
1125       if (idx < max_pub_params)
1126         err =
1127           cdk_pk_get_mpi (pkt->pkt.secret_key->pk, idx, buf, buf_size,
1128                           &buf_size, NULL);
1129       else
1130         {
1131           err =
1132             cdk_sk_get_mpi (pkt->pkt.secret_key, idx - max_pub_params, buf,
1133                             buf_size, &buf_size, NULL);
1134         }
1135     }
1136
1137   if (err == CDK_Too_Short)
1138     {
1139       buf = gnutls_realloc_fast (buf, buf_size);
1140       if (buf == NULL)
1141         {
1142           gnutls_assert ();
1143           return GNUTLS_E_MEMORY_ERROR;
1144         }
1145
1146       if (priv == 0)
1147         err =
1148           cdk_pk_get_mpi (pkt->pkt.public_key, idx, buf, buf_size, &buf_size,
1149                           NULL);
1150       else
1151         {
1152           if (idx < max_pub_params)
1153             err =
1154               cdk_pk_get_mpi (pkt->pkt.secret_key->pk, idx, buf, buf_size,
1155                               &buf_size, NULL);
1156           else
1157             {
1158               err =
1159                 cdk_sk_get_mpi (pkt->pkt.secret_key, idx - max_pub_params,
1160                                 buf, buf_size, &buf_size, NULL);
1161             }
1162         }
1163     }
1164
1165   if (err != CDK_Success)
1166     {
1167       gnutls_assert ();
1168       gnutls_free (buf);
1169       return _gnutls_map_cdk_rc (err);
1170     }
1171
1172   err = _gnutls_mpi_scan (m, buf, buf_size);
1173   gnutls_free (buf);
1174
1175   if (err < 0)
1176     {
1177       gnutls_assert ();
1178       return err;
1179     }
1180
1181   return 0;
1182 }
1183
1184
1185 /* Extracts DSA and RSA parameters from a certificate.
1186  */
1187 int
1188 _gnutls_openpgp_crt_get_mpis (gnutls_openpgp_crt_t cert,
1189                               uint32_t * keyid /* [2] */ ,
1190                               bigint_t * params, int *params_size)
1191 {
1192   int result, i;
1193   int pk_algorithm, local_params;
1194   cdk_packet_t pkt;
1195
1196   if (keyid == NULL)
1197     pkt = cdk_kbnode_find_packet (cert->knode, CDK_PKT_PUBLIC_KEY);
1198   else
1199     pkt = _gnutls_openpgp_find_key (cert->knode, keyid, 0);
1200
1201   if (pkt == NULL)
1202     {
1203       gnutls_assert ();
1204       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
1205     }
1206
1207   pk_algorithm = _gnutls_openpgp_get_algo (pkt->pkt.public_key->pubkey_algo);
1208
1209   switch (pk_algorithm)
1210     {
1211     case GNUTLS_PK_RSA:
1212       local_params = RSA_PUBLIC_PARAMS;
1213       break;
1214     case GNUTLS_PK_DSA:
1215       local_params = DSA_PUBLIC_PARAMS;
1216       break;
1217     default:
1218       gnutls_assert ();
1219       return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
1220     }
1221
1222   if (*params_size < local_params)
1223     {
1224       gnutls_assert ();
1225       return GNUTLS_E_INTERNAL_ERROR;
1226     }
1227
1228   *params_size = local_params;
1229
1230   for (i = 0; i < local_params; i++)
1231     {
1232       result = _gnutls_read_pgp_mpi (pkt, 0, i, &params[i]);
1233       if (result < 0)
1234         {
1235           gnutls_assert ();
1236           goto error;
1237         }
1238     }
1239
1240   return 0;
1241
1242 error:
1243   {
1244     int j;
1245     for (j = 0; j < i; j++)
1246       _gnutls_mpi_release (&params[j]);
1247   }
1248
1249   return result;
1250 }
1251
1252 /* The internal version of export
1253  */
1254 static int
1255 _get_pk_rsa_raw (gnutls_openpgp_crt_t crt, gnutls_openpgp_keyid_t keyid,
1256                  gnutls_datum_t * m, gnutls_datum_t * e)
1257 {
1258   int pk_algorithm, ret, i;
1259   cdk_packet_t pkt;
1260   uint32_t kid32[2];
1261   bigint_t params[MAX_PUBLIC_PARAMS_SIZE];
1262   int params_size = MAX_PUBLIC_PARAMS_SIZE;
1263
1264   if (crt == NULL)
1265     {
1266       gnutls_assert ();
1267       return GNUTLS_E_INVALID_REQUEST;
1268     }
1269
1270   KEYID_IMPORT (kid32, keyid);
1271
1272   pkt = _gnutls_openpgp_find_key (crt->knode, kid32, 0);
1273   if (pkt == NULL)
1274     {
1275       gnutls_assert ();
1276       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
1277     }
1278
1279   pk_algorithm = _gnutls_openpgp_get_algo (pkt->pkt.public_key->pubkey_algo);
1280
1281   if (pk_algorithm != GNUTLS_PK_RSA)
1282     {
1283       gnutls_assert ();
1284       return GNUTLS_E_INVALID_REQUEST;
1285     }
1286
1287   ret = _gnutls_openpgp_crt_get_mpis (crt, kid32, params, &params_size);
1288   if (ret < 0)
1289     {
1290       gnutls_assert ();
1291       return ret;
1292     }
1293
1294   ret = _gnutls_mpi_dprint (params[0], m);
1295   if (ret < 0)
1296     {
1297       gnutls_assert ();
1298       goto cleanup;
1299     }
1300
1301   ret = _gnutls_mpi_dprint (params[1], e);
1302   if (ret < 0)
1303     {
1304       gnutls_assert ();
1305       _gnutls_free_datum (m);
1306       goto cleanup;
1307     }
1308
1309   ret = 0;
1310
1311 cleanup:
1312   for (i = 0; i < params_size; i++)
1313     {
1314       _gnutls_mpi_release (&params[i]);
1315     }
1316   return ret;
1317 }
1318
1319 static int
1320 _get_pk_dsa_raw (gnutls_openpgp_crt_t crt, gnutls_openpgp_keyid_t keyid,
1321                  gnutls_datum_t * p, gnutls_datum_t * q,
1322                  gnutls_datum_t * g, gnutls_datum_t * y)
1323 {
1324   int pk_algorithm, ret, i;
1325   cdk_packet_t pkt;
1326   uint32_t kid32[2];
1327   bigint_t params[MAX_PUBLIC_PARAMS_SIZE];
1328   int params_size = MAX_PUBLIC_PARAMS_SIZE;
1329
1330   if (crt == NULL)
1331     {
1332       gnutls_assert ();
1333       return GNUTLS_E_INVALID_REQUEST;
1334     }
1335
1336   KEYID_IMPORT (kid32, keyid);
1337
1338   pkt = _gnutls_openpgp_find_key (crt->knode, kid32, 0);
1339   if (pkt == NULL)
1340     {
1341       gnutls_assert ();
1342       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
1343     }
1344
1345   pk_algorithm = _gnutls_openpgp_get_algo (pkt->pkt.public_key->pubkey_algo);
1346
1347   if (pk_algorithm != GNUTLS_PK_DSA)
1348     {
1349       gnutls_assert ();
1350       return GNUTLS_E_INVALID_REQUEST;
1351     }
1352
1353   ret = _gnutls_openpgp_crt_get_mpis (crt, kid32, params, &params_size);
1354   if (ret < 0)
1355     {
1356       gnutls_assert ();
1357       return ret;
1358     }
1359
1360   /* P */
1361   ret = _gnutls_mpi_dprint (params[0], p);
1362   if (ret < 0)
1363     {
1364       gnutls_assert ();
1365       goto cleanup;
1366     }
1367
1368   /* Q */
1369   ret = _gnutls_mpi_dprint (params[1], q);
1370   if (ret < 0)
1371     {
1372       gnutls_assert ();
1373       _gnutls_free_datum (p);
1374       goto cleanup;
1375     }
1376
1377
1378   /* G */
1379   ret = _gnutls_mpi_dprint (params[2], g);
1380   if (ret < 0)
1381     {
1382       gnutls_assert ();
1383       _gnutls_free_datum (p);
1384       _gnutls_free_datum (q);
1385       goto cleanup;
1386     }
1387
1388
1389   /* Y */
1390   ret = _gnutls_mpi_dprint (params[3], y);
1391   if (ret < 0)
1392     {
1393       gnutls_assert ();
1394       _gnutls_free_datum (p);
1395       _gnutls_free_datum (g);
1396       _gnutls_free_datum (q);
1397       goto cleanup;
1398     }
1399
1400   ret = 0;
1401
1402 cleanup:
1403   for (i = 0; i < params_size; i++)
1404     {
1405       _gnutls_mpi_release (&params[i]);
1406     }
1407   return ret;
1408 }
1409
1410
1411 /**
1412  * gnutls_openpgp_crt_get_pk_rsa_raw:
1413  * @crt: Holds the certificate
1414  * @m: will hold the modulus
1415  * @e: will hold the public exponent
1416  *
1417  * This function will export the RSA public key's parameters found in
1418  * the given structure.  The new parameters will be allocated using
1419  * gnutls_malloc() and will be stored in the appropriate datum.
1420  *
1421  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
1422  *
1423  * Since: 2.4.0
1424  **/
1425 int
1426 gnutls_openpgp_crt_get_pk_rsa_raw (gnutls_openpgp_crt_t crt,
1427                                    gnutls_datum_t * m, gnutls_datum_t * e)
1428 {
1429   uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE];
1430   int ret;
1431
1432   ret = gnutls_openpgp_crt_get_key_id (crt, keyid);
1433   if (ret < 0)
1434     {
1435       gnutls_assert ();
1436       return ret;
1437     }
1438
1439   return _get_pk_rsa_raw (crt, keyid, m, e);
1440 }
1441
1442 /**
1443  * gnutls_openpgp_crt_get_pk_dsa_raw:
1444  * @crt: Holds the certificate
1445  * @p: will hold the p
1446  * @q: will hold the q
1447  * @g: will hold the g
1448  * @y: will hold the y
1449  *
1450  * This function will export the DSA public key's parameters found in
1451  * the given certificate.  The new parameters will be allocated using
1452  * gnutls_malloc() and will be stored in the appropriate datum.
1453  *
1454  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
1455  *
1456  * Since: 2.4.0
1457  **/
1458 int
1459 gnutls_openpgp_crt_get_pk_dsa_raw (gnutls_openpgp_crt_t crt,
1460                                    gnutls_datum_t * p, gnutls_datum_t * q,
1461                                    gnutls_datum_t * g, gnutls_datum_t * y)
1462 {
1463   uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE];
1464   int ret;
1465
1466   ret = gnutls_openpgp_crt_get_key_id (crt, keyid);
1467   if (ret < 0)
1468     {
1469       gnutls_assert ();
1470       return ret;
1471     }
1472
1473   return _get_pk_dsa_raw (crt, keyid, p, q, g, y);
1474 }
1475
1476 /**
1477  * gnutls_openpgp_crt_get_subkey_pk_rsa_raw:
1478  * @crt: Holds the certificate
1479  * @idx: Is the subkey index
1480  * @m: will hold the modulus
1481  * @e: will hold the public exponent
1482  *
1483  * This function will export the RSA public key's parameters found in
1484  * the given structure.  The new parameters will be allocated using
1485  * gnutls_malloc() and will be stored in the appropriate datum.
1486  *
1487  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
1488  *
1489  * Since: 2.4.0
1490  **/
1491 int
1492 gnutls_openpgp_crt_get_subkey_pk_rsa_raw (gnutls_openpgp_crt_t crt,
1493                                           unsigned int idx,
1494                                           gnutls_datum_t * m,
1495                                           gnutls_datum_t * e)
1496 {
1497   uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE];
1498   int ret;
1499
1500   ret = gnutls_openpgp_crt_get_subkey_id (crt, idx, keyid);
1501   if (ret < 0)
1502     {
1503       gnutls_assert ();
1504       return ret;
1505     }
1506
1507   return _get_pk_rsa_raw (crt, keyid, m, e);
1508 }
1509
1510 /**
1511  * gnutls_openpgp_crt_get_subkey_pk_dsa_raw:
1512  * @crt: Holds the certificate
1513  * @idx: Is the subkey index
1514  * @p: will hold the p
1515  * @q: will hold the q
1516  * @g: will hold the g
1517  * @y: will hold the y
1518  *
1519  * This function will export the DSA public key's parameters found in
1520  * the given certificate.  The new parameters will be allocated using
1521  * gnutls_malloc() and will be stored in the appropriate datum.
1522  *
1523  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
1524  *
1525  * Since: 2.4.0
1526  **/
1527 int
1528 gnutls_openpgp_crt_get_subkey_pk_dsa_raw (gnutls_openpgp_crt_t crt,
1529                                           unsigned int idx,
1530                                           gnutls_datum_t * p,
1531                                           gnutls_datum_t * q,
1532                                           gnutls_datum_t * g,
1533                                           gnutls_datum_t * y)
1534 {
1535   uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE];
1536   int ret;
1537
1538   ret = gnutls_openpgp_crt_get_subkey_id (crt, idx, keyid);
1539   if (ret < 0)
1540     {
1541       gnutls_assert ();
1542       return ret;
1543     }
1544
1545   return _get_pk_dsa_raw (crt, keyid, p, q, g, y);
1546 }
1547
1548 /**
1549  * gnutls_openpgp_crt_get_preferred_key_id:
1550  * @key: the structure that contains the OpenPGP public key.
1551  * @keyid: the struct to save the keyid.
1552  *
1553  * Get preferred key id.  If it hasn't been set it returns
1554  * %GNUTLS_E_INVALID_REQUEST.
1555  *
1556  * Returns: the 64-bit preferred keyID of the OpenPGP key.
1557  **/
1558 int
1559 gnutls_openpgp_crt_get_preferred_key_id (gnutls_openpgp_crt_t key,
1560                                          gnutls_openpgp_keyid_t keyid)
1561 {
1562   if (!key->preferred_set)
1563     return gnutls_assert_val(GNUTLS_E_OPENPGP_PREFERRED_KEY_ERROR);
1564
1565   if (!key || !keyid)
1566     {
1567       gnutls_assert ();
1568       return GNUTLS_E_INVALID_REQUEST;
1569     }
1570
1571   memcpy (keyid, key->preferred_keyid, GNUTLS_OPENPGP_KEYID_SIZE);
1572
1573   return 0;
1574 }
1575
1576 /**
1577  * gnutls_openpgp_crt_set_preferred_key_id:
1578  * @key: the structure that contains the OpenPGP public key.
1579  * @keyid: the selected keyid
1580  *
1581  * This allows setting a preferred key id for the given certificate.
1582  * This key will be used by functions that involve key handling.
1583  *
1584  * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
1585  *   otherwise an error code is returned.
1586  **/
1587 int
1588 gnutls_openpgp_crt_set_preferred_key_id (gnutls_openpgp_crt_t key,
1589                                          const gnutls_openpgp_keyid_t keyid)
1590 {
1591   int ret;
1592
1593   if (!key)
1594     {
1595       gnutls_assert ();
1596       return GNUTLS_E_INVALID_REQUEST;
1597     }
1598
1599   /* check if the id is valid */
1600   ret = gnutls_openpgp_crt_get_subkey_idx (key, keyid);
1601   if (ret < 0)
1602     {
1603       _gnutls_x509_log ("the requested subkey does not exist\n");
1604       gnutls_assert ();
1605       return ret;
1606     }
1607
1608   key->preferred_set = 1;
1609   memcpy (key->preferred_keyid, keyid, GNUTLS_OPENPGP_KEYID_SIZE);
1610
1611   return 0;
1612 }
1613
1614 /**
1615  * gnutls_openpgp_crt_get_auth_subkey:
1616  * @crt: the structure that contains the OpenPGP public key.
1617  * @keyid: the struct to save the keyid.
1618  * @flag: Non zero indicates that a valid subkey is always returned.
1619  *
1620  * Returns the 64-bit keyID of the first valid OpenPGP subkey marked
1621  * for authentication.  If flag is non zero and no authentication
1622  * subkey exists, then a valid subkey will be returned even if it is
1623  * not marked for authentication.
1624  * Returns the 64-bit keyID of the first valid OpenPGP subkey marked
1625  * for authentication.  If flag is non zero and no authentication
1626  * subkey exists, then a valid subkey will be returned even if it is
1627  * not marked for authentication.
1628  *
1629  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
1630  **/
1631 int
1632 gnutls_openpgp_crt_get_auth_subkey (gnutls_openpgp_crt_t crt,
1633                                     gnutls_openpgp_keyid_t keyid,
1634                                     unsigned int flag)
1635 {
1636   int ret, subkeys, i;
1637   unsigned int usage;
1638   unsigned int keyid_init = 0;
1639
1640   subkeys = gnutls_openpgp_crt_get_subkey_count (crt);
1641   if (subkeys <= 0)
1642     {
1643       gnutls_assert ();
1644       return GNUTLS_E_OPENPGP_SUBKEY_ERROR;
1645     }
1646
1647   /* Try to find a subkey with the authentication flag set.
1648    * if none exists use the last one found
1649    */
1650   for (i = 0; i < subkeys; i++)
1651     {
1652       ret = gnutls_openpgp_crt_get_subkey_pk_algorithm(crt, i, NULL);
1653       if (ret == GNUTLS_PK_UNKNOWN)
1654         continue;
1655       
1656       ret = gnutls_openpgp_crt_get_subkey_revoked_status (crt, i);
1657       if (ret != 0)             /* it is revoked. ignore it */
1658         continue;
1659
1660       if (keyid_init == 0)
1661         {                       /* keep the first valid subkey */
1662           ret = gnutls_openpgp_crt_get_subkey_id (crt, i, keyid);
1663           if (ret < 0)
1664             {
1665               gnutls_assert ();
1666               return ret;
1667             }
1668
1669           keyid_init = 1;
1670         }
1671
1672       ret = gnutls_openpgp_crt_get_subkey_usage (crt, i, &usage);
1673       if (ret < 0)
1674         {
1675           gnutls_assert ();
1676           return ret;
1677         }
1678
1679       if (usage & GNUTLS_KEY_KEY_AGREEMENT)
1680         {
1681           ret = gnutls_openpgp_crt_get_subkey_id (crt, i, keyid);
1682           if (ret < 0)
1683             {
1684               gnutls_assert ();
1685               return ret;
1686             }
1687           return 0;
1688         }
1689     }
1690
1691   if (flag && keyid_init)
1692     return 0;
1693   else
1694     return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
1695 }