Doc fixes.
[gnutls:gnutls.git] / lib / openpgp / privkey.c
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation
3  *
4  * Author: 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 privkey 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 <gnutls_num.h>
33 #include <openpgp_int.h>
34 #include <gnutls_openpgp.h>
35 #include <gnutls_cert.h>
36
37 /**
38  * gnutls_openpgp_privkey_init - initializes a #gnutls_openpgp_privkey_t structure
39  * @key: The structure to be initialized
40  *
41  * This function will initialize an OpenPGP key structure.
42  *
43  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
44  **/
45 int
46 gnutls_openpgp_privkey_init (gnutls_openpgp_privkey_t * key)
47 {
48   *key = gnutls_calloc (1, sizeof (gnutls_openpgp_privkey_int));
49
50   if (*key)
51     return 0; /* success */
52   return GNUTLS_E_MEMORY_ERROR;
53 }
54
55 /**
56  * gnutls_openpgp_privkey_deinit - deinitializes memory used by a #gnutls_openpgp_privkey_t structure
57  * @key: The structure to be initialized
58  *
59  * This function will deinitialize a key structure.
60  **/
61 void
62 gnutls_openpgp_privkey_deinit (gnutls_openpgp_privkey_t key)
63 {
64   if (!key)
65     return;
66
67   if (key->knode)
68     {
69       cdk_kbnode_release (key->knode);
70       key->knode = NULL;
71     }
72
73   gnutls_free (key);
74 }
75
76 /**
77  * gnutls_openpgp_privkey_import - import a RAW or BASE64 encoded key
78  * @key: The structure to store the parsed key.
79  * @data: The RAW or BASE64 encoded key.
80  * @format: One of gnutls_openpgp_crt_fmt_t elements.
81  * @pass: Unused for now
82  * @flags: should be zero
83  *
84  * This function will convert the given RAW or Base64 encoded key to
85  * the native gnutls_openpgp_privkey_t format.  The output will be
86  * stored in 'key'.
87  *
88  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
89  **/
90 int
91 gnutls_openpgp_privkey_import (gnutls_openpgp_privkey_t key,
92                                const gnutls_datum_t * data,
93                                gnutls_openpgp_crt_fmt_t format,
94                                const char *pass, unsigned int flags)
95 {
96   cdk_stream_t inp;
97   cdk_packet_t pkt;
98   int rc;
99
100   if (data->data == NULL || data->size == 0)
101     {
102       gnutls_assert();
103       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
104     }
105   
106   if (format == GNUTLS_OPENPGP_FMT_RAW)
107     rc = cdk_kbnode_read_from_mem (&key->knode, data->data, data->size);
108   else
109     {
110       rc = cdk_stream_tmp_from_mem (data->data, data->size, &inp);
111       if (rc)
112         {
113           rc = _gnutls_map_cdk_rc (rc);
114           gnutls_assert ();
115           return rc;
116         }      
117       if (cdk_armor_filter_use (inp))
118         rc = cdk_stream_set_armor_flag (inp, 0);
119       if (!rc)
120         rc = cdk_keydb_get_keyblock (inp, &key->knode);
121       cdk_stream_close (inp);
122       if (rc)
123         {
124           rc = _gnutls_map_cdk_rc (rc);
125           gnutls_assert ();
126           return rc;
127         }
128     }
129
130   /* Test if the import was successful. */
131   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY);
132   if (pkt == NULL)
133     {
134       gnutls_assert();
135       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
136     }
137   
138   return 0;
139 }
140
141 /**
142  * gnutls_openpgp_privkey_export - export a RAW or BASE64 encoded key
143  * @key: Holds the key.
144  * @format: One of gnutls_openpgp_crt_fmt_t elements.
145  * @password: the password that will be used to encrypt the key.
146  * @flags: zero for future compatibility
147  * @output_data: will contain the key base64 encoded or raw
148  * @output_data_size: holds the size of output_data (and will be
149  *   replaced by the actual size of parameters)
150  *
151  * This function will convert the given key to RAW or Base64 format.
152  * If the buffer provided is not long enough to hold the output, then
153  * GNUTLS_E_SHORT_MEMORY_BUFFER will be returned.
154  *
155  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
156  **/
157 int
158 gnutls_openpgp_privkey_export (gnutls_openpgp_privkey_t key,
159                            gnutls_openpgp_crt_fmt_t format,
160                            const char* password, unsigned int flags,
161                            void *output_data, size_t * output_data_size)
162 {
163   /* FIXME for now we do not export encrypted keys */
164   return _gnutls_openpgp_export( key->knode, format, output_data, output_data_size, 1);
165 }
166
167
168 /**
169  * gnutls_openpgp_privkey_get_pk_algorithm - return the key's PublicKey algorithm
170  * @key: is an OpenPGP key
171  * @bits: if bits is non null it will hold the size of the parameters' in bits
172  *
173  * This function will return the public key algorithm of an OpenPGP
174  * certificate.
175  *
176  * If bits is non null, it should have enough size to hold the parameters
177  * size in bits. For RSA the bits returned is the modulus.
178  * For DSA the bits returned are of the public exponent.
179  *
180  * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
181  *   success, or a negative value on error.
182  **/
183 gnutls_pk_algorithm_t
184 gnutls_openpgp_privkey_get_pk_algorithm (gnutls_openpgp_privkey_t key,
185                                          unsigned int *bits)
186 {
187   cdk_packet_t pkt;
188   int algo;
189
190   if (!key)
191     {
192       gnutls_assert();
193       return GNUTLS_PK_UNKNOWN;
194     }
195   
196   algo = 0;
197   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY);
198   if (pkt)
199     {
200       if (bits)
201         *bits = cdk_pk_get_nbits (pkt->pkt.secret_key->pk);
202       algo = _gnutls_openpgp_get_algo(pkt->pkt.secret_key->pk->pubkey_algo);
203     }
204   
205   return algo;
206 }
207
208 int _gnutls_openpgp_get_algo( int cdk_algo)
209 {
210 int algo;
211
212       if (is_RSA (cdk_algo))
213         algo = GNUTLS_PK_RSA;
214       else if (is_DSA (cdk_algo))
215         algo = GNUTLS_PK_DSA;
216       else {
217         _gnutls_x509_log("Unknown OpenPGP algorithm %d\n", cdk_algo);
218         algo = GNUTLS_PK_UNKNOWN;
219       }
220       
221       return algo;
222 }
223
224 /**
225  * gnutls_openpgp_privkey_get_revoked_ status - Get the revoked status of the key
226  * @key: the structure that contains the OpenPGP private key.
227  *
228  * Get revocation status of key.
229  *
230  * Returns: true (1) if the key has been revoked, or false (0) if it
231  *   has not, or a negative value indicates an error.
232  **/
233 int
234 gnutls_openpgp_privkey_get_revoked_status (gnutls_openpgp_privkey_t key)
235 {
236   cdk_packet_t pkt;
237
238   if (!key)
239     {
240       gnutls_assert ();
241       return GNUTLS_E_INVALID_REQUEST;
242     }
243
244   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY);
245   if (!pkt)
246     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
247
248   if (pkt->pkt.secret_key->is_revoked != 0) return 1;
249   return 0;
250 }
251
252 /**
253  * gnutls_openpgp_privkey_get_fingerprint - Gets the fingerprint
254  * @key: the raw data that contains the OpenPGP secret key.
255  * @fpr: the buffer to save the fingerprint, must hold at least 20 bytes.
256  * @fprlen: the integer to save the length of the fingerprint.
257  *
258  * Get the fingerprint of the OpenPGP key. Depends on the
259  * algorithm, the fingerprint can be 16 or 20 bytes.
260  *
261  * Returns: On success, 0 is returned, or an error code.
262  **/
263 int
264 gnutls_openpgp_privkey_get_fingerprint (gnutls_openpgp_privkey_t key,
265                                     void *fpr, size_t * fprlen)
266 {
267   cdk_packet_t pkt;
268   cdk_pkt_pubkey_t pk = NULL;
269
270   if (!fpr || !fprlen)
271     {
272       gnutls_assert ();
273       return GNUTLS_E_INVALID_REQUEST;
274     }
275
276   *fprlen = 0;
277
278   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY);
279   if (!pkt) 
280     {
281       gnutls_assert();
282       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
283     }
284
285   pk = pkt->pkt.secret_key->pk;
286   *fprlen = 20;
287   
288   if (is_RSA (pk->pubkey_algo) && pk->version < 4)
289     *fprlen = 16;
290
291   cdk_pk_get_fingerprint (pk, fpr);
292
293   return 0;
294 }
295
296 /**
297  * gnutls_openpgp_privkey_get_key_id - Gets the keyID
298  * @key: the structure that contains the OpenPGP secret key.
299  * @keyid: the buffer to save the keyid.
300  *
301  * Get key-id.
302  *
303  * Returns: the 64-bit keyID of the OpenPGP key.
304  **/
305 int
306 gnutls_openpgp_privkey_get_key_id (gnutls_openpgp_privkey_t key,
307                                    gnutls_openpgp_keyid_t keyid)
308 {
309   cdk_packet_t pkt;
310   uint32_t kid[2];
311
312   if (!key || !keyid)
313     {
314       gnutls_assert ();
315       return GNUTLS_E_INVALID_REQUEST;
316     }
317
318   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY);
319   if (!pkt)
320     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
321
322   cdk_sk_get_keyid (pkt->pkt.secret_key, kid);
323   _gnutls_write_uint32( kid[0], keyid);
324   _gnutls_write_uint32( kid[1], keyid+4);
325
326   return 0;
327 }
328
329
330 /**
331  * gnutls_openpgp_privkey_get_subkey_count - return the number of subkeys
332  * @key: is an OpenPGP key
333  *
334  * This function will return the number of subkeys present in the
335  * given OpenPGP certificate.
336  *
337  * Returns: the number of subkeys, or a negative value on error.
338  **/
339 int
340 gnutls_openpgp_privkey_get_subkey_count (gnutls_openpgp_privkey_t key)
341 {
342   cdk_kbnode_t p, ctx;
343   cdk_packet_t pkt;
344   int subkeys;
345
346   if (key == NULL)
347     {
348       gnutls_assert ();
349       return 0;
350     }
351
352   ctx = NULL;
353   subkeys = 0;
354   while ((p = cdk_kbnode_walk (key->knode, &ctx, 0)))
355     {
356       pkt = cdk_kbnode_get_packet (p);
357       if (pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
358         subkeys++;
359     }
360
361   return subkeys;
362 }
363
364 /* returns the subkey with the given index */
365 static cdk_packet_t _get_secret_subkey(gnutls_openpgp_privkey_t key, unsigned int indx)
366 {
367   cdk_kbnode_t p, ctx;
368   cdk_packet_t pkt;
369   int subkeys;
370
371   ctx = NULL;
372   subkeys = 0;
373   while ((p = cdk_kbnode_walk (key->knode, &ctx, 0)))
374     {
375       pkt = cdk_kbnode_get_packet (p);
376       if (pkt->pkttype == CDK_PKT_SECRET_SUBKEY && indx == subkeys++)
377         return pkt;
378     }
379
380   return NULL;
381 }
382
383 /**
384  * gnutls_openpgp_privkey_get_subkey_revoked_ status - Get the revoked status of the key
385  * @key: the structure that contains the OpenPGP private key.
386  * @idx: is the subkey index
387  *
388  * Get revocation status of key.
389  *
390  * Returns: true (1) if the key has been revoked, or false (0) if it
391  *   has not, or a negative value indicates an error.
392  **/
393 int
394 gnutls_openpgp_privkey_get_subkey_revoked_status (gnutls_openpgp_privkey_t key, unsigned int idx)
395 {
396   cdk_packet_t pkt;
397
398   if (!key)
399     {
400       gnutls_assert ();
401       return GNUTLS_E_INVALID_REQUEST;
402     }
403
404   pkt = _get_secret_subkey( key, idx);
405   if (!pkt)
406     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
407
408   if (pkt->pkt.secret_key->is_revoked != 0) return 1;
409   return 0;
410 }
411
412 /**
413  * gnutls_openpgp_privkey_get_subkey_pk_algorithm - return the subkey's PublicKey algorithm
414  * @key: is an OpenPGP key
415  * @idx: is the subkey index
416  * @bits: if bits is non null it will hold the size of the parameters' in bits
417  *
418  * This function will return the public key algorithm of a subkey of an OpenPGP
419  * certificate.
420  *
421  * If bits is non null, it should have enough size to hold the parameters
422  * size in bits. For RSA the bits returned is the modulus.
423  * For DSA the bits returned are of the public exponent.
424  *
425  * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
426  *   success, or a negative value on error.
427  **/
428 gnutls_pk_algorithm_t
429 gnutls_openpgp_privkey_get_subkey_pk_algorithm (gnutls_openpgp_privkey_t key,
430     unsigned int idx, unsigned int *bits)
431 {
432   cdk_packet_t pkt;
433   int algo;
434
435   if (!key)
436     {
437       gnutls_assert();
438       return GNUTLS_PK_UNKNOWN;
439     }
440   
441   pkt = _get_secret_subkey( key, idx);
442
443   algo = 0;
444   if (pkt)
445     {
446       if (bits)
447         *bits = cdk_pk_get_nbits (pkt->pkt.secret_key->pk);
448       algo = pkt->pkt.secret_key->pubkey_algo;
449       if (is_RSA (algo))
450         algo = GNUTLS_PK_RSA;
451       else if (is_DSA (algo))
452         algo = GNUTLS_PK_DSA;
453       else
454         algo = GNUTLS_E_UNKNOWN_PK_ALGORITHM;
455     }
456
457   return algo;
458 }
459
460 /**
461  * gnutls_openpgp_privkey_get_subkey_idx - Returns the subkey's index
462  * @key: the structure that contains the OpenPGP private key.
463  * @keyid: the keyid.
464  *
465  * Get index of subkey.
466  *
467  * Returns: the index of the subkey or a negative error value.
468  **/
469 int
470 gnutls_openpgp_privkey_get_subkey_idx (gnutls_openpgp_privkey_t key,
471                                        const gnutls_openpgp_keyid_t keyid)
472 {
473   int ret;
474   uint32_t kid[2];
475
476   if (!key)
477     {
478       gnutls_assert ();
479       return GNUTLS_E_INVALID_REQUEST;
480     }
481
482   KEYID_IMPORT( kid, keyid);
483   ret = _gnutls_openpgp_find_subkey_idx( key->knode, kid, 1);
484
485   if (ret < 0)
486     {
487       gnutls_assert();
488     }
489
490   return ret;
491 }
492
493 /**
494  * gnutls_openpgp_privkey_get_subkey_creation_time - Extract the timestamp
495  * @key: the structure that contains the OpenPGP private key.
496  * @idx: the subkey index
497  *
498  * Get subkey creation time.
499  *
500  * Returns: the timestamp when the OpenPGP key was created.
501  **/
502 time_t
503 gnutls_openpgp_privkey_get_subkey_creation_time (gnutls_openpgp_privkey_t key,
504                                                  unsigned int idx)
505 {
506   cdk_packet_t pkt;
507   time_t timestamp;
508
509   if (!key)
510     return (time_t) - 1;
511
512   pkt = _get_secret_subkey( key, idx);
513   if (pkt)
514     timestamp = pkt->pkt.secret_key->pk->timestamp;
515   else
516     timestamp = 0;
517
518   return timestamp;
519 }
520
521 /**
522  * gnutls_openpgp_privkey_get_subkey_expiration_time - Extract the expire date
523  * @key: the structure that contains the OpenPGP private key.
524  * @idx: the subkey index
525  *
526  * Get subkey expiration time.  A value of '0' means that the key
527  * doesn't expire at all.
528  *
529  * Returns: the time when the OpenPGP key expires.
530  **/
531 time_t
532 gnutls_openpgp_privkey_get_subkey_expiration_time (gnutls_openpgp_privkey_t key,
533                                                    unsigned int idx)
534 {
535   cdk_packet_t pkt;
536   time_t expiredate;
537
538   if (!key)
539     return (time_t) - 1;
540
541   pkt = _get_secret_subkey( key, idx);
542   if (pkt)
543     expiredate = pkt->pkt.secret_key->expiredate;
544   else
545     expiredate = 0;
546
547   return expiredate;
548 }
549
550 /**
551  * gnutls_openpgp_privkey_get_subkey_id - Gets the keyID
552  * @key: the structure that contains the OpenPGP secret key.
553  * @idx: the subkey index
554  * @keyid: the buffer to save the keyid.
555  *
556  * Get the key-id for the subkey.
557  *
558  * Returns: the 64-bit keyID of the OpenPGP key.
559  **/
560 int
561 gnutls_openpgp_privkey_get_subkey_id (gnutls_openpgp_privkey_t key,
562                                       unsigned int idx,
563                                       gnutls_openpgp_keyid_t keyid)
564 {
565   cdk_packet_t pkt;
566   uint32_t kid[2];
567
568   if (!key || !keyid)
569     {
570       gnutls_assert ();
571       return GNUTLS_E_INVALID_REQUEST;
572     }
573
574   pkt = _get_secret_subkey( key, idx);
575   if (!pkt)
576     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
577
578   cdk_sk_get_keyid (pkt->pkt.secret_key, kid);
579   _gnutls_write_uint32( kid[0], keyid);
580   _gnutls_write_uint32( kid[1], keyid+4);
581
582   return 0;
583 }
584
585 /* Extracts DSA and RSA parameters from a certificate.
586  */
587 int
588 _gnutls_openpgp_privkey_get_mpis (gnutls_openpgp_privkey_t pkey, uint32_t *keyid /*[2]*/,
589                            mpi_t * params, int *params_size)
590 {
591   int result, i;
592   int pk_algorithm, local_params;
593   cdk_packet_t pkt;
594
595   if (keyid == NULL)
596     pkt = cdk_kbnode_find_packet (pkey->knode, CDK_PKT_SECRET_KEY);
597   else
598     pkt = _gnutls_openpgp_find_key( pkey->knode, keyid, 1);
599   
600   if (pkt == NULL)
601     {
602       gnutls_assert();
603       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
604     }
605
606   pk_algorithm = _gnutls_openpgp_get_algo( pkt->pkt.secret_key->pk->pubkey_algo);
607
608   switch (pk_algorithm)
609     {
610       case GNUTLS_PK_RSA:
611         local_params = RSA_PRIVATE_PARAMS;
612         break;
613       case GNUTLS_PK_DSA:
614         local_params = DSA_PRIVATE_PARAMS;
615         break;
616       default:
617         gnutls_assert ();
618         return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
619     }
620
621   if (*params_size < local_params) 
622     {
623       gnutls_assert();
624       return GNUTLS_E_INTERNAL_ERROR;
625     }
626     
627   *params_size = local_params;
628
629     
630   for (i = 0; i < local_params; i++)
631     {
632        result = _gnutls_read_pgp_mpi( pkt, 1, i, &params[i]);
633        if (result < 0)
634          {
635            gnutls_assert();
636            goto error;
637          }
638     }
639
640   return 0;
641   
642 error:
643   {
644     int j;
645     for (j=0;j<i;j++)
646       _gnutls_mpi_release( &params[j]);
647   }
648
649   return result;
650 }
651
652 /* The internal version of export
653  */
654 static
655 int _get_sk_rsa_raw(gnutls_openpgp_privkey_t pkey, gnutls_openpgp_keyid_t keyid,
656   gnutls_datum_t * m, gnutls_datum_t * e,
657   gnutls_datum_t * d, gnutls_datum_t * p,
658   gnutls_datum_t * q, gnutls_datum_t * u)
659 {
660   int pk_algorithm, ret, i;
661   cdk_packet_t pkt;
662   uint32_t kid32[2];
663   mpi_t params[MAX_PRIV_PARAMS_SIZE];
664   int params_size = MAX_PRIV_PARAMS_SIZE;
665
666   if (pkey == NULL)
667     {
668       gnutls_assert ();
669       return GNUTLS_E_INVALID_REQUEST;
670     }
671   
672   KEYID_IMPORT(kid32, keyid);
673   
674   pkt = _gnutls_openpgp_find_key( pkey->knode, kid32, 1);
675   if (pkt == NULL)
676     {
677       gnutls_assert();
678       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
679     }
680
681   pk_algorithm = _gnutls_openpgp_get_algo( pkt->pkt.secret_key->pk->pubkey_algo);
682   
683   if (pk_algorithm != GNUTLS_PK_RSA)
684     {
685       gnutls_assert ();
686       return GNUTLS_E_INVALID_REQUEST;
687     }
688
689   ret = _gnutls_openpgp_privkey_get_mpis (pkey, kid32, params, &params_size);
690   if (ret < 0)
691     {
692       gnutls_assert ();
693       return ret;
694     }
695
696   ret = _gnutls_mpi_dprint (m, params[0]);
697   if (ret < 0)
698     {
699       gnutls_assert ();
700       goto cleanup;
701     }
702
703   ret = _gnutls_mpi_dprint (e, params[1]);
704   if (ret < 0)
705     {
706       gnutls_assert ();
707       _gnutls_free_datum (m);
708       goto cleanup;
709     }
710
711   ret = _gnutls_mpi_dprint (d, params[2]);
712   if (ret < 0)
713     {
714       gnutls_assert ();
715       _gnutls_free_datum (m);
716       _gnutls_free_datum (e);
717       goto cleanup;
718     }
719
720   ret = _gnutls_mpi_dprint (p, params[3]);
721   if (ret < 0)
722     {
723       gnutls_assert ();
724       _gnutls_free_datum (m);
725       _gnutls_free_datum (e);
726       _gnutls_free_datum (d);
727       goto cleanup;
728     }
729
730   ret = _gnutls_mpi_dprint (q, params[4]);
731   if (ret < 0)
732     {
733       gnutls_assert ();
734       _gnutls_free_datum (m);
735       _gnutls_free_datum (e);
736       _gnutls_free_datum (d);
737       _gnutls_free_datum (p);
738       goto cleanup;
739     }
740
741   ret = _gnutls_mpi_dprint (u, params[5]);
742   if (ret < 0)
743     {
744       gnutls_assert ();
745       _gnutls_free_datum (q);
746       _gnutls_free_datum (m);
747       _gnutls_free_datum (e);
748       _gnutls_free_datum (d);
749       _gnutls_free_datum (p);
750       goto cleanup;
751     }
752
753   ret = 0;
754
755 cleanup:
756   for (i = 0; i < params_size; i++)
757     {
758       _gnutls_mpi_release (&params[i]);
759     }
760   return ret;
761 }
762
763 static
764 int _get_sk_dsa_raw(gnutls_openpgp_privkey_t pkey, gnutls_openpgp_keyid_t keyid,
765                                 gnutls_datum_t * p, gnutls_datum_t * q,
766                                 gnutls_datum_t * g, gnutls_datum_t * y,
767                                 gnutls_datum_t * x)
768 {
769   int pk_algorithm, ret, i;
770   cdk_packet_t pkt;
771   uint32_t kid32[2];
772   mpi_t params[MAX_PRIV_PARAMS_SIZE];
773   int params_size = MAX_PRIV_PARAMS_SIZE;
774
775   if (pkey == NULL)
776     {
777       gnutls_assert ();
778       return GNUTLS_E_INVALID_REQUEST;
779     }
780   
781   KEYID_IMPORT(kid32, keyid);
782
783   pkt = _gnutls_openpgp_find_key( pkey->knode, kid32, 1);
784   if (pkt == NULL)
785     {
786       gnutls_assert();
787       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
788     }
789
790   pk_algorithm = _gnutls_openpgp_get_algo( pkt->pkt.secret_key->pk->pubkey_algo);
791   
792   if (pk_algorithm != GNUTLS_PK_DSA)
793     {
794       gnutls_assert ();
795       return GNUTLS_E_INVALID_REQUEST;
796     }
797
798   ret = _gnutls_openpgp_privkey_get_mpis (pkey, kid32, params, &params_size);
799   if (ret < 0)
800     {
801       gnutls_assert ();
802       return ret;
803     }
804
805   /* P */
806   ret = _gnutls_mpi_dprint (p, params[0]);
807   if (ret < 0)
808     {
809       gnutls_assert ();
810       goto cleanup;
811     }
812
813   /* Q */
814   ret = _gnutls_mpi_dprint (q, params[1]);
815   if (ret < 0)
816     {
817       gnutls_assert ();
818       _gnutls_free_datum (p);
819       goto cleanup;
820     }
821
822
823   /* G */
824   ret = _gnutls_mpi_dprint (g, params[2]);
825   if (ret < 0)
826     {
827       gnutls_assert ();
828       _gnutls_free_datum (p);
829       _gnutls_free_datum (q);
830       goto cleanup;
831     }
832
833
834   /* Y */
835   ret = _gnutls_mpi_dprint (y, params[3]);
836   if (ret < 0)
837     {
838       gnutls_assert ();
839       _gnutls_free_datum (p);
840       _gnutls_free_datum (g);
841       _gnutls_free_datum (q);
842       goto cleanup;
843     }
844
845   ret = _gnutls_mpi_dprint (x, params[4]);
846   if (ret < 0)
847     {
848       gnutls_assert ();
849       _gnutls_free_datum (y);
850       _gnutls_free_datum (p);
851       _gnutls_free_datum (g);
852       _gnutls_free_datum (q);
853       goto cleanup;
854     }
855
856   ret = 0;
857
858 cleanup:
859   for (i = 0; i < params_size; i++)
860     {
861       _gnutls_mpi_release (&params[i]);
862     }
863   return ret;
864 }
865
866
867 /**
868  * gnutls_openpgp_privkey_export_rsa_raw - This function will export the RSA private key
869  * @pkey: Holds the certificate
870  * @m: will hold the modulus
871  * @e: will hold the public exponent
872  * @d: will hold the private exponent
873  * @p: will hold the first prime (p)
874  * @q: will hold the second prime (q)
875  * @u: will hold the coefficient
876  *
877  * This function will export the RSA private key's parameters found in
878  * the given structure.  The new parameters will be allocated using
879  * gnutls_malloc() and will be stored in the appropriate datum.
880  *
881  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
882  **/
883 int
884 gnutls_openpgp_privkey_export_rsa_raw (gnutls_openpgp_privkey_t pkey, 
885                                     gnutls_datum_t * m, gnutls_datum_t * e,
886                                     gnutls_datum_t * d, gnutls_datum_t * p,
887                                     gnutls_datum_t * q, gnutls_datum_t * u)
888 {
889 gnutls_openpgp_keyid_t keyid;
890 int ret;
891
892   ret = gnutls_openpgp_privkey_get_key_id( pkey, keyid);  
893   if (ret < 0)
894     {
895       gnutls_assert ();
896       return ret;
897     }
898     
899   return _get_sk_rsa_raw( pkey, keyid, m, e, d, p, q, u);
900 }
901
902 /**
903  * gnutls_openpgp_privkey_export_dsa_raw - This function will export the DSA private key
904  * @pkey: Holds the certificate
905  * @p: will hold the p
906  * @q: will hold the q
907  * @g: will hold the g
908  * @y: will hold the y
909  * @x: will hold the x
910  *
911  * This function will export the DSA private key's parameters found in
912  * the given certificate.  The new parameters will be allocated using
913  * gnutls_malloc() and will be stored in the appropriate datum.
914  *
915  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
916  **/
917 int
918 gnutls_openpgp_privkey_export_dsa_raw (gnutls_openpgp_privkey_t pkey, 
919                                     gnutls_datum_t * p, gnutls_datum_t * q,
920                                     gnutls_datum_t * g, gnutls_datum_t * y,
921                                     gnutls_datum_t * x)
922 {
923 gnutls_openpgp_keyid_t keyid;
924 int ret;
925
926   ret = gnutls_openpgp_privkey_get_key_id( pkey, keyid);  
927   if (ret < 0)
928     {
929       gnutls_assert ();
930       return ret;
931     }
932     
933   return _get_sk_dsa_raw( pkey, keyid, p, q, g, y, x);
934 }
935
936 /**
937  * gnutls_openpgp_privkey_export_subkey_rsa_raw - export the RSA private key
938  * @pkey: Holds the certificate
939  * @idx: Is the subkey index
940  * @m: will hold the modulus
941  * @e: will hold the public exponent
942  * @d: will hold the private exponent
943  * @p: will hold the first prime (p)
944  * @q: will hold the second prime (q)
945  * @u: will hold the coefficient
946  *
947  * This function will export the RSA private key's parameters found in
948  * the given structure.  The new parameters will be allocated using
949  * gnutls_malloc() and will be stored in the appropriate datum.
950  *
951  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
952  **/
953 int
954 gnutls_openpgp_privkey_export_subkey_rsa_raw (gnutls_openpgp_privkey_t pkey, unsigned int idx,
955                                     gnutls_datum_t * m, gnutls_datum_t * e,
956                                     gnutls_datum_t * d, gnutls_datum_t * p,
957                                     gnutls_datum_t * q, gnutls_datum_t * u)
958 {
959 gnutls_openpgp_keyid_t keyid;
960 int ret;
961
962   ret = gnutls_openpgp_privkey_get_subkey_id( pkey, idx, keyid);  
963   if (ret < 0)
964     {
965       gnutls_assert ();
966       return ret;
967     }
968     
969   return _get_sk_rsa_raw( pkey, keyid, m, e, d, p, q, u);
970 }
971
972 /**
973  * gnutls_openpgp_privkey_export_subkey_dsa_raw - export the DSA private key
974  * @pkey: Holds the certificate
975  * @idx: Is the subkey index
976  * @p: will hold the p
977  * @q: will hold the q
978  * @g: will hold the g
979  * @y: will hold the y
980  * @x: will hold the x
981  *
982  * This function will export the DSA private key's parameters found
983  * in the given certificate.  The new parameters will be allocated
984  * using gnutls_malloc() and will be stored in the appropriate datum.
985  *
986  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
987  **/
988 int
989 gnutls_openpgp_privkey_export_subkey_dsa_raw (gnutls_openpgp_privkey_t pkey,
990                                               unsigned int idx,
991                                               gnutls_datum_t * p,
992                                               gnutls_datum_t * q,
993                                               gnutls_datum_t * g,
994                                               gnutls_datum_t * y,
995                                               gnutls_datum_t * x)
996 {
997   gnutls_openpgp_keyid_t keyid;
998   int ret;
999
1000   ret = gnutls_openpgp_privkey_get_subkey_id( pkey, idx, keyid);
1001   if (ret < 0)
1002     {
1003       gnutls_assert ();
1004       return ret;
1005     }
1006
1007   return _get_sk_dsa_raw( pkey, keyid, p, q, g, y, x);
1008 }
1009
1010 /**
1011  * gnutls_openpgp_privkey_get_preferred_key_id - Gets the preferred keyID
1012  * @key: the structure that contains the OpenPGP public key.
1013  * @keyid: the struct to save the keyid.
1014  *
1015  * Get the preferred key-id for the key.
1016  *
1017  * Returns: the 64-bit preferred keyID of the OpenPGP key, or if it
1018  *   hasn't been set it returns %GNUTLS_E_INVALID_REQUEST.
1019  **/
1020 int
1021 gnutls_openpgp_privkey_get_preferred_key_id (gnutls_openpgp_privkey_t key,
1022                                              gnutls_openpgp_keyid_t keyid)
1023 {
1024   if (!key || !keyid || !key->preferred_set)
1025     {
1026       gnutls_assert ();
1027       return GNUTLS_E_INVALID_REQUEST;
1028     }
1029
1030   memcpy( keyid, key->preferred_keyid, sizeof(keyid));
1031
1032   return 0;
1033 }
1034
1035 /**
1036  * gnutls_openpgp_privkey_set_preferred_key_id - Set the prefered keyID
1037  * @key: the structure that contains the OpenPGP public key.
1038  * @keyid: the selected keyid
1039  *
1040  * This allows setting a preferred key id for the given certificate.
1041  * This key will be used by functions that involve key handling.
1042  *
1043  * Returns: On success, 0 is returned, or an error code.
1044  **/
1045 int
1046 gnutls_openpgp_privkey_set_preferred_key_id (gnutls_openpgp_privkey_t key,
1047                                              const gnutls_openpgp_keyid_t keyid)
1048 {
1049   int ret;
1050
1051   if (!key)
1052     {
1053       gnutls_assert ();
1054       return GNUTLS_E_INVALID_REQUEST;
1055     }
1056
1057   /* check if the id is valid */
1058   ret = gnutls_openpgp_privkey_get_subkey_idx ( key, keyid);
1059   if (ret < 0)
1060     {
1061       _gnutls_x509_log("the requested subkey does not exist\n");
1062       gnutls_assert();
1063       return ret;
1064     }
1065
1066   key->preferred_set = 1;
1067   memcpy( key->preferred_keyid, keyid, sizeof(keyid));
1068
1069   return 0;
1070 }