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