Tizen 2.0 Release
[external/libgnutls26.git] / lib / openpgp / gnutls_openpgp.c
1 /*
2  * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
3  * Free Software Foundation, Inc.
4  *
5  * Author: Timo Schulz, Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * The GnuTLS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA
23  *
24  */
25
26 #include "gnutls_int.h"
27 #include "gnutls_errors.h"
28 #include "gnutls_mpi.h"
29 #include "gnutls_num.h"
30 #include "gnutls_cert.h"
31 #include "gnutls_datum.h"
32 #include "gnutls_global.h"
33 #include "gnutls_openpgp.h"
34 #include "read-file.h"
35 #include <gnutls_str.h>
36 #include <gnutls_sig.h>
37 #include <stdio.h>
38 #include <sys/stat.h>
39
40 #define datum_append(x, y, z) _gnutls_datum_append_m (x, y, z, gnutls_realloc)
41
42 /* Map an OpenCDK error type to a GnuTLS error type. */
43 int
44 _gnutls_map_cdk_rc (int rc)
45 {
46   switch (rc)
47     {
48     case CDK_Success:
49       return 0;
50     case CDK_Too_Short:
51       return GNUTLS_E_SHORT_MEMORY_BUFFER;
52     case CDK_General_Error:
53       return GNUTLS_E_INTERNAL_ERROR;
54     case CDK_File_Error:
55       return GNUTLS_E_FILE_ERROR;
56     case CDK_MPI_Error:
57       return GNUTLS_E_MPI_SCAN_FAILED;
58     case CDK_Error_No_Key:
59       return GNUTLS_E_OPENPGP_GETKEY_FAILED;
60     case CDK_Armor_Error:
61       return GNUTLS_E_BASE64_DECODING_ERROR;
62     case CDK_Inv_Value:
63       return GNUTLS_E_INVALID_REQUEST;
64     default:
65       return GNUTLS_E_INTERNAL_ERROR;
66     }
67 }
68
69 /*-
70  * _gnutls_openpgp_raw_crt_to_gcert - Converts raw OpenPGP data to GnuTLS certs
71  * @cert: the certificate to store the data.
72  * @raw: the buffer which contains the whole OpenPGP key packets.
73  *
74  * The RFC2440 (OpenPGP Message Format) data is converted to a GnuTLS
75  * specific certificate.
76  -*/
77 int
78 _gnutls_openpgp_raw_crt_to_gcert (gnutls_cert * gcert,
79                                   const gnutls_datum_t * raw,
80                                   const gnutls_openpgp_keyid_t keyid)
81 {
82   gnutls_openpgp_crt_t pcrt;
83   int ret;
84
85   ret = gnutls_openpgp_crt_init (&pcrt);
86   if (ret < 0)
87     {
88       gnutls_assert ();
89       return ret;
90     }
91
92   ret = gnutls_openpgp_crt_import (pcrt, raw, GNUTLS_OPENPGP_FMT_RAW);
93   if (ret < 0)
94     {
95       gnutls_assert ();
96       gnutls_openpgp_crt_deinit (pcrt);
97       return ret;
98     }
99
100   if (keyid != NULL)
101     {
102       ret = gnutls_openpgp_crt_set_preferred_key_id (pcrt, keyid);
103       if (ret < 0)
104         {
105           gnutls_assert ();
106           gnutls_openpgp_crt_deinit (pcrt);
107           return ret;
108         }
109     }
110
111   ret = _gnutls_openpgp_crt_to_gcert (gcert, pcrt);
112   gnutls_openpgp_crt_deinit (pcrt);
113
114   return ret;
115 }
116
117 /**
118  * gnutls_certificate_set_openpgp_key:
119  * @res: is a #gnutls_certificate_credentials_t structure.
120  * @key: contains an openpgp public key
121  * @pkey: is an openpgp private key
122  *
123  * This function sets a certificate/private key pair in the
124  * gnutls_certificate_credentials_t structure.  This function may be
125  * called more than once (in case multiple keys/certificates exist
126  * for the server).
127  *
128  * Note that this function requires that the preferred key ids have
129  * been set and be used. See gnutls_openpgp_crt_set_preferred_key_id().
130  * Otherwise the master key will be used.
131  *
132  * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
133  *   otherwise an error code is returned.
134  **/
135 int
136 gnutls_certificate_set_openpgp_key (gnutls_certificate_credentials_t res,
137                                     gnutls_openpgp_crt_t crt,
138                                     gnutls_openpgp_privkey_t pkey)
139 {
140   int ret;
141   gnutls_privkey_t privkey;
142   gnutls_cert *ccert;
143
144   /* this should be first */
145
146   ret = gnutls_privkey_init (&privkey);
147   if (ret < 0)
148     {
149       gnutls_assert ();
150       return ret;
151     }
152   
153   ret =
154     gnutls_privkey_import_openpgp (privkey, pkey,
155                                    GNUTLS_PRIVKEY_IMPORT_COPY);
156   if (ret < 0)
157     {
158       gnutls_privkey_deinit (privkey);
159       gnutls_assert ();
160       return ret;
161     }
162
163
164   ccert = gnutls_calloc (1, sizeof (gnutls_cert));
165   if (ccert == NULL)
166     {
167       gnutls_assert ();
168       gnutls_privkey_deinit (privkey);
169       return GNUTLS_E_MEMORY_ERROR;
170     }
171
172   ret = _gnutls_openpgp_crt_to_gcert (ccert, crt);
173   if (ret < 0)
174     {
175       gnutls_assert ();
176       gnutls_free (ccert);
177       gnutls_privkey_deinit (privkey);
178       return ret;
179     }
180
181   ret = certificate_credentials_append_pkey (res, privkey);
182   if (ret >= 0)
183     ret = certificate_credential_append_crt_list (res, ccert, 1);
184
185   if (ret < 0)
186     {
187       gnutls_assert ();
188       gnutls_free (ccert);
189       gnutls_privkey_deinit (privkey);
190       return ret;
191     }
192
193   res->ncerts++;
194
195   /* FIXME: Check if the keys match. */
196
197   return 0;
198 }
199
200 /*-
201  * gnutls_openpgp_get_key:
202  * @key: the destination context to save the key.
203  * @keyring: the datum struct that contains all keyring information.
204  * @attr: The attribute (keyid, fingerprint, ...).
205  * @by: What attribute is used.
206  *
207  * This function can be used to retrieve keys by different pattern
208  * from a binary or a file keyring.
209  -*/
210 int
211 gnutls_openpgp_get_key (gnutls_datum_t * key,
212                         gnutls_openpgp_keyring_t keyring, key_attr_t by,
213                         opaque * pattern)
214 {
215   cdk_kbnode_t knode = NULL;
216   unsigned long keyid[2];
217   unsigned char *buf;
218   void *desc;
219   size_t len;
220   int rc = 0;
221   cdk_keydb_search_t st;
222
223   if (!key || !keyring || by == KEY_ATTR_NONE)
224     {
225       gnutls_assert ();
226       return GNUTLS_E_INVALID_REQUEST;
227     }
228
229   memset (key, 0, sizeof *key);
230
231   if (by == KEY_ATTR_SHORT_KEYID)
232     {
233       keyid[0] = _gnutls_read_uint32 (pattern);
234       desc = keyid;
235     }
236   else if (by == KEY_ATTR_KEYID)
237     {
238       keyid[0] = _gnutls_read_uint32 (pattern);
239       keyid[1] = _gnutls_read_uint32 (pattern + 4);
240       desc = keyid;
241     }
242   else
243     desc = pattern;
244   rc = cdk_keydb_search_start (&st, keyring->db, by, desc);
245   if (!rc)
246     rc = cdk_keydb_search (st, keyring->db, &knode);
247
248   cdk_keydb_search_release (st);
249
250   if (rc)
251     {
252       rc = _gnutls_map_cdk_rc (rc);
253       goto leave;
254     }
255
256   if (!cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY))
257     {
258       rc = GNUTLS_E_OPENPGP_GETKEY_FAILED;
259       goto leave;
260     }
261
262   /* We let the function allocate the buffer to avoid
263      to call the function twice. */
264   rc = cdk_kbnode_write_to_mem_alloc (knode, &buf, &len);
265   if (!rc)
266     datum_append (key, buf, len);
267   gnutls_free (buf);
268
269 leave:
270   cdk_kbnode_release (knode);
271   return rc;
272 }
273
274 /**
275  * gnutls_certificate_set_openpgp_key_mem:
276  * @res: the destination context to save the data.
277  * @cert: the datum that contains the public key.
278  * @key: the datum that contains the secret key.
279  * @format: the format of the keys
280  *
281  * This funtion is used to load OpenPGP keys into the GnuTLS credential 
282  * structure. The datum should contain at least one valid non encrypted subkey.
283  *
284  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
285  *   negative error value.
286  **/
287 int
288 gnutls_certificate_set_openpgp_key_mem (gnutls_certificate_credentials_t res,
289                                         const gnutls_datum_t * cert,
290                                         const gnutls_datum_t * key,
291                                         gnutls_openpgp_crt_fmt_t format)
292 {
293   return gnutls_certificate_set_openpgp_key_mem2 (res, cert, key,
294                                                   NULL, format);
295 }
296
297 /**
298  * gnutls_certificate_set_openpgp_key_file:
299  * @res: the destination context to save the data.
300  * @certfile: the file that contains the public key.
301  * @keyfile: the file that contains the secret key.
302  * @format: the format of the keys
303  *
304  * This funtion is used to load OpenPGP keys into the GnuTLS
305  * credentials structure. The file should contain at least one valid non encrypted subkey.
306  *
307  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
308  *   negative error value.
309  **/
310 int
311 gnutls_certificate_set_openpgp_key_file (gnutls_certificate_credentials_t res,
312                                          const char *certfile,
313                                          const char *keyfile,
314                                          gnutls_openpgp_crt_fmt_t format)
315 {
316   return gnutls_certificate_set_openpgp_key_file2 (res, certfile,
317                                                    keyfile, NULL, format);
318 }
319
320 static int
321 get_keyid (gnutls_openpgp_keyid_t keyid, const char *str)
322 {
323   size_t keyid_size = GNUTLS_OPENPGP_KEYID_SIZE;
324
325   if (strlen (str) != 16)
326     {
327       _gnutls_debug_log
328         ("The OpenPGP subkey ID has to be 16 hexadecimal characters.\n");
329       return GNUTLS_E_INVALID_REQUEST;
330     }
331
332   if (_gnutls_hex2bin (str, strlen (str), keyid, &keyid_size) < 0)
333     {
334       _gnutls_debug_log ("Error converting hex string: %s.\n", str);
335       return GNUTLS_E_INVALID_REQUEST;
336     }
337
338   return 0;
339 }
340
341 /**
342  * gnutls_certificate_set_openpgp_key_mem2:
343  * @res: the destination context to save the data.
344  * @cert: the datum that contains the public key.
345  * @key: the datum that contains the secret key.
346  * @subkey_id: a hex encoded subkey id
347  * @format: the format of the keys
348  *
349  * This funtion is used to load OpenPGP keys into the GnuTLS
350  * credentials structure. The datum should contain at least one valid non encrypted subkey.
351  *
352  * The special keyword "auto" is also accepted as @subkey_id.  In that
353  * case the gnutls_openpgp_crt_get_auth_subkey() will be used to
354  * retrieve the subkey.
355  *
356  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
357  *   negative error value.
358  *
359  * Since: 2.4.0
360  **/
361 int
362 gnutls_certificate_set_openpgp_key_mem2 (gnutls_certificate_credentials_t res,
363                                          const gnutls_datum_t * cert,
364                                          const gnutls_datum_t * key,
365                                          const char *subkey_id,
366                                          gnutls_openpgp_crt_fmt_t format)
367 {
368   gnutls_openpgp_privkey_t pkey;
369   gnutls_openpgp_crt_t crt;
370   int ret;
371   uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE];
372
373   ret = gnutls_openpgp_privkey_init (&pkey);
374   if (ret < 0)
375     {
376       gnutls_assert ();
377       return ret;
378     }
379
380   ret = gnutls_openpgp_privkey_import (pkey, key, format, NULL, 0);
381   if (ret < 0)
382     {
383       gnutls_assert ();
384       gnutls_openpgp_privkey_deinit (pkey);
385       return ret;
386     }
387
388   ret = gnutls_openpgp_crt_init (&crt);
389   if (ret < 0)
390     {
391       gnutls_assert ();
392       gnutls_openpgp_privkey_deinit (pkey);
393       return ret;
394     }
395
396   ret = gnutls_openpgp_crt_import (crt, cert, format);
397   if (ret < 0)
398     {
399       gnutls_assert ();
400       gnutls_openpgp_privkey_deinit (pkey);
401       gnutls_openpgp_crt_deinit (crt);
402       return ret;
403     }
404
405   if (subkey_id != NULL)
406     {
407       if (strcasecmp (subkey_id, "auto") == 0)
408         ret = gnutls_openpgp_crt_get_auth_subkey (crt, keyid, 1);
409       else
410         ret = get_keyid (keyid, subkey_id);
411
412       if (ret < 0)
413         gnutls_assert ();
414
415       if (ret >= 0)
416         {
417           ret = gnutls_openpgp_crt_set_preferred_key_id (crt, keyid);
418           if (ret >= 0)
419             ret = gnutls_openpgp_privkey_set_preferred_key_id (pkey, keyid);
420         }
421
422       if (ret < 0)
423         {
424           gnutls_assert ();
425           gnutls_openpgp_privkey_deinit (pkey);
426           gnutls_openpgp_crt_deinit (crt);
427           return ret;
428         }
429     }
430
431   ret = gnutls_certificate_set_openpgp_key (res, crt, pkey);
432
433   gnutls_openpgp_crt_deinit (crt);
434   gnutls_openpgp_privkey_deinit (pkey);
435
436   return ret;
437 }
438
439 /**
440  * gnutls_certificate_set_openpgp_key_file2:
441  * @res: the destination context to save the data.
442  * @certfile: the file that contains the public key.
443  * @keyfile: the file that contains the secret key.
444  * @subkey_id: a hex encoded subkey id
445  * @format: the format of the keys
446  *
447  * This funtion is used to load OpenPGP keys into the GnuTLS credential 
448  * structure. The file should contain at least one valid non encrypted subkey.
449  *
450  * The special keyword "auto" is also accepted as @subkey_id.  In that
451  * case the gnutls_openpgp_crt_get_auth_subkey() will be used to
452  * retrieve the subkey.
453  *
454  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
455  *   negative error value.
456  *
457  * Since: 2.4.0
458  **/
459 int
460 gnutls_certificate_set_openpgp_key_file2 (gnutls_certificate_credentials_t
461                                           res, const char *certfile,
462                                           const char *keyfile,
463                                           const char *subkey_id,
464                                           gnutls_openpgp_crt_fmt_t format)
465 {
466   struct stat statbuf;
467   gnutls_datum_t key, cert;
468   int rc;
469   size_t size;
470
471   if (!res || !keyfile || !certfile)
472     {
473       gnutls_assert ();
474       return GNUTLS_E_INVALID_REQUEST;
475     }
476
477   if (stat (certfile, &statbuf) || stat (keyfile, &statbuf))
478     {
479       gnutls_assert ();
480       return GNUTLS_E_FILE_ERROR;
481     }
482
483   cert.data = read_binary_file (certfile, &size);
484   cert.size = (unsigned int) size;
485   if (cert.data == NULL)
486     {
487       gnutls_assert ();
488       return GNUTLS_E_FILE_ERROR;
489     }
490
491   key.data = read_binary_file (keyfile, &size);
492   key.size = (unsigned int) size;
493   if (key.data == NULL)
494     {
495       gnutls_assert ();
496       free (cert.data);
497       return GNUTLS_E_FILE_ERROR;
498     }
499
500   rc =
501     gnutls_certificate_set_openpgp_key_mem2 (res, &cert, &key, subkey_id,
502                                              format);
503
504   free (cert.data);
505   free (key.data);
506
507   if (rc < 0)
508     {
509       gnutls_assert ();
510       return rc;
511     }
512
513   return 0;
514 }
515
516
517 int
518 gnutls_openpgp_count_key_names (const gnutls_datum_t * cert)
519 {
520   cdk_kbnode_t knode, p, ctx;
521   cdk_packet_t pkt;
522   int nuids;
523
524   if (cert == NULL)
525     {
526       gnutls_assert ();
527       return 0;
528     }
529
530   if (cdk_kbnode_read_from_mem (&knode, cert->data, cert->size))
531     {
532       gnutls_assert ();
533       return 0;
534     }
535
536   ctx = NULL;
537   for (nuids = 0;;)
538     {
539       p = cdk_kbnode_walk (knode, &ctx, 0);
540       if (!p)
541         break;
542       pkt = cdk_kbnode_get_packet (p);
543       if (pkt->pkttype == CDK_PKT_USER_ID)
544         nuids++;
545     }
546
547   cdk_kbnode_release (knode);
548   return nuids;
549 }
550
551 /**
552  * gnutls_certificate_set_openpgp_keyring_file:
553  * @c: A certificate credentials structure
554  * @file: filename of the keyring.
555  * @format: format of keyring.
556  *
557  * The function is used to set keyrings that will be used internally
558  * by various OpenPGP functions. For example to find a key when it
559  * is needed for an operations. The keyring will also be used at the
560  * verification functions.
561  *
562  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
563  *   negative error value.
564  **/
565 int
566 gnutls_certificate_set_openpgp_keyring_file (gnutls_certificate_credentials_t
567                                              c, const char *file,
568                                              gnutls_openpgp_crt_fmt_t format)
569 {
570   gnutls_datum_t ring;
571   size_t size;
572   int rc;
573
574   if (!c || !file)
575     {
576       gnutls_assert ();
577       return GNUTLS_E_INVALID_REQUEST;
578     }
579
580   ring.data = read_binary_file (file, &size);
581   ring.size = (unsigned int) size;
582   if (ring.data == NULL)
583     {
584       gnutls_assert ();
585       return GNUTLS_E_FILE_ERROR;
586     }
587
588   rc =
589     gnutls_certificate_set_openpgp_keyring_mem (c, ring.data, ring.size,
590                                                 format);
591
592   free (ring.data);
593
594   return rc;
595 }
596
597 /**
598  * gnutls_certificate_set_openpgp_keyring_mem:
599  * @c: A certificate credentials structure
600  * @data: buffer with keyring data.
601  * @dlen: length of data buffer.
602  * @format: the format of the keyring
603  *
604  * The function is used to set keyrings that will be used internally
605  * by various OpenPGP functions. For example to find a key when it
606  * is needed for an operations. The keyring will also be used at the
607  * verification functions.
608  *
609  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
610  *   negative error value.
611  **/
612 int
613 gnutls_certificate_set_openpgp_keyring_mem (gnutls_certificate_credentials_t
614                                             c, const opaque * data,
615                                             size_t dlen,
616                                             gnutls_openpgp_crt_fmt_t format)
617 {
618   gnutls_datum_t ddata;
619   int rc;
620
621   ddata.data = (void *) data;
622   ddata.size = dlen;
623
624   if (!c || !data || !dlen)
625     {
626       gnutls_assert ();
627       return GNUTLS_E_INVALID_REQUEST;
628     }
629
630   rc = gnutls_openpgp_keyring_init (&c->keyring);
631   if (rc < 0)
632     {
633       gnutls_assert ();
634       return rc;
635     }
636
637   rc = gnutls_openpgp_keyring_import (c->keyring, &ddata, format);
638   if (rc < 0)
639     {
640       gnutls_assert ();
641       gnutls_openpgp_keyring_deinit (c->keyring);
642       return rc;
643     }
644
645   return 0;
646 }
647
648 /*-
649  * _gnutls_openpgp_request_key - Receives a key from a database, key server etc
650  * @ret - a pointer to gnutls_datum_t structure.
651  * @cred - a gnutls_certificate_credentials_t structure.
652  * @key_fingerprint - The keyFingerprint
653  * @key_fingerprint_size - the size of the fingerprint
654  *
655  * Retrieves a key from a local database, keyring, or a key server. The
656  * return value is locally allocated.
657  *
658  -*/
659 int
660 _gnutls_openpgp_request_key (gnutls_session_t session, gnutls_datum_t * ret,
661                              const gnutls_certificate_credentials_t cred,
662                              opaque * key_fpr, int key_fpr_size)
663 {
664   int rc = 0;
665
666   if (!ret || !cred || !key_fpr)
667     {
668       gnutls_assert ();
669       return GNUTLS_E_INVALID_REQUEST;
670     }
671
672   if (key_fpr_size != 16 && key_fpr_size != 20)
673     return GNUTLS_E_HASH_FAILED;        /* only MD5 and SHA1 are supported */
674
675   rc = gnutls_openpgp_get_key (ret, cred->keyring, KEY_ATTR_FPR, key_fpr);
676
677   if (rc >= 0)                  /* key was found */
678     {
679       rc = 0;
680       goto error;
681     }
682   else
683     rc = GNUTLS_E_OPENPGP_GETKEY_FAILED;
684
685   /* If the callback function was set, then try this one. */
686   if (session->internals.openpgp_recv_key_func != NULL)
687     {
688       rc = session->internals.openpgp_recv_key_func (session,
689                                                      key_fpr,
690                                                      key_fpr_size, ret);
691       if (rc < 0)
692         {
693           gnutls_assert ();
694           rc = GNUTLS_E_OPENPGP_GETKEY_FAILED;
695           goto error;
696         }
697     }
698
699 error:
700
701   return rc;
702 }
703
704 /**
705  * gnutls_openpgp_set_recv_key_function:
706  * @session: a TLS session
707  * @func: the callback
708  *
709  * This funtion will set a key retrieval function for OpenPGP keys. This
710  * callback is only useful in server side, and will be used if the peer
711  * sent a key fingerprint instead of a full key.
712  *
713  **/
714 void
715 gnutls_openpgp_set_recv_key_function (gnutls_session_t session,
716                                       gnutls_openpgp_recv_key_func func)
717 {
718   session->internals.openpgp_recv_key_func = func;
719 }
720
721
722 /* Converts a parsed gnutls_openpgp_crt_t to a gnutls_cert structure.
723  */
724 int
725 _gnutls_openpgp_crt_to_gcert (gnutls_cert * gcert, gnutls_openpgp_crt_t cert)
726 {
727   int ret;
728   uint8_t keyid[GNUTLS_OPENPGP_KEYID_SIZE];
729   char err_buf[33];
730
731   memset (gcert, 0, sizeof (gnutls_cert));
732   gcert->cert_type = GNUTLS_CRT_OPENPGP;
733   gcert->sign_algo = GNUTLS_SIGN_UNKNOWN;       /* N/A here */
734
735   gcert->version = gnutls_openpgp_crt_get_version (cert);
736   gcert->params_size = MAX_PUBLIC_PARAMS_SIZE;
737
738   ret = gnutls_openpgp_crt_get_preferred_key_id (cert, keyid);
739
740   if (ret == 0)
741     {
742       int idx;
743       uint32_t kid32[2];
744
745       _gnutls_debug_log
746         ("Importing Openpgp cert and using openpgp sub key: %s\n",
747          _gnutls_bin2hex (keyid, GNUTLS_OPENPGP_KEYID_SIZE, err_buf, sizeof (err_buf),
748                           NULL));
749
750       KEYID_IMPORT (kid32, keyid);
751
752       idx = gnutls_openpgp_crt_get_subkey_idx (cert, keyid);
753       if (idx < 0)
754         {
755           gnutls_assert ();
756           return idx;
757         }
758
759       gcert->subject_pk_algorithm =
760         gnutls_openpgp_crt_get_subkey_pk_algorithm (cert, idx, NULL);
761
762       gnutls_openpgp_crt_get_subkey_usage (cert, idx, &gcert->key_usage);
763       gcert->use_subkey = 1;
764
765       memcpy (gcert->subkey_id, keyid, GNUTLS_OPENPGP_KEYID_SIZE);
766
767       ret =
768         _gnutls_openpgp_crt_get_mpis (cert, kid32, gcert->params,
769                                       &gcert->params_size);
770     }
771   else
772     {
773       _gnutls_debug_log
774         ("Importing Openpgp cert and using main openpgp key\n");
775       gcert->subject_pk_algorithm =
776         gnutls_openpgp_crt_get_pk_algorithm (cert, NULL);
777
778       gnutls_openpgp_crt_get_key_usage (cert, &gcert->key_usage);
779       ret =
780         _gnutls_openpgp_crt_get_mpis (cert, NULL, gcert->params,
781                                       &gcert->params_size);
782       gcert->use_subkey = 0;
783     }
784
785   if (ret < 0)
786     {
787       gnutls_assert ();
788       return ret;
789     }
790
791   {                             /* copy the raw certificate */
792 #define SMALL_RAW 512
793     opaque *raw;
794     size_t raw_size = SMALL_RAW;
795
796     /* initially allocate a bogus size, just in case the certificate
797      * fits in it. That way we minimize the DER encodings performed.
798      */
799     raw = gnutls_malloc (raw_size);
800     if (raw == NULL)
801       {
802         gnutls_assert ();
803         return GNUTLS_E_MEMORY_ERROR;
804       }
805
806     ret =
807       gnutls_openpgp_crt_export (cert, GNUTLS_OPENPGP_FMT_RAW, raw,
808                                  &raw_size);
809     if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
810       {
811         gnutls_assert ();
812         gnutls_free (raw);
813         return ret;
814       }
815
816     if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
817       {
818         raw = gnutls_realloc (raw, raw_size);
819         if (raw == NULL)
820           {
821             gnutls_assert ();
822             return GNUTLS_E_MEMORY_ERROR;
823           }
824
825         ret =
826           gnutls_openpgp_crt_export (cert, GNUTLS_OPENPGP_FMT_RAW, raw,
827                                      &raw_size);
828         if (ret < 0)
829           {
830             gnutls_assert ();
831             gnutls_free (raw);
832             return ret;
833           }
834       }
835
836     gcert->raw.data = raw;
837     gcert->raw.size = raw_size;
838   }
839
840   return 0;
841
842 }