Tizen 2.0 Release
[external/libgnutls26.git] / lib / openpgp / privkey.c
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
3  * Software Foundation, Inc.
4  *
5  * Author: 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 privkey 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 <gnutls_num.h>
34 #include <openpgp_int.h>
35 #include <gnutls_openpgp.h>
36 #include <gnutls_cert.h>
37 #include <gnutls_sig.h>
38
39 /**
40  * gnutls_openpgp_privkey_init:
41  * @key: The structure to be initialized
42  *
43  * This function will initialize an OpenPGP key structure.
44  *
45  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
46  **/
47 int
48 gnutls_openpgp_privkey_init (gnutls_openpgp_privkey_t * key)
49 {
50   *key = gnutls_calloc (1, sizeof (gnutls_openpgp_privkey_int));
51
52   if (*key)
53     return 0;                   /* success */
54   return GNUTLS_E_MEMORY_ERROR;
55 }
56
57 /**
58  * gnutls_openpgp_privkey_deinit:
59  * @key: The structure to be initialized
60  *
61  * This function will deinitialize a key structure.
62  **/
63 void
64 gnutls_openpgp_privkey_deinit (gnutls_openpgp_privkey_t key)
65 {
66   if (!key)
67     return;
68
69   if (key->knode)
70     {
71       cdk_kbnode_release (key->knode);
72       key->knode = NULL;
73     }
74
75   gnutls_free (key);
76 }
77
78 /*-
79  * _gnutls_openpgp_privkey_cpy - This function copies a gnutls_openpgp_privkey_t structure
80  * @dest: The structure where to copy
81  * @src: The structure to be copied
82  *
83  * This function will copy an X.509 certificate structure.
84  *
85  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
86  *   negative error value.
87  -*/
88 int
89 _gnutls_openpgp_privkey_cpy (gnutls_openpgp_privkey_t dest, gnutls_openpgp_privkey_t src)
90 {
91   int ret;
92   size_t der_size=0;
93   opaque *der;
94   gnutls_datum_t tmp;
95
96   ret = gnutls_openpgp_privkey_export (src, GNUTLS_OPENPGP_FMT_RAW, NULL, 0, NULL, &der_size);
97   if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
98     return gnutls_assert_val(ret);
99
100   der = gnutls_malloc (der_size);
101   if (der == NULL)
102     return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
103
104   ret = gnutls_openpgp_privkey_export (src, GNUTLS_OPENPGP_FMT_RAW, NULL, 0, der, &der_size);
105   if (ret < 0)
106     {
107       gnutls_assert ();
108       gnutls_free (der);
109       return ret;
110     }
111
112   tmp.data = der;
113   tmp.size = der_size;
114   ret = gnutls_openpgp_privkey_import (dest, &tmp, GNUTLS_OPENPGP_FMT_RAW, NULL, 0);
115
116   gnutls_free (der);
117
118   if (ret < 0)
119     return gnutls_assert_val(ret);
120
121   memcpy(dest->preferred_keyid, src->preferred_keyid, GNUTLS_OPENPGP_KEYID_SIZE);
122   dest->preferred_set = src->preferred_set;
123
124   return 0;
125 }
126
127 /**
128  * gnutls_openpgp_privkey_sec_param:
129  * @key: a key structure
130  *
131  * This function will return the security parameter appropriate with
132  * this private key.
133  *
134  * Returns: On success, a valid security parameter is returned otherwise
135  * %GNUTLS_SEC_PARAM_UNKNOWN is returned.
136  **/
137 gnutls_sec_param_t
138 gnutls_openpgp_privkey_sec_param (gnutls_openpgp_privkey_t key)
139 {
140   gnutls_pk_algorithm_t algo;
141   unsigned int bits;
142
143   algo = gnutls_openpgp_privkey_get_pk_algorithm (key, &bits);
144   if (algo == GNUTLS_PK_UNKNOWN)
145     {
146       gnutls_assert ();
147       return GNUTLS_SEC_PARAM_UNKNOWN;
148     }
149
150   return gnutls_pk_bits_to_sec_param (algo, bits);
151 }
152
153 /**
154  * gnutls_openpgp_privkey_import:
155  * @key: The structure to store the parsed key.
156  * @data: The RAW or BASE64 encoded key.
157  * @format: One of #gnutls_openpgp_crt_fmt_t elements.
158  * @password: not used for now
159  * @flags: should be zero
160  *
161  * This function will convert the given RAW or Base64 encoded key to
162  * the native gnutls_openpgp_privkey_t format.  The output will be
163  * stored in 'key'.
164  *
165  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
166  **/
167 int
168 gnutls_openpgp_privkey_import (gnutls_openpgp_privkey_t key,
169                                const gnutls_datum_t * data,
170                                gnutls_openpgp_crt_fmt_t format,
171                                const char *password, unsigned int flags)
172 {
173   cdk_stream_t inp;
174   cdk_packet_t pkt;
175   int rc;
176
177   if (data->data == NULL || data->size == 0)
178     {
179       gnutls_assert ();
180       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
181     }
182
183   if (format == GNUTLS_OPENPGP_FMT_RAW)
184     {
185       rc = cdk_kbnode_read_from_mem (&key->knode, data->data, data->size);
186       if (rc != 0)
187         {
188           rc = _gnutls_map_cdk_rc (rc);
189           gnutls_assert ();
190           return rc;
191         }
192     }
193   else
194     {
195       rc = cdk_stream_tmp_from_mem (data->data, data->size, &inp);
196       if (rc != 0)
197         {
198           rc = _gnutls_map_cdk_rc (rc);
199           gnutls_assert ();
200           return rc;
201         }
202
203       if (cdk_armor_filter_use (inp))
204         {
205           rc = cdk_stream_set_armor_flag (inp, 0);
206           if (rc != 0)
207             {
208               rc = _gnutls_map_cdk_rc (rc);
209               cdk_stream_close (inp);
210               gnutls_assert ();
211               return rc;
212             }
213         }
214
215       rc = cdk_keydb_get_keyblock (inp, &key->knode);
216       cdk_stream_close (inp);
217
218       if (rc != 0)
219         {
220           rc = _gnutls_map_cdk_rc (rc);
221           gnutls_assert ();
222           return rc;
223         }
224     }
225
226   /* Test if the import was successful. */
227   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY);
228   if (pkt == NULL)
229     {
230       gnutls_assert ();
231       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
232     }
233
234   return 0;
235 }
236
237 /**
238  * gnutls_openpgp_privkey_export:
239  * @key: Holds the key.
240  * @format: One of gnutls_openpgp_crt_fmt_t elements.
241  * @password: the password that will be used to encrypt the key. (unused for now)
242  * @flags: zero for future compatibility
243  * @output_data: will contain the key base64 encoded or raw
244  * @output_data_size: holds the size of output_data (and will be
245  *   replaced by the actual size of parameters)
246  *
247  * This function will convert the given key to RAW or Base64 format.
248  * If the buffer provided is not long enough to hold the output, then
249  * GNUTLS_E_SHORT_MEMORY_BUFFER will be returned.
250  *
251  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
252  *
253  * Since: 2.4.0
254  **/
255 int
256 gnutls_openpgp_privkey_export (gnutls_openpgp_privkey_t key,
257                                gnutls_openpgp_crt_fmt_t format,
258                                const char *password, unsigned int flags,
259                                void *output_data, size_t * output_data_size)
260 {
261   /* FIXME for now we do not export encrypted keys */
262   return _gnutls_openpgp_export (key->knode, format, output_data,
263                                  output_data_size, 1);
264 }
265
266
267 /**
268  * gnutls_openpgp_privkey_get_pk_algorithm:
269  * @key: is an OpenPGP key
270  * @bits: if bits is non null it will hold the size of the parameters' in bits
271  *
272  * This function will return the public key algorithm of an OpenPGP
273  * certificate.
274  *
275  * If bits is non null, it should have enough size to hold the parameters
276  * size in bits. For RSA the bits returned is the modulus.
277  * For DSA the bits returned are of the public exponent.
278  *
279  * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
280  *   success, or a negative value on error.
281  *
282  * Since: 2.4.0
283  **/
284 gnutls_pk_algorithm_t
285 gnutls_openpgp_privkey_get_pk_algorithm (gnutls_openpgp_privkey_t key,
286                                          unsigned int *bits)
287 {
288   cdk_packet_t pkt;
289   int algo;
290
291   if (!key)
292     {
293       gnutls_assert ();
294       return GNUTLS_PK_UNKNOWN;
295     }
296
297   algo = 0;
298   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY);
299   if (pkt)
300     {
301       if (bits)
302         *bits = cdk_pk_get_nbits (pkt->pkt.secret_key->pk);
303       algo = _gnutls_openpgp_get_algo (pkt->pkt.secret_key->pk->pubkey_algo);
304     }
305
306   return algo;
307 }
308
309 int
310 _gnutls_openpgp_get_algo (int cdk_algo)
311 {
312   int algo;
313
314   if (is_RSA (cdk_algo))
315     algo = GNUTLS_PK_RSA;
316   else if (is_DSA (cdk_algo))
317     algo = GNUTLS_PK_DSA;
318   else
319     {
320       _gnutls_x509_log ("Unknown OpenPGP algorithm %d\n", cdk_algo);
321       algo = GNUTLS_PK_UNKNOWN;
322     }
323
324   return algo;
325 }
326
327 /**
328  * gnutls_openpgp_privkey_get_revoked_status:
329  * @key: the structure that contains the OpenPGP private key.
330  *
331  * Get revocation status of key.
332  *
333  * Returns: true (1) if the key has been revoked, or false (0) if it
334  *   has not, or a negative value indicates an error.
335  *
336  * Since: 2.4.0
337  **/
338 int
339 gnutls_openpgp_privkey_get_revoked_status (gnutls_openpgp_privkey_t key)
340 {
341   cdk_packet_t pkt;
342
343   if (!key)
344     {
345       gnutls_assert ();
346       return GNUTLS_E_INVALID_REQUEST;
347     }
348
349   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY);
350   if (!pkt)
351     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
352
353   if (pkt->pkt.secret_key->is_revoked != 0)
354     return 1;
355   return 0;
356 }
357
358 /**
359  * gnutls_openpgp_privkey_get_fingerprint:
360  * @key: the raw data that contains the OpenPGP secret key.
361  * @fpr: the buffer to save the fingerprint, must hold at least 20 bytes.
362  * @fprlen: the integer to save the length of the fingerprint.
363  *
364  * Get the fingerprint of the OpenPGP key. Depends on the
365  * algorithm, the fingerprint can be 16 or 20 bytes.
366  *
367  * Returns: On success, 0 is returned, or an error code.
368  *
369  * Since: 2.4.0
370  **/
371 int
372 gnutls_openpgp_privkey_get_fingerprint (gnutls_openpgp_privkey_t key,
373                                         void *fpr, size_t * fprlen)
374 {
375   cdk_packet_t pkt;
376   cdk_pkt_pubkey_t pk = NULL;
377
378   if (!fpr || !fprlen)
379     {
380       gnutls_assert ();
381       return GNUTLS_E_INVALID_REQUEST;
382     }
383
384   *fprlen = 0;
385
386   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY);
387   if (!pkt)
388     {
389       gnutls_assert ();
390       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
391     }
392
393   pk = pkt->pkt.secret_key->pk;
394   *fprlen = 20;
395
396   if (is_RSA (pk->pubkey_algo) && pk->version < 4)
397     *fprlen = 16;
398
399   cdk_pk_get_fingerprint (pk, fpr);
400
401   return 0;
402 }
403
404 /**
405  * gnutls_openpgp_privkey_get_key_id:
406  * @key: the structure that contains the OpenPGP secret key.
407  * @keyid: the buffer to save the keyid.
408  *
409  * Get key-id.
410  *
411  * Returns: the 64-bit keyID of the OpenPGP key.
412  *
413  * Since: 2.4.0
414  **/
415 int
416 gnutls_openpgp_privkey_get_key_id (gnutls_openpgp_privkey_t key,
417                                    gnutls_openpgp_keyid_t keyid)
418 {
419   cdk_packet_t pkt;
420   uint32_t kid[2];
421
422   if (!key || !keyid)
423     {
424       gnutls_assert ();
425       return GNUTLS_E_INVALID_REQUEST;
426     }
427
428   pkt = cdk_kbnode_find_packet (key->knode, CDK_PKT_SECRET_KEY);
429   if (!pkt)
430     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
431
432   cdk_sk_get_keyid (pkt->pkt.secret_key, kid);
433   _gnutls_write_uint32 (kid[0], keyid);
434   _gnutls_write_uint32 (kid[1], keyid + 4);
435
436   return 0;
437 }
438
439
440 /**
441  * gnutls_openpgp_privkey_get_subkey_count:
442  * @key: is an OpenPGP key
443  *
444  * This function will return the number of subkeys present in the
445  * given OpenPGP certificate.
446  *
447  * Returns: the number of subkeys, or a negative value on error.
448  *
449  * Since: 2.4.0
450  **/
451 int
452 gnutls_openpgp_privkey_get_subkey_count (gnutls_openpgp_privkey_t key)
453 {
454   cdk_kbnode_t p, ctx;
455   cdk_packet_t pkt;
456   int subkeys;
457
458   if (key == NULL)
459     {
460       gnutls_assert ();
461       return 0;
462     }
463
464   ctx = NULL;
465   subkeys = 0;
466   while ((p = cdk_kbnode_walk (key->knode, &ctx, 0)))
467     {
468       pkt = cdk_kbnode_get_packet (p);
469       if (pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
470         subkeys++;
471     }
472
473   return subkeys;
474 }
475
476 /* returns the subkey with the given index */
477 static cdk_packet_t
478 _get_secret_subkey (gnutls_openpgp_privkey_t key, unsigned int indx)
479 {
480   cdk_kbnode_t p, ctx;
481   cdk_packet_t pkt;
482   unsigned int subkeys;
483
484   ctx = NULL;
485   subkeys = 0;
486   while ((p = cdk_kbnode_walk (key->knode, &ctx, 0)))
487     {
488       pkt = cdk_kbnode_get_packet (p);
489       if (pkt->pkttype == CDK_PKT_SECRET_SUBKEY && indx == subkeys++)
490         return pkt;
491     }
492
493   return NULL;
494 }
495
496 /**
497  * gnutls_openpgp_privkey_get_subkey_revoked_status:
498  * @key: the structure that contains the OpenPGP private key.
499  * @idx: is the subkey index
500  *
501  * Get revocation status of key.
502  *
503  * Returns: true (1) if the key has been revoked, or false (0) if it
504  *   has not, or a negative value indicates an error.
505  *
506  * Since: 2.4.0
507  **/
508 int
509 gnutls_openpgp_privkey_get_subkey_revoked_status (gnutls_openpgp_privkey_t
510                                                   key, unsigned int idx)
511 {
512   cdk_packet_t pkt;
513
514   if (!key)
515     {
516       gnutls_assert ();
517       return GNUTLS_E_INVALID_REQUEST;
518     }
519
520   pkt = _get_secret_subkey (key, idx);
521   if (!pkt)
522     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
523
524   if (pkt->pkt.secret_key->is_revoked != 0)
525     return 1;
526   return 0;
527 }
528
529 /**
530  * gnutls_openpgp_privkey_get_subkey_pk_algorithm:
531  * @key: is an OpenPGP key
532  * @idx: is the subkey index
533  * @bits: if bits is non null it will hold the size of the parameters' in bits
534  *
535  * This function will return the public key algorithm of a subkey of an OpenPGP
536  * certificate.
537  *
538  * If bits is non null, it should have enough size to hold the parameters
539  * size in bits. For RSA the bits returned is the modulus.
540  * For DSA the bits returned are of the public exponent.
541  *
542  * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
543  *   success, or a negative value on error.
544  *
545  * Since: 2.4.0
546  **/
547 gnutls_pk_algorithm_t
548 gnutls_openpgp_privkey_get_subkey_pk_algorithm (gnutls_openpgp_privkey_t key,
549                                                 unsigned int idx,
550                                                 unsigned int *bits)
551 {
552   cdk_packet_t pkt;
553   int algo;
554
555   if (!key)
556     {
557       gnutls_assert ();
558       return GNUTLS_PK_UNKNOWN;
559     }
560
561   pkt = _get_secret_subkey (key, idx);
562
563   algo = 0;
564   if (pkt)
565     {
566       if (bits)
567         *bits = cdk_pk_get_nbits (pkt->pkt.secret_key->pk);
568       algo = pkt->pkt.secret_key->pubkey_algo;
569       if (is_RSA (algo))
570         algo = GNUTLS_PK_RSA;
571       else if (is_DSA (algo))
572         algo = GNUTLS_PK_DSA;
573       else
574         algo = GNUTLS_E_UNKNOWN_PK_ALGORITHM;
575     }
576
577   return algo;
578 }
579
580 /**
581  * gnutls_openpgp_privkey_get_subkey_idx:
582  * @key: the structure that contains the OpenPGP private key.
583  * @keyid: the keyid.
584  *
585  * Get index of subkey.
586  *
587  * Returns: the index of the subkey or a negative error value.
588  *
589  * Since: 2.4.0
590  **/
591 int
592 gnutls_openpgp_privkey_get_subkey_idx (gnutls_openpgp_privkey_t key,
593                                        const gnutls_openpgp_keyid_t keyid)
594 {
595   int ret;
596   uint32_t kid[2];
597
598   if (!key)
599     {
600       gnutls_assert ();
601       return GNUTLS_E_INVALID_REQUEST;
602     }
603
604   KEYID_IMPORT (kid, keyid);
605   ret = _gnutls_openpgp_find_subkey_idx (key->knode, kid, 1);
606
607   if (ret < 0)
608     {
609       gnutls_assert ();
610     }
611
612   return ret;
613 }
614
615 /**
616  * gnutls_openpgp_privkey_get_subkey_creation_time:
617  * @key: the structure that contains the OpenPGP private key.
618  * @idx: the subkey index
619  *
620  * Get subkey creation time.
621  *
622  * Returns: the timestamp when the OpenPGP key was created.
623  *
624  * Since: 2.4.0
625  **/
626 time_t
627 gnutls_openpgp_privkey_get_subkey_creation_time (gnutls_openpgp_privkey_t key,
628                                                  unsigned int idx)
629 {
630   cdk_packet_t pkt;
631   time_t timestamp;
632
633   if (!key)
634     return (time_t) - 1;
635
636   pkt = _get_secret_subkey (key, idx);
637   if (pkt)
638     timestamp = pkt->pkt.secret_key->pk->timestamp;
639   else
640     timestamp = 0;
641
642   return timestamp;
643 }
644
645 /**
646  * gnutls_openpgp_privkey_get_subkey_expiration_time:
647  * @key: the structure that contains the OpenPGP private key.
648  * @idx: the subkey index
649  *
650  * Get subkey expiration time.  A value of '0' means that the key
651  * doesn't expire at all.
652  *
653  * Returns: the time when the OpenPGP key expires.
654  *
655  * Since: 2.4.0
656  **/
657 time_t
658 gnutls_openpgp_privkey_get_subkey_expiration_time (gnutls_openpgp_privkey_t
659                                                    key, unsigned int idx)
660 {
661   cdk_packet_t pkt;
662   time_t expiredate;
663
664   if (!key)
665     return (time_t) - 1;
666
667   pkt = _get_secret_subkey (key, idx);
668   if (pkt)
669     expiredate = pkt->pkt.secret_key->expiredate;
670   else
671     expiredate = 0;
672
673   return expiredate;
674 }
675
676 /**
677  * gnutls_openpgp_privkey_get_subkey_id:
678  * @key: the structure that contains the OpenPGP secret key.
679  * @idx: the subkey index
680  * @keyid: the buffer to save the keyid.
681  *
682  * Get the key-id for the subkey.
683  *
684  * Returns: the 64-bit keyID of the OpenPGP key.
685  *
686  * Since: 2.4.0
687  **/
688 int
689 gnutls_openpgp_privkey_get_subkey_id (gnutls_openpgp_privkey_t key,
690                                       unsigned int idx,
691                                       gnutls_openpgp_keyid_t keyid)
692 {
693   cdk_packet_t pkt;
694   uint32_t kid[2];
695
696   if (!key || !keyid)
697     {
698       gnutls_assert ();
699       return GNUTLS_E_INVALID_REQUEST;
700     }
701
702   pkt = _get_secret_subkey (key, idx);
703   if (!pkt)
704     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
705
706   cdk_sk_get_keyid (pkt->pkt.secret_key, kid);
707   _gnutls_write_uint32 (kid[0], keyid);
708   _gnutls_write_uint32 (kid[1], keyid + 4);
709
710   return 0;
711 }
712
713 /**
714  * gnutls_openpgp_privkey_get_subkey_fingerprint:
715  * @key: the raw data that contains the OpenPGP secret key.
716  * @idx: the subkey index
717  * @fpr: the buffer to save the fingerprint, must hold at least 20 bytes.
718  * @fprlen: the integer to save the length of the fingerprint.
719  *
720  * Get the fingerprint of an OpenPGP subkey.  Depends on the
721  * algorithm, the fingerprint can be 16 or 20 bytes.
722  *
723  * Returns: On success, 0 is returned, or an error code.
724  *
725  * Since: 2.4.0
726  **/
727 int
728 gnutls_openpgp_privkey_get_subkey_fingerprint (gnutls_openpgp_privkey_t key,
729                                                unsigned int idx,
730                                                void *fpr, size_t * fprlen)
731 {
732   cdk_packet_t pkt;
733   cdk_pkt_pubkey_t pk = NULL;
734
735   if (!fpr || !fprlen)
736     {
737       gnutls_assert ();
738       return GNUTLS_E_INVALID_REQUEST;
739     }
740
741   *fprlen = 0;
742
743   pkt = _get_secret_subkey (key, idx);
744   if (!pkt)
745     return GNUTLS_E_OPENPGP_GETKEY_FAILED;
746
747
748   pk = pkt->pkt.secret_key->pk;
749   *fprlen = 20;
750
751   if (is_RSA (pk->pubkey_algo) && pk->version < 4)
752     *fprlen = 16;
753
754   cdk_pk_get_fingerprint (pk, fpr);
755
756   return 0;
757 }
758
759 /* Extracts DSA and RSA parameters from a certificate.
760  */
761 int
762 _gnutls_openpgp_privkey_get_mpis (gnutls_openpgp_privkey_t pkey,
763                                   uint32_t * keyid /*[2] */ ,
764                                   bigint_t * params, int *params_size)
765 {
766   int result, i;
767   int pk_algorithm;
768   gnutls_pk_params_st pk_params;
769   cdk_packet_t pkt;
770
771   memset (&pk_params, 0, sizeof (pk_params));
772
773   if (keyid == NULL)
774     pkt = cdk_kbnode_find_packet (pkey->knode, CDK_PKT_SECRET_KEY);
775   else
776     pkt = _gnutls_openpgp_find_key (pkey->knode, keyid, 1);
777
778   if (pkt == NULL)
779     {
780       gnutls_assert ();
781       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
782     }
783
784   pk_algorithm =
785     _gnutls_openpgp_get_algo (pkt->pkt.secret_key->pk->pubkey_algo);
786
787   switch (pk_algorithm)
788     {
789     case GNUTLS_PK_RSA:
790       /* openpgp does not hold all parameters as in PKCS #1
791        */
792       pk_params.params_nr = RSA_PRIVATE_PARAMS - 2;
793       break;
794     case GNUTLS_PK_DSA:
795       pk_params.params_nr = DSA_PRIVATE_PARAMS;
796       break;
797     default:
798       gnutls_assert ();
799       return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
800     }
801
802   for (i = 0; i < pk_params.params_nr; i++)
803     {
804       result = _gnutls_read_pgp_mpi (pkt, 1, i, &pk_params.params[i]);
805       if (result < 0)
806         {
807           gnutls_assert ();
808           goto error;
809         }
810     }
811   
812   /* fixup will generate exp1 and exp2 that are not
813    * available here.
814    */
815   result = _gnutls_pk_fixup (pk_algorithm, GNUTLS_IMPORT, &pk_params);
816   if (result < 0)
817     {
818       gnutls_assert ();
819       goto error;
820     }
821
822   if (*params_size < pk_params.params_nr)
823     {
824       gnutls_assert ();
825       return GNUTLS_E_INTERNAL_ERROR;
826     }
827
828   *params_size = pk_params.params_nr;
829   for (i = 0; i < pk_params.params_nr; i++)
830     params[i] = pk_params.params[i];
831
832   return 0;
833
834 error:
835   {
836     int j;
837     for (j = 0; j < i; j++)
838       _gnutls_mpi_release (&pk_params.params[j]);
839   }
840
841   return result;
842 }
843
844 /* The internal version of export
845  */
846 static int
847 _get_sk_rsa_raw (gnutls_openpgp_privkey_t pkey, gnutls_openpgp_keyid_t keyid,
848                  gnutls_datum_t * m, gnutls_datum_t * e,
849                  gnutls_datum_t * d, gnutls_datum_t * p,
850                  gnutls_datum_t * q, gnutls_datum_t * u)
851 {
852   int pk_algorithm, ret, i;
853   cdk_packet_t pkt;
854   uint32_t kid32[2];
855   bigint_t params[MAX_PRIV_PARAMS_SIZE];
856   int params_size = MAX_PRIV_PARAMS_SIZE;
857
858   if (pkey == NULL)
859     {
860       gnutls_assert ();
861       return GNUTLS_E_INVALID_REQUEST;
862     }
863
864   KEYID_IMPORT (kid32, keyid);
865
866   pkt = _gnutls_openpgp_find_key (pkey->knode, kid32, 1);
867   if (pkt == NULL)
868     {
869       gnutls_assert ();
870       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
871     }
872
873   pk_algorithm =
874     _gnutls_openpgp_get_algo (pkt->pkt.secret_key->pk->pubkey_algo);
875
876   if (pk_algorithm != GNUTLS_PK_RSA)
877     {
878       gnutls_assert ();
879       return GNUTLS_E_INVALID_REQUEST;
880     }
881
882   ret = _gnutls_openpgp_privkey_get_mpis (pkey, kid32, params, &params_size);
883   if (ret < 0)
884     {
885       gnutls_assert ();
886       return ret;
887     }
888
889   ret = _gnutls_mpi_dprint (params[0], m);
890   if (ret < 0)
891     {
892       gnutls_assert ();
893       goto cleanup;
894     }
895
896   ret = _gnutls_mpi_dprint (params[1], e);
897   if (ret < 0)
898     {
899       gnutls_assert ();
900       _gnutls_free_datum (m);
901       goto cleanup;
902     }
903
904   ret = _gnutls_mpi_dprint (params[2], d);
905   if (ret < 0)
906     {
907       gnutls_assert ();
908       _gnutls_free_datum (m);
909       _gnutls_free_datum (e);
910       goto cleanup;
911     }
912
913   ret = _gnutls_mpi_dprint (params[3], p);
914   if (ret < 0)
915     {
916       gnutls_assert ();
917       _gnutls_free_datum (m);
918       _gnutls_free_datum (e);
919       _gnutls_free_datum (d);
920       goto cleanup;
921     }
922
923   ret = _gnutls_mpi_dprint (params[4], q);
924   if (ret < 0)
925     {
926       gnutls_assert ();
927       _gnutls_free_datum (m);
928       _gnutls_free_datum (e);
929       _gnutls_free_datum (d);
930       _gnutls_free_datum (p);
931       goto cleanup;
932     }
933
934   ret = _gnutls_mpi_dprint (params[5], u);
935   if (ret < 0)
936     {
937       gnutls_assert ();
938       _gnutls_free_datum (q);
939       _gnutls_free_datum (m);
940       _gnutls_free_datum (e);
941       _gnutls_free_datum (d);
942       _gnutls_free_datum (p);
943       goto cleanup;
944     }
945
946   ret = 0;
947
948 cleanup:
949   for (i = 0; i < params_size; i++)
950     {
951       _gnutls_mpi_release (&params[i]);
952     }
953   return ret;
954 }
955
956 static int
957 _get_sk_dsa_raw (gnutls_openpgp_privkey_t pkey, gnutls_openpgp_keyid_t keyid,
958                  gnutls_datum_t * p, gnutls_datum_t * q,
959                  gnutls_datum_t * g, gnutls_datum_t * y, gnutls_datum_t * x)
960 {
961   int pk_algorithm, ret, i;
962   cdk_packet_t pkt;
963   uint32_t kid32[2];
964   bigint_t params[MAX_PRIV_PARAMS_SIZE];
965   int params_size = MAX_PRIV_PARAMS_SIZE;
966
967   if (pkey == NULL)
968     {
969       gnutls_assert ();
970       return GNUTLS_E_INVALID_REQUEST;
971     }
972
973   KEYID_IMPORT (kid32, keyid);
974
975   pkt = _gnutls_openpgp_find_key (pkey->knode, kid32, 1);
976   if (pkt == NULL)
977     {
978       gnutls_assert ();
979       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
980     }
981
982   pk_algorithm =
983     _gnutls_openpgp_get_algo (pkt->pkt.secret_key->pk->pubkey_algo);
984
985   if (pk_algorithm != GNUTLS_PK_DSA)
986     {
987       gnutls_assert ();
988       return GNUTLS_E_INVALID_REQUEST;
989     }
990
991   ret = _gnutls_openpgp_privkey_get_mpis (pkey, kid32, params, &params_size);
992   if (ret < 0)
993     {
994       gnutls_assert ();
995       return ret;
996     }
997
998   /* P */
999   ret = _gnutls_mpi_dprint (params[0], p);
1000   if (ret < 0)
1001     {
1002       gnutls_assert ();
1003       goto cleanup;
1004     }
1005
1006   /* Q */
1007   ret = _gnutls_mpi_dprint (params[1], q);
1008   if (ret < 0)
1009     {
1010       gnutls_assert ();
1011       _gnutls_free_datum (p);
1012       goto cleanup;
1013     }
1014
1015
1016   /* G */
1017   ret = _gnutls_mpi_dprint (params[2], g);
1018   if (ret < 0)
1019     {
1020       gnutls_assert ();
1021       _gnutls_free_datum (p);
1022       _gnutls_free_datum (q);
1023       goto cleanup;
1024     }
1025
1026
1027   /* Y */
1028   ret = _gnutls_mpi_dprint (params[3], y);
1029   if (ret < 0)
1030     {
1031       gnutls_assert ();
1032       _gnutls_free_datum (p);
1033       _gnutls_free_datum (g);
1034       _gnutls_free_datum (q);
1035       goto cleanup;
1036     }
1037
1038   ret = _gnutls_mpi_dprint (params[4], x);
1039   if (ret < 0)
1040     {
1041       gnutls_assert ();
1042       _gnutls_free_datum (y);
1043       _gnutls_free_datum (p);
1044       _gnutls_free_datum (g);
1045       _gnutls_free_datum (q);
1046       goto cleanup;
1047     }
1048
1049   ret = 0;
1050
1051 cleanup:
1052   for (i = 0; i < params_size; i++)
1053     {
1054       _gnutls_mpi_release (&params[i]);
1055     }
1056   return ret;
1057 }
1058
1059
1060 /**
1061  * gnutls_openpgp_privkey_export_rsa_raw:
1062  * @pkey: Holds the certificate
1063  * @m: will hold the modulus
1064  * @e: will hold the public exponent
1065  * @d: will hold the private exponent
1066  * @p: will hold the first prime (p)
1067  * @q: will hold the second prime (q)
1068  * @u: will hold the coefficient
1069  *
1070  * This function will export the RSA private key's parameters found in
1071  * the given structure.  The new parameters will be allocated using
1072  * gnutls_malloc() and will be stored in the appropriate datum.
1073  *
1074  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
1075  *
1076  * Since: 2.4.0
1077  **/
1078 int
1079 gnutls_openpgp_privkey_export_rsa_raw (gnutls_openpgp_privkey_t pkey,
1080                                        gnutls_datum_t * m, gnutls_datum_t * e,
1081                                        gnutls_datum_t * d, gnutls_datum_t * p,
1082                                        gnutls_datum_t * q, gnutls_datum_t * u)
1083 {
1084   uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE];
1085   int ret;
1086
1087   ret = gnutls_openpgp_privkey_get_key_id (pkey, keyid);
1088   if (ret < 0)
1089     {
1090       gnutls_assert ();
1091       return ret;
1092     }
1093
1094   return _get_sk_rsa_raw (pkey, keyid, m, e, d, p, q, u);
1095 }
1096
1097 /**
1098  * gnutls_openpgp_privkey_export_dsa_raw:
1099  * @pkey: Holds the certificate
1100  * @p: will hold the p
1101  * @q: will hold the q
1102  * @g: will hold the g
1103  * @y: will hold the y
1104  * @x: will hold the x
1105  *
1106  * This function will export the DSA private key's parameters found in
1107  * the given certificate.  The new parameters will be allocated using
1108  * gnutls_malloc() and will be stored in the appropriate datum.
1109  *
1110  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
1111  *
1112  * Since: 2.4.0
1113  **/
1114 int
1115 gnutls_openpgp_privkey_export_dsa_raw (gnutls_openpgp_privkey_t pkey,
1116                                        gnutls_datum_t * p, gnutls_datum_t * q,
1117                                        gnutls_datum_t * g, gnutls_datum_t * y,
1118                                        gnutls_datum_t * x)
1119 {
1120   uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE];
1121   int ret;
1122
1123   ret = gnutls_openpgp_privkey_get_key_id (pkey, keyid);
1124   if (ret < 0)
1125     {
1126       gnutls_assert ();
1127       return ret;
1128     }
1129
1130   return _get_sk_dsa_raw (pkey, keyid, p, q, g, y, x);
1131 }
1132
1133 /**
1134  * gnutls_openpgp_privkey_export_subkey_rsa_raw:
1135  * @pkey: Holds the certificate
1136  * @idx: Is the subkey index
1137  * @m: will hold the modulus
1138  * @e: will hold the public exponent
1139  * @d: will hold the private exponent
1140  * @p: will hold the first prime (p)
1141  * @q: will hold the second prime (q)
1142  * @u: will hold the coefficient
1143  *
1144  * This function will export the RSA private key's parameters found in
1145  * the given structure.  The new parameters will be allocated using
1146  * gnutls_malloc() and will be stored in the appropriate datum.
1147  *
1148  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
1149  *
1150  * Since: 2.4.0
1151  **/
1152 int
1153 gnutls_openpgp_privkey_export_subkey_rsa_raw (gnutls_openpgp_privkey_t pkey,
1154                                               unsigned int idx,
1155                                               gnutls_datum_t * m,
1156                                               gnutls_datum_t * e,
1157                                               gnutls_datum_t * d,
1158                                               gnutls_datum_t * p,
1159                                               gnutls_datum_t * q,
1160                                               gnutls_datum_t * u)
1161 {
1162   uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE];
1163   int ret;
1164
1165   ret = gnutls_openpgp_privkey_get_subkey_id (pkey, idx, keyid);
1166   if (ret < 0)
1167     {
1168       gnutls_assert ();
1169       return ret;
1170     }
1171
1172   return _get_sk_rsa_raw (pkey, keyid, m, e, d, p, q, u);
1173 }
1174
1175 /**
1176  * gnutls_openpgp_privkey_export_subkey_dsa_raw:
1177  * @pkey: Holds the certificate
1178  * @idx: Is the subkey index
1179  * @p: will hold the p
1180  * @q: will hold the q
1181  * @g: will hold the g
1182  * @y: will hold the y
1183  * @x: will hold the x
1184  *
1185  * This function will export the DSA private key's parameters found
1186  * in the given certificate.  The new parameters will be allocated
1187  * using gnutls_malloc() and will be stored in the appropriate datum.
1188  *
1189  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
1190  *
1191  * Since: 2.4.0
1192  **/
1193 int
1194 gnutls_openpgp_privkey_export_subkey_dsa_raw (gnutls_openpgp_privkey_t pkey,
1195                                               unsigned int idx,
1196                                               gnutls_datum_t * p,
1197                                               gnutls_datum_t * q,
1198                                               gnutls_datum_t * g,
1199                                               gnutls_datum_t * y,
1200                                               gnutls_datum_t * x)
1201 {
1202   uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE];
1203   int ret;
1204
1205   ret = gnutls_openpgp_privkey_get_subkey_id (pkey, idx, keyid);
1206   if (ret < 0)
1207     {
1208       gnutls_assert ();
1209       return ret;
1210     }
1211
1212   return _get_sk_dsa_raw (pkey, keyid, p, q, g, y, x);
1213 }
1214
1215 /**
1216  * gnutls_openpgp_privkey_get_preferred_key_id:
1217  * @key: the structure that contains the OpenPGP public key.
1218  * @keyid: the struct to save the keyid.
1219  *
1220  * Get the preferred key-id for the key.
1221  *
1222  * Returns: the 64-bit preferred keyID of the OpenPGP key, or if it
1223  *   hasn't been set it returns %GNUTLS_E_INVALID_REQUEST.
1224  **/
1225 int
1226 gnutls_openpgp_privkey_get_preferred_key_id (gnutls_openpgp_privkey_t key,
1227                                              gnutls_openpgp_keyid_t keyid)
1228 {
1229   if (!key->preferred_set)
1230     return gnutls_assert_val(GNUTLS_E_OPENPGP_PREFERRED_KEY_ERROR);
1231
1232   if (!key || !keyid)
1233     {
1234       gnutls_assert ();
1235       return GNUTLS_E_INVALID_REQUEST;
1236     }
1237
1238   memcpy (keyid, key->preferred_keyid, GNUTLS_OPENPGP_KEYID_SIZE);
1239
1240   return 0;
1241 }
1242
1243 /**
1244  * gnutls_openpgp_privkey_set_preferred_key_id:
1245  * @key: the structure that contains the OpenPGP public key.
1246  * @keyid: the selected keyid
1247  *
1248  * This allows setting a preferred key id for the given certificate.
1249  * This key will be used by functions that involve key handling.
1250  *
1251  * Returns: On success, 0 is returned, or an error code.
1252  **/
1253 int
1254 gnutls_openpgp_privkey_set_preferred_key_id (gnutls_openpgp_privkey_t key,
1255                                              const gnutls_openpgp_keyid_t
1256                                              keyid)
1257 {
1258   int ret;
1259
1260   if (!key)
1261     {
1262       gnutls_assert ();
1263       return GNUTLS_E_INVALID_REQUEST;
1264     }
1265
1266   /* check if the id is valid */
1267   ret = gnutls_openpgp_privkey_get_subkey_idx (key, keyid);
1268   if (ret < 0)
1269     {
1270       _gnutls_x509_log ("the requested subkey does not exist\n");
1271       gnutls_assert ();
1272       return ret;
1273     }
1274
1275   key->preferred_set = 1;
1276   memcpy (key->preferred_keyid, keyid, GNUTLS_OPENPGP_KEYID_SIZE);
1277
1278   return 0;
1279 }
1280
1281 /**
1282  * gnutls_openpgp_privkey_sign_hash:
1283  * @key: Holds the key
1284  * @hash: holds the data to be signed
1285  * @signature: will contain newly allocated signature
1286  *
1287  * This function will sign the given hash using the private key.  You
1288  * should use gnutls_openpgp_privkey_set_preferred_key_id() before
1289  * calling this function to set the subkey to use.
1290  *
1291  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
1292  *   negative error value.
1293  *
1294  * Deprecated: Use gnutls_privkey_sign_hash() instead.
1295  */
1296 int
1297 gnutls_openpgp_privkey_sign_hash (gnutls_openpgp_privkey_t key,
1298                                    const gnutls_datum_t * hash,
1299                                    gnutls_datum_t * signature)
1300 {
1301   int result, i;
1302   bigint_t params[MAX_PRIV_PARAMS_SIZE];
1303   int params_size = MAX_PRIV_PARAMS_SIZE;
1304   int pk_algorithm;
1305   uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE];
1306
1307   if (key == NULL)
1308     {
1309       gnutls_assert ();
1310       return GNUTLS_E_INVALID_REQUEST;
1311     }
1312
1313   result = gnutls_openpgp_privkey_get_preferred_key_id (key, keyid);
1314   if (result == 0)
1315     {
1316       uint32_t kid[2];
1317       int idx;
1318
1319       KEYID_IMPORT (kid, keyid);
1320
1321       idx = gnutls_openpgp_privkey_get_subkey_idx (key, keyid);
1322       pk_algorithm =
1323         gnutls_openpgp_privkey_get_subkey_pk_algorithm (key, idx, NULL);
1324       result =
1325         _gnutls_openpgp_privkey_get_mpis (key, kid, params, &params_size);
1326     }
1327   else
1328     {
1329       pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm (key, NULL);
1330       result = _gnutls_openpgp_privkey_get_mpis (key, NULL,
1331                                                  params, &params_size);
1332     }
1333
1334   if (result < 0)
1335     {
1336       gnutls_assert ();
1337       return result;
1338     }
1339
1340
1341   result =
1342     _gnutls_soft_sign (pk_algorithm, params, params_size, hash, signature);
1343
1344   for (i = 0; i < params_size; i++)
1345     _gnutls_mpi_release (&params[i]);
1346
1347   if (result < 0)
1348     {
1349       gnutls_assert ();
1350       return result;
1351     }
1352
1353   return 0;
1354 }
1355
1356 /*-
1357  * _gnutls_openpgp_privkey_decrypt_data:
1358  * @key: Holds the key
1359  * @flags: zero for now
1360  * @ciphertext: holds the data to be decrypted
1361  * @plaintext: will contain newly allocated plaintext
1362  *
1363  * This function will sign the given hash using the private key.  You
1364  * should use gnutls_openpgp_privkey_set_preferred_key_id() before
1365  * calling this function to set the subkey to use.
1366  *
1367  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
1368  *   negative error value.
1369  -*/
1370 int
1371 _gnutls_openpgp_privkey_decrypt_data (gnutls_openpgp_privkey_t key,
1372                                      unsigned int flags,
1373                                      const gnutls_datum_t * ciphertext,
1374                                      gnutls_datum_t * plaintext)
1375 {
1376   int result, i;
1377   bigint_t params[MAX_PRIV_PARAMS_SIZE];
1378   int params_size = MAX_PRIV_PARAMS_SIZE;
1379   int pk_algorithm;
1380   uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE];
1381
1382   if (key == NULL)
1383     {
1384       gnutls_assert ();
1385       return GNUTLS_E_INVALID_REQUEST;
1386     }
1387
1388   result = gnutls_openpgp_privkey_get_preferred_key_id (key, keyid);
1389   if (result == 0)
1390     {
1391       uint32_t kid[2];
1392
1393       KEYID_IMPORT (kid, keyid);
1394       result = _gnutls_openpgp_privkey_get_mpis (key, kid,
1395                                                  params, &params_size);
1396
1397       i = gnutls_openpgp_privkey_get_subkey_idx (key, keyid);
1398
1399       pk_algorithm = gnutls_openpgp_privkey_get_subkey_pk_algorithm (key, i, NULL);
1400     }
1401   else
1402     {
1403       pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm (key, NULL);
1404
1405       result = _gnutls_openpgp_privkey_get_mpis (key, NULL,
1406                                                  params, &params_size);
1407
1408     }
1409
1410   if (result < 0)
1411     {
1412       gnutls_assert ();
1413       return result;
1414     }
1415
1416   if (pk_algorithm != GNUTLS_PK_RSA)
1417     {
1418       gnutls_assert ();
1419       return GNUTLS_E_INVALID_REQUEST;
1420     }
1421
1422   result =
1423     _gnutls_pkcs1_rsa_decrypt (plaintext, ciphertext, params, params_size, 2);
1424
1425   for (i = 0; i < params_size; i++)
1426     _gnutls_mpi_release (&params[i]);
1427
1428   if (result < 0)
1429     {
1430       gnutls_assert ();
1431       return result;
1432     }
1433
1434   return 0;
1435 }