gpg: Use only OpenPGP public key algo ids and add the EdDSA algo id.
[gnupg.git] / g10 / export.c
1 /* export.c - Export keys in the OpenPGP defined format.
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
3  *               2005, 2010 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27
28 #include "gpg.h"
29 #include "options.h"
30 #include "packet.h"
31 #include "status.h"
32 #include "keydb.h"
33 #include "util.h"
34 #include "main.h"
35 #include "i18n.h"
36 #include "trustdb.h"
37 #include "call-agent.h"
38
39 /* An object to keep track of subkeys. */
40 struct subkey_list_s
41 {
42   struct subkey_list_s *next;
43   u32 kid[2];
44 };
45 typedef struct subkey_list_s *subkey_list_t;
46
47
48 static int do_export (ctrl_t ctrl,
49                       strlist_t users, int secret, unsigned int options );
50 static int do_export_stream (ctrl_t ctrl, iobuf_t out,
51                              strlist_t users, int secret,
52                              kbnode_t *keyblock_out, unsigned int options,
53                              int *any);
54 static int build_sexp (iobuf_t out, PACKET *pkt, int *indent);
55
56
57 int
58 parse_export_options(char *str,unsigned int *options,int noisy)
59 {
60   struct parse_options export_opts[]=
61     {
62       {"export-local-sigs",EXPORT_LOCAL_SIGS,NULL,
63        N_("export signatures that are marked as local-only")},
64       {"export-attributes",EXPORT_ATTRIBUTES,NULL,
65        N_("export attribute user IDs (generally photo IDs)")},
66       {"export-sensitive-revkeys",EXPORT_SENSITIVE_REVKEYS,NULL,
67        N_("export revocation keys marked as \"sensitive\"")},
68       {"export-clean",EXPORT_CLEAN,NULL,
69        N_("remove unusable parts from key during export")},
70       {"export-minimal",EXPORT_MINIMAL|EXPORT_CLEAN,NULL,
71        N_("remove as much as possible from key during export")},
72       {"export-sexp-format",EXPORT_SEXP_FORMAT, NULL,
73        N_("export keys in an S-expression based format")},
74       /* Aliases for backward compatibility */
75       {"include-local-sigs",EXPORT_LOCAL_SIGS,NULL,NULL},
76       {"include-attributes",EXPORT_ATTRIBUTES,NULL,NULL},
77       {"include-sensitive-revkeys",EXPORT_SENSITIVE_REVKEYS,NULL,NULL},
78       /* dummy */
79       {"export-unusable-sigs",0,NULL,NULL},
80       {"export-clean-sigs",0,NULL,NULL},
81       {"export-clean-uids",0,NULL,NULL},
82       {NULL,0,NULL,NULL}
83       /* add tags for include revoked and disabled? */
84     };
85
86   return parse_options(str,options,export_opts,noisy);
87 }
88
89
90 /****************
91  * Export the public keys (to standard out or --output).
92  * Depending on opt.armor the output is armored.
93  * options are defined in main.h.
94  * If USERS is NULL, the complete ring will be exported.  */
95 int
96 export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options )
97 {
98   return do_export (ctrl, users, 0, options );
99 }
100
101 /****************
102  * Export to an already opened stream; return -1 if no keys have
103  * been exported
104  */
105 int
106 export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users,
107                        kbnode_t *keyblock_out, unsigned int options )
108 {
109   int any, rc;
110
111   rc = do_export_stream (ctrl, out, users, 0, keyblock_out, options, &any);
112   if (!rc && !any)
113     rc = -1;
114   return rc;
115 }
116
117
118 /*
119  * Export a single key into a memory buffer.
120  */
121 gpg_error_t
122 export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
123                       kbnode_t *r_keyblock, void **r_data, size_t *r_datalen)
124 {
125   gpg_error_t err;
126   iobuf_t iobuf;
127   int any;
128   strlist_t helplist;
129
130   *r_keyblock = NULL;
131   *r_data = NULL;
132   *r_datalen = 0;
133
134   helplist = NULL;
135   if (!add_to_strlist_try (&helplist, keyspec))
136     return gpg_error_from_syserror ();
137
138   iobuf = iobuf_temp ();
139   err = do_export_stream (ctrl, iobuf, helplist, 0, r_keyblock, options, &any);
140   if (!err && !any)
141     err = gpg_error (GPG_ERR_NOT_FOUND);
142   if (!err)
143     {
144       const void *src;
145       size_t datalen;
146
147       iobuf_flush_temp (iobuf);
148       src = iobuf_get_temp_buffer (iobuf);
149       datalen = iobuf_get_temp_length (iobuf);
150       if (!datalen)
151         err = gpg_error (GPG_ERR_NO_PUBKEY);
152       else if (!(*r_data = xtrymalloc (datalen)))
153         err = gpg_error_from_syserror ();
154       else
155         {
156           memcpy (*r_data, src, datalen);
157           *r_datalen = datalen;
158         }
159     }
160   iobuf_close (iobuf);
161   free_strlist (helplist);
162   if (err && *r_keyblock)
163     {
164       release_kbnode (*r_keyblock);
165       *r_keyblock = NULL;
166     }
167   return err;
168 }
169
170
171 int
172 export_seckeys (ctrl_t ctrl, strlist_t users )
173 {
174   /* Use only relevant options for the secret key. */
175   unsigned int options = (opt.export_options & EXPORT_SEXP_FORMAT);
176   return do_export (ctrl, users, 1, options);
177 }
178
179 int
180 export_secsubkeys (ctrl_t ctrl, strlist_t users )
181 {
182   /* Use only relevant options for the secret key. */
183   unsigned int options = (opt.export_options & EXPORT_SEXP_FORMAT);
184   return do_export (ctrl, users, 2, options);
185 }
186
187
188 /* Export the keys identified by the list of strings in USERS.  If
189    Secret is false public keys will be exported.  With secret true
190    secret keys will be exported; in this case 1 means the entire
191    secret keyblock and 2 only the subkeys.  OPTIONS are the export
192    options to apply.  */
193 static int
194 do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options )
195 {
196   IOBUF out = NULL;
197   int any, rc;
198   armor_filter_context_t *afx = NULL;
199   compress_filter_context_t zfx;
200
201   memset( &zfx, 0, sizeof zfx);
202
203   rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, &out );
204   if (rc)
205     return rc;
206
207   if (!(options & EXPORT_SEXP_FORMAT))
208     {
209       if ( opt.armor )
210         {
211           afx = new_armor_context ();
212           afx->what = secret? 5 : 1;
213           push_armor_filter (afx, out);
214         }
215       if ( opt.compress_keys )
216         push_compress_filter (out,&zfx,default_compress_algo());
217     }
218
219   rc = do_export_stream (ctrl, out, users, secret, NULL, options, &any );
220
221   if ( rc || !any )
222     iobuf_cancel (out);
223   else
224     iobuf_close (out);
225   release_armor_context (afx);
226   return rc;
227 }
228
229
230
231 /* Release an entire subkey list. */
232 static void
233 release_subkey_list (subkey_list_t list)
234 {
235   while (list)
236     {
237       subkey_list_t tmp = list->next;;
238       xfree (list);
239       list = tmp;
240     }
241 }
242
243
244 /* Returns true if NODE is a subkey and contained in LIST. */
245 static int
246 subkey_in_list_p (subkey_list_t list, KBNODE node)
247 {
248   if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
249       || node->pkt->pkttype == PKT_SECRET_SUBKEY )
250     {
251       u32 kid[2];
252
253       keyid_from_pk (node->pkt->pkt.public_key, kid);
254
255       for (; list; list = list->next)
256         if (list->kid[0] == kid[0] && list->kid[1] == kid[1])
257           return 1;
258     }
259   return 0;
260 }
261
262 /* Allocate a new subkey list item from NODE. */
263 static subkey_list_t
264 new_subkey_list_item (KBNODE node)
265 {
266   subkey_list_t list = xcalloc (1, sizeof *list);
267
268   if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
269       || node->pkt->pkttype == PKT_SECRET_SUBKEY)
270     keyid_from_pk (node->pkt->pkt.public_key, list->kid);
271
272   return list;
273 }
274
275
276 /* Helper function to check whether the subkey at NODE actually
277    matches the description at DESC.  The function returns true if the
278    key under question has been specified by an exact specification
279    (keyID or fingerprint) and does match the one at NODE.  It is
280    assumed that the packet at NODE is either a public or secret
281    subkey. */
282 static int
283 exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node)
284 {
285   u32 kid[2];
286   byte fpr[MAX_FINGERPRINT_LEN];
287   size_t fprlen;
288   int result = 0;
289
290   switch(desc->mode)
291     {
292     case KEYDB_SEARCH_MODE_SHORT_KID:
293     case KEYDB_SEARCH_MODE_LONG_KID:
294       keyid_from_pk (node->pkt->pkt.public_key, kid);
295       break;
296
297     case KEYDB_SEARCH_MODE_FPR16:
298     case KEYDB_SEARCH_MODE_FPR20:
299     case KEYDB_SEARCH_MODE_FPR:
300       fingerprint_from_pk (node->pkt->pkt.public_key, fpr,&fprlen);
301       break;
302
303     default:
304       break;
305     }
306
307   switch(desc->mode)
308     {
309     case KEYDB_SEARCH_MODE_SHORT_KID:
310       if (desc->u.kid[1] == kid[1])
311         result = 1;
312       break;
313
314     case KEYDB_SEARCH_MODE_LONG_KID:
315       if (desc->u.kid[0] == kid[0] && desc->u.kid[1] == kid[1])
316         result = 1;
317       break;
318
319     case KEYDB_SEARCH_MODE_FPR16:
320       if (!memcmp (desc->u.fpr, fpr, 16))
321         result = 1;
322       break;
323
324     case KEYDB_SEARCH_MODE_FPR20:
325     case KEYDB_SEARCH_MODE_FPR:
326       if (!memcmp (desc->u.fpr, fpr, 20))
327         result = 1;
328       break;
329
330     default:
331       break;
332     }
333
334   return result;
335 }
336
337
338 /* Return a canonicalized public key algoithms.  This is used to
339    compare different flavors of algorithms (e.g. ELG and ELG_E are
340    considered the same).  */
341 static int
342 canon_pubkey_algo (int algo)
343 {
344   switch (algo)
345     {
346     case GCRY_PK_RSA:
347     case GCRY_PK_RSA_E:
348     case GCRY_PK_RSA_S: return GCRY_PK_RSA;
349     case GCRY_PK_ELG:
350     case GCRY_PK_ELG_E: return GCRY_PK_ELG;
351     default: return algo;
352     }
353 }
354
355
356 /* Use the key transfer format given in S_PGP to create the secinfo
357    structure in PK and change the parameter array in PK to include the
358    secret parameters.  */
359 static gpg_error_t
360 transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
361 {
362   gpg_error_t err;
363   gcry_sexp_t top_list;
364   gcry_sexp_t list = NULL;
365   const char *value;
366   size_t valuelen;
367   char *string;
368   int  idx;
369   int  is_v4, is_protected;
370   int  pubkey_algo;
371   int  protect_algo = 0;
372   char iv[16];
373   int  ivlen = 0;
374   int  s2k_mode = 0;
375   int  s2k_algo = 0;
376   byte s2k_salt[8];
377   u32  s2k_count = 0;
378   size_t npkey, nskey;
379   gcry_mpi_t skey[10];  /* We support up to 9 parameters.  */
380   int skeyidx = 0;
381   struct seckey_info *ski;
382
383   top_list = gcry_sexp_find_token (s_pgp, "openpgp-private-key", 0);
384   if (!top_list)
385     goto bad_seckey;
386
387   list = gcry_sexp_find_token (top_list, "version", 0);
388   if (!list)
389     goto bad_seckey;
390   value = gcry_sexp_nth_data (list, 1, &valuelen);
391   if (!value || valuelen != 1 || !(value[0] == '3' || value[0] == '4'))
392     goto bad_seckey;
393   is_v4 = (value[0] == '4');
394
395   gcry_sexp_release (list);
396   list = gcry_sexp_find_token (top_list, "protection", 0);
397   if (!list)
398     goto bad_seckey;
399   value = gcry_sexp_nth_data (list, 1, &valuelen);
400   if (!value)
401     goto bad_seckey;
402   if (valuelen == 4 && !memcmp (value, "sha1", 4))
403     is_protected = 2;
404   else if (valuelen == 3 && !memcmp (value, "sum", 3))
405     is_protected = 1;
406   else if (valuelen == 4 && !memcmp (value, "none", 4))
407     is_protected = 0;
408   else
409     goto bad_seckey;
410   if (is_protected)
411     {
412       string = gcry_sexp_nth_string (list, 2);
413       if (!string)
414         goto bad_seckey;
415       protect_algo = gcry_cipher_map_name (string);
416       xfree (string);
417
418       value = gcry_sexp_nth_data (list, 3, &valuelen);
419       if (!value || !valuelen || valuelen > sizeof iv)
420         goto bad_seckey;
421       memcpy (iv, value, valuelen);
422       ivlen = valuelen;
423
424       string = gcry_sexp_nth_string (list, 4);
425       if (!string)
426         goto bad_seckey;
427       s2k_mode = strtol (string, NULL, 10);
428       xfree (string);
429
430       string = gcry_sexp_nth_string (list, 5);
431       if (!string)
432         goto bad_seckey;
433       s2k_algo = gcry_md_map_name (string);
434       xfree (string);
435
436       value = gcry_sexp_nth_data (list, 6, &valuelen);
437       if (!value || !valuelen || valuelen > sizeof s2k_salt)
438         goto bad_seckey;
439       memcpy (s2k_salt, value, valuelen);
440
441       string = gcry_sexp_nth_string (list, 7);
442       if (!string)
443         goto bad_seckey;
444       s2k_count = strtoul (string, NULL, 10);
445       xfree (string);
446     }
447
448   gcry_sexp_release (list);
449   list = gcry_sexp_find_token (top_list, "algo", 0);
450   if (!list)
451     goto bad_seckey;
452   string = gcry_sexp_nth_string (list, 1);
453   if (!string)
454     goto bad_seckey;
455   pubkey_algo = gcry_pk_map_name (string);
456   xfree (string);
457
458   if (gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
459       || gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey)
460       || !npkey || npkey >= nskey || nskey > PUBKEY_MAX_NSKEY)
461     goto bad_seckey;
462   pubkey_algo = map_pk_gcry_to_openpgp (pubkey_algo);
463
464   gcry_sexp_release (list);
465   list = gcry_sexp_find_token (top_list, "skey", 0);
466   if (!list)
467     goto bad_seckey;
468   for (idx=0;;)
469     {
470       int is_enc;
471
472       value = gcry_sexp_nth_data (list, ++idx, &valuelen);
473       if (!value && skeyidx >= npkey)
474         break;  /* Ready.  */
475
476       /* Check for too many parameters.  Note that depending on the
477          protection mode and version number we may see less than NSKEY
478          (but at least NPKEY+1) parameters.  */
479       if (idx >= 2*nskey)
480         goto bad_seckey;
481       if (skeyidx >= DIM (skey)-1)
482         goto bad_seckey;
483
484       if (!value || valuelen != 1 || !(value[0] == '_' || value[0] == 'e'))
485         goto bad_seckey;
486       is_enc = (value[0] == 'e');
487       value = gcry_sexp_nth_data (list, ++idx, &valuelen);
488       if (!value || !valuelen)
489         goto bad_seckey;
490       if (is_enc)
491         {
492           void *p = xtrymalloc (valuelen);
493           if (!p)
494             goto outofmem;
495           memcpy (p, value, valuelen);
496           skey[skeyidx] = gcry_mpi_set_opaque (NULL, p, valuelen*8);
497           if (!skey[skeyidx])
498             goto outofmem;
499         }
500       else
501         {
502           if (gcry_mpi_scan (skey + skeyidx, GCRYMPI_FMT_STD,
503                              value, valuelen, NULL))
504             goto bad_seckey;
505         }
506       skeyidx++;
507     }
508   skey[skeyidx++] = NULL;
509
510   gcry_sexp_release (list); list = NULL;
511
512   /* We have no need for the CSUM valuel thus we don't parse it.  */
513   /* list = gcry_sexp_find_token (top_list, "csum", 0); */
514   /* if (list) */
515   /*   { */
516   /*     string = gcry_sexp_nth_string (list, 1); */
517   /*     if (!string) */
518   /*       goto bad_seckey; */
519   /*     desired_csum = strtoul (string, NULL, 10); */
520   /*     xfree (string); */
521   /*   } */
522   /* else */
523   /*   desired_csum = 0; */
524   /* gcry_sexp_release (list); list = NULL; */
525
526   gcry_sexp_release (top_list); top_list = NULL;
527
528   /* log_debug ("XXX is_v4=%d\n", is_v4); */
529   /* log_debug ("XXX pubkey_algo=%d\n", pubkey_algo); */
530   /* log_debug ("XXX is_protected=%d\n", is_protected); */
531   /* log_debug ("XXX protect_algo=%d\n", protect_algo); */
532   /* log_printhex ("XXX iv", iv, ivlen); */
533   /* log_debug ("XXX ivlen=%d\n", ivlen); */
534   /* log_debug ("XXX s2k_mode=%d\n", s2k_mode); */
535   /* log_debug ("XXX s2k_algo=%d\n", s2k_algo); */
536   /* log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt); */
537   /* log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count); */
538   /* for (idx=0; skey[idx]; idx++) */
539   /*   { */
540   /*     int is_enc = gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE); */
541   /*     log_info ("XXX skey[%d]%s:", idx, is_enc? " (enc)":""); */
542   /*     if (is_enc) */
543   /*       { */
544   /*         void *p; */
545   /*         unsigned int nbits; */
546   /*         p = gcry_mpi_get_opaque (skey[idx], &nbits); */
547   /*         log_printhex (NULL, p, (nbits+7)/8); */
548   /*       } */
549   /*     else */
550   /*       gcry_mpi_dump (skey[idx]); */
551   /*     log_printf ("\n"); */
552   /*   } */
553
554   if (!is_v4 || is_protected != 2 )
555     {
556       /* We only support the v4 format and a SHA-1 checksum.  */
557       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
558       goto leave;
559     }
560
561   /* We need to change the received parameters for ECC algorithms.
562      The transfer format has all parameters but OpenPGP defines that
563      only the OID of the curve is to be used.  */
564   if (pubkey_algo == PUBKEY_ALGO_ECDSA
565       || pubkey_algo == PUBKEY_ALGO_EDDSA
566       || pubkey_algo == PUBKEY_ALGO_ECDH)
567     {
568       gcry_sexp_t s_pubkey;
569       const char *curvename, *curveoidstr;
570       gcry_mpi_t mpi;
571
572       /* We build an S-expression with the public key parameters and
573          ask Libgcrypt to return the matching curve name.  */
574       if (npkey != 6 || !skey[0] || !skey[1] || !skey[2]
575           || !skey[3] || !skey[4] || !skey[5]
576           || !skey[6] || skey[7])
577         {
578           err = gpg_error (GPG_ERR_INTERNAL);
579           goto leave;
580         }
581       err = gcry_sexp_build (&s_pubkey, NULL,
582                              "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)))",
583                              skey[0], skey[1], skey[2], skey[3], skey[4]);
584       if (err)
585         goto leave;
586       curvename = gcry_pk_get_curve (s_pubkey, 0, NULL);
587       gcry_sexp_release (s_pubkey);
588       curveoidstr = openpgp_curve_to_oid (curvename, NULL);
589       if (!curveoidstr)
590         {
591           log_error ("no OID known for curve '%s'\n", curvename);
592           err = gpg_error (GPG_ERR_UNKNOWN_NAME);
593           goto leave;
594         }
595       err = openpgp_oid_from_str (curveoidstr, &mpi);
596       if (err)
597         goto leave;
598
599       /* Now replace the curve parameters by the OID and shift the
600          rest of the parameters.  */
601       gcry_mpi_release (skey[0]);
602       skey[0] = mpi;
603       for (idx=1; idx <= 4; idx++)
604         gcry_mpi_release (skey[idx]);
605       skey[1] = skey[5];
606       skey[2] = skey[6];
607       for (idx=3; idx <= 6; idx++)
608         skey[idx] = NULL;
609
610       /* Fixup the NPKEY and NSKEY to match OpenPGP reality.  */
611       npkey = 2;
612       nskey = 3;
613
614       /* for (idx=0; skey[idx]; idx++) */
615       /*   { */
616       /*     log_info ("YYY skey[%d]:", idx); */
617       /*     if (gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE)) */
618       /*       { */
619       /*         void *p; */
620       /*         unsigned int nbits; */
621       /*         p = gcry_mpi_get_opaque (skey[idx], &nbits); */
622       /*         log_printhex (NULL, p, (nbits+7)/8); */
623       /*       } */
624       /*     else */
625       /*       gcry_mpi_dump (skey[idx]); */
626       /*     log_printf ("\n"); */
627       /*   } */
628     }
629
630   /* Do some sanity checks.  */
631   if (s2k_count > 255)
632     {
633       /* We expect an already encoded S2K count.  */
634       err = gpg_error (GPG_ERR_INV_DATA);
635       goto leave;
636     }
637   if (canon_pubkey_algo (pubkey_algo) != canon_pubkey_algo (pk->pubkey_algo))
638     {
639       err = gpg_error (GPG_ERR_PUBKEY_ALGO);
640       goto leave;
641     }
642   err = openpgp_cipher_test_algo (protect_algo);
643   if (err)
644     goto leave;
645   err = openpgp_md_test_algo (s2k_algo);
646   if (err)
647     goto leave;
648
649   /* Check that the public key parameters match.  Note that since
650      Libgcrypt 1.5 gcry_mpi_cmp handles opaque MPI correctly.  */
651   for (idx=0; idx < npkey; idx++)
652     if (gcry_mpi_cmp (pk->pkey[idx], skey[idx]))
653       {
654         err = gpg_error (GPG_ERR_BAD_PUBKEY);
655         goto leave;
656       }
657
658   /* Check that the first secret key parameter in SKEY is encrypted
659      and that there are no more secret key parameters.  The latter is
660      guaranteed by the v4 packet format.  */
661   if (!gcry_mpi_get_flag (skey[npkey], GCRYMPI_FLAG_OPAQUE))
662     goto bad_seckey;
663   if (npkey+1 < DIM (skey) && skey[npkey+1])
664     goto bad_seckey;
665
666   /* Check that the secret key parameters in PK are all set to NULL. */
667   for (idx=npkey; idx < nskey; idx++)
668     if (pk->pkey[idx])
669       goto bad_seckey;
670
671   /* Now build the protection info. */
672   pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
673   if (!ski)
674     {
675       err = gpg_error_from_syserror ();
676       goto leave;
677     }
678
679   ski->is_protected = 1;
680   ski->sha1chk = 1;
681   ski->algo = protect_algo;
682   ski->s2k.mode = s2k_mode;
683   ski->s2k.hash_algo = s2k_algo;
684   assert (sizeof ski->s2k.salt == sizeof s2k_salt);
685   memcpy (ski->s2k.salt, s2k_salt, sizeof s2k_salt);
686   ski->s2k.count = s2k_count;
687   assert (ivlen <= sizeof ski->iv);
688   memcpy (ski->iv, iv, ivlen);
689   ski->ivlen = ivlen;
690
691   /* Store the protected secret key parameter.  */
692   pk->pkey[npkey] = skey[npkey];
693   skey[npkey] = NULL;
694
695   /* That's it.  */
696
697  leave:
698   gcry_sexp_release (list);
699   gcry_sexp_release (top_list);
700   for (idx=0; idx < skeyidx; idx++)
701     gcry_mpi_release (skey[idx]);
702   return err;
703
704  bad_seckey:
705   err = gpg_error (GPG_ERR_BAD_SECKEY);
706   goto leave;
707
708  outofmem:
709   err = gpg_error (GPG_ERR_ENOMEM);
710   goto leave;
711 }
712
713 /* Export the keys identified by the list of strings in USERS to the
714    stream OUT.  If Secret is false public keys will be exported.  With
715    secret true secret keys will be exported; in this case 1 means the
716    entire secret keyblock and 2 only the subkeys.  OPTIONS are the
717    export options to apply.  If KEYBLOCK_OUT is not NULL, AND the exit
718    code is zero, a pointer to the first keyblock found and exported
719    will be stored at this address; no other keyblocks are exported in
720    this case.  The caller must free it the returned keyblock.  If any
721    key has been exported true is stored at ANY. */
722 static int
723 do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
724                   kbnode_t *keyblock_out, unsigned int options, int *any)
725 {
726   gpg_error_t err = 0;
727   PACKET pkt;
728   KBNODE keyblock = NULL;
729   KBNODE kbctx, node;
730   size_t ndesc, descindex;
731   KEYDB_SEARCH_DESC *desc = NULL;
732   subkey_list_t subkey_list = NULL;  /* Track already processed subkeys. */
733   KEYDB_HANDLE kdbhd;
734   strlist_t sl;
735   int indent = 0;
736   gcry_cipher_hd_t cipherhd = NULL;
737
738   *any = 0;
739   init_packet (&pkt);
740   kdbhd = keydb_new ();
741
742   if (!users)
743     {
744       ndesc = 1;
745       desc = xcalloc (ndesc, sizeof *desc);
746       desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
747     }
748   else
749     {
750       for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
751         ;
752       desc = xmalloc ( ndesc * sizeof *desc);
753
754       for (ndesc=0, sl=users; sl; sl = sl->next)
755         {
756           if (!(err=classify_user_id (sl->d, desc+ndesc, 1)))
757             ndesc++;
758           else
759             log_error (_("key \"%s\" not found: %s\n"),
760                        sl->d, gpg_strerror (err));
761         }
762
763       /* It would be nice to see which of the given users did actually
764          match one in the keyring.  To implement this we need to have
765          a found flag for each entry in desc.  To set this flag we
766          must check all those entries after a match to mark all
767          matched one - currently we stop at the first match.  To do
768          this we need an extra flag to enable this feature.  */
769     }
770
771 #ifdef ENABLE_SELINUX_HACKS
772   if (secret)
773     {
774       log_error (_("exporting secret keys not allowed\n"));
775       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
776       goto leave;
777     }
778 #endif
779
780   /* For secret key export we need to setup a decryption context.  */
781   if (secret)
782     {
783       void *kek = NULL;
784       size_t keklen;
785
786       err = agent_keywrap_key (ctrl, 1, &kek, &keklen);
787       if (err)
788         {
789           log_error ("error getting the KEK: %s\n", gpg_strerror (err));
790           goto leave;
791         }
792
793       /* Prepare a cipher context.  */
794       err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
795                               GCRY_CIPHER_MODE_AESWRAP, 0);
796       if (!err)
797         err = gcry_cipher_setkey (cipherhd, kek, keklen);
798       if (err)
799         {
800           log_error ("error setting up an encryption context: %s\n",
801                      gpg_strerror (err));
802           goto leave;
803         }
804       xfree (kek);
805       kek = NULL;
806     }
807
808   while (!(err = keydb_search (kdbhd, desc, ndesc, &descindex)))
809     {
810       int skip_until_subkey = 0;
811       u32 keyid[2];
812       PKT_public_key *pk;
813
814       if (!users)
815         desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
816
817       /* Read the keyblock. */
818       release_kbnode (keyblock);
819       keyblock = NULL;
820       err = keydb_get_keyblock (kdbhd, &keyblock);
821       if (err)
822         {
823           log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
824           goto leave;
825         }
826
827       node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
828       if (!node)
829         {
830           log_error ("public key packet not found in keyblock - skipped\n");
831           continue;
832         }
833       pk = node->pkt->pkt.public_key;
834       keyid_from_pk (pk, keyid);
835
836       /* If a secret key export is required we need to check whether
837          we have a secret key at all and if so create the seckey_info
838          structure.  */
839       if (secret)
840         {
841           if (agent_probe_any_secret_key (ctrl, keyblock))
842             continue;  /* No secret key (neither primary nor subkey).  */
843
844           /* No v3 keys with GNU mode 1001. */
845           if (secret == 2 && pk->version == 3)
846             {
847               log_info (_("key %s: PGP 2.x style key - skipped\n"),
848                         keystr (keyid));
849               continue;
850             }
851
852           /* The agent does not yet allow to export v3 packets.  It is
853              actually questionable whether we should allow them at
854              all.  */
855           if (pk->version == 3)
856             {
857               log_info ("key %s: PGP 2.x style key (v3) export "
858                         "not yet supported - skipped\n", keystr (keyid));
859               continue;
860             }
861         }
862
863       /* Always do the cleaning on the public key part if requested.
864          Note that we don't yet set this option if we are exporting
865          secret keys.  Note that both export-clean and export-minimal
866          only apply to UID sigs (0x10, 0x11, 0x12, and 0x13).  A
867          designated revocation is never stripped, even with
868          export-minimal set.  */
869       if ((options & EXPORT_CLEAN))
870         clean_key (keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL);
871
872       /* And write it. */
873       for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
874         {
875           if (skip_until_subkey)
876             {
877               if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
878                 skip_until_subkey = 0;
879               else
880                 continue;
881             }
882
883           /* We used to use comment packets, but not any longer.  In
884              case we still have comments on a key, strip them here
885              before we call build_packet(). */
886           if (node->pkt->pkttype == PKT_COMMENT)
887             continue;
888
889           /* Make sure that ring_trust packets never get exported. */
890           if (node->pkt->pkttype == PKT_RING_TRUST)
891             continue;
892
893           /* If exact is set, then we only export what was requested
894              (plus the primary key, if the user didn't specifically
895              request it). */
896           if (desc[descindex].exact
897               && node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
898             {
899               if (!exact_subkey_match_p (desc+descindex, node))
900                 {
901                   /* Before skipping this subkey, check whether any
902                      other description wants an exact match on a
903                      subkey and include that subkey into the output
904                      too.  Need to add this subkey to a list so that
905                      it won't get processed a second time.
906
907                      So the first step here is to check that list and
908                      skip in any case if the key is in that list.
909
910                      We need this whole mess because the import
911                      function of GnuPG < 2.1 is not able to merge
912                      secret keys and thus it is useless to output them
913                      as two separate keys and have import merge them.  */
914                   if (subkey_in_list_p (subkey_list, node))
915                     skip_until_subkey = 1; /* Already processed this one. */
916                   else
917                     {
918                       size_t j;
919
920                       for (j=0; j < ndesc; j++)
921                         if (j != descindex && desc[j].exact
922                             && exact_subkey_match_p (desc+j, node))
923                           break;
924                       if (!(j < ndesc))
925                         skip_until_subkey = 1; /* No other one matching. */
926                     }
927                 }
928
929               if(skip_until_subkey)
930                 continue;
931
932               /* Mark this one as processed. */
933               {
934                 subkey_list_t tmp = new_subkey_list_item (node);
935                 tmp->next = subkey_list;
936                 subkey_list = tmp;
937               }
938             }
939
940           if (node->pkt->pkttype == PKT_SIGNATURE)
941             {
942               /* Do not export packets which are marked as not
943                  exportable.  */
944               if (!(options&EXPORT_LOCAL_SIGS)
945                   && !node->pkt->pkt.signature->flags.exportable)
946                 continue; /* not exportable */
947
948               /* Do not export packets with a "sensitive" revocation
949                  key unless the user wants us to.  Note that we do
950                  export these when issuing the actual revocation
951                  (see revoke.c). */
952               if (!(options&EXPORT_SENSITIVE_REVKEYS)
953                   && node->pkt->pkt.signature->revkey)
954                 {
955                   int i;
956
957                   for (i=0;i<node->pkt->pkt.signature->numrevkeys;i++)
958                     if ( (node->pkt->pkt.signature->revkey[i]->class & 0x40))
959                       break;
960
961                   if (i < node->pkt->pkt.signature->numrevkeys)
962                     continue;
963                 }
964             }
965
966           /* Don't export attribs? */
967           if (!(options&EXPORT_ATTRIBUTES)
968               && node->pkt->pkttype == PKT_USER_ID
969               && node->pkt->pkt.user_id->attrib_data )
970             {
971               /* Skip until we get to something that is not an attrib
972                  or a signature on an attrib */
973               while (kbctx->next && kbctx->next->pkt->pkttype==PKT_SIGNATURE)
974                 kbctx = kbctx->next;
975
976               continue;
977             }
978
979           if (secret && (node->pkt->pkttype == PKT_PUBLIC_KEY
980                          || node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
981             {
982               u32 subkidbuf[2], *subkid;
983               char *hexgrip, *serialno;
984
985               pk = node->pkt->pkt.public_key;
986               if (node->pkt->pkttype == PKT_PUBLIC_KEY)
987                 subkid = NULL;
988               else
989                 {
990                   keyid_from_pk (pk, subkidbuf);
991                   subkid = subkidbuf;
992                 }
993
994               if (pk->seckey_info)
995                 {
996                   log_error ("key %s: oops: seckey_info already set"
997                              " - skipped\n", keystr_with_sub (keyid, subkid));
998                   skip_until_subkey = 1;
999                   continue;
1000                 }
1001
1002               err = hexkeygrip_from_pk (pk, &hexgrip);
1003               if (err)
1004                 {
1005                   log_error ("key %s: error computing keygrip: %s"
1006                              " - skipped\n", keystr_with_sub (keyid, subkid),
1007                              gpg_strerror (err));
1008                   skip_until_subkey = 1;
1009                   err = 0;
1010                   continue;
1011                 }
1012
1013               if (secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY)
1014                 {
1015                   /* We are asked not to export the secret parts of
1016                      the primary key.  Make up an error code to create
1017                      the stub.  */
1018                   err = GPG_ERR_NOT_FOUND;
1019                   serialno = NULL;
1020                 }
1021               else
1022                 err = agent_get_keyinfo (ctrl, hexgrip, &serialno);
1023
1024               if ((!err && serialno)
1025                   && secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY)
1026                 {
1027                   /* It does not make sense to export a key with its
1028                      primary key on card using a non-key stub.  Thus
1029                      we skip those keys when used with
1030                      --export-secret-subkeys. */
1031                   log_info (_("key %s: key material on-card - skipped\n"),
1032                             keystr_with_sub (keyid, subkid));
1033                   skip_until_subkey = 1;
1034                 }
1035               else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND
1036                        || (!err && serialno))
1037                 {
1038                   /* Create a key stub.  */
1039                   struct seckey_info *ski;
1040                   const char *s;
1041
1042                   pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
1043                   if (!ski)
1044                     {
1045                       err = gpg_error_from_syserror ();
1046                       xfree (hexgrip);
1047                       goto leave;
1048                     }
1049
1050                   ski->is_protected = 1;
1051                   if (err)
1052                     ski->s2k.mode = 1001; /* GNU dummy (no secret key).  */
1053                   else
1054                     {
1055                       ski->s2k.mode = 1002; /* GNU-divert-to-card.  */
1056                       for (s=serialno; sizeof (ski->ivlen) && *s && s[1];
1057                            ski->ivlen++, s += 2)
1058                         ski->iv[ski->ivlen] = xtoi_2 (s);
1059                     }
1060
1061                   if ((options&EXPORT_SEXP_FORMAT))
1062                     err = build_sexp (out, node->pkt, &indent);
1063                   else
1064                     err = build_packet (out, node->pkt);
1065                 }
1066               else if (!err)
1067                 {
1068                   /* FIXME: Move this spaghetti code into a separate
1069                      function.  */
1070                   unsigned char *wrappedkey = NULL;
1071                   size_t wrappedkeylen;
1072                   unsigned char *key = NULL;
1073                   size_t keylen, realkeylen;
1074                   gcry_sexp_t s_skey;
1075
1076                   if (opt.verbose)
1077                     log_info ("key %s: asking agent for the secret parts\n",
1078                               keystr_with_sub (keyid, subkid));
1079
1080                   err = agent_export_key (ctrl, hexgrip, "Key foo", NULL,
1081                                           &wrappedkey, &wrappedkeylen);
1082                   if (err)
1083                     goto unwraperror;
1084                   if (wrappedkeylen < 24)
1085                     {
1086                       err = gpg_error (GPG_ERR_INV_LENGTH);
1087                       goto unwraperror;
1088                     }
1089                   keylen = wrappedkeylen - 8;
1090                   key = xtrymalloc_secure (keylen);
1091                   if (!key)
1092                     {
1093                       err = gpg_error_from_syserror ();
1094                       goto unwraperror;
1095                     }
1096                   err = gcry_cipher_decrypt (cipherhd, key, keylen,
1097                                              wrappedkey, wrappedkeylen);
1098                   if (err)
1099                     goto unwraperror;
1100                   realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err);
1101                   if (!realkeylen)
1102                     goto unwraperror; /* Invalid csexp.  */
1103
1104                   err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen);
1105                   xfree (key);
1106                   key = NULL;
1107                   if (err)
1108                     goto unwraperror;
1109                   err = transfer_format_to_openpgp (s_skey, pk);
1110                   gcry_sexp_release (s_skey);
1111                   if (err)
1112                     goto unwraperror;
1113
1114                   if ((options&EXPORT_SEXP_FORMAT))
1115                     err = build_sexp (out, node->pkt, &indent);
1116                   else
1117                     err = build_packet (out, node->pkt);
1118                   goto unwraperror_leave;
1119
1120                 unwraperror:
1121                   xfree (wrappedkey);
1122                   xfree (key);
1123                   if (err)
1124                     {
1125                       log_error ("key %s: error receiving key from agent:"
1126                                  " %s%s\n",
1127                                  keystr_with_sub (keyid, subkid),
1128                                  gpg_strerror (err),
1129                                  gpg_err_code (err) == GPG_ERR_FULLY_CANCELED?
1130                                  "":_(" - skipped"));
1131                       if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
1132                         goto leave;
1133                       skip_until_subkey = 1;
1134                       err = 0;
1135                     }
1136                 unwraperror_leave:
1137                   ;
1138                 }
1139               else
1140                 {
1141                   log_error ("key %s: error getting keyinfo from agent: %s"
1142                              " - skipped\n", keystr_with_sub (keyid, subkid),
1143                              gpg_strerror (err));
1144                   skip_until_subkey = 1;
1145                   err = 0;
1146                 }
1147
1148               xfree (pk->seckey_info);
1149               pk->seckey_info = NULL;
1150               xfree (hexgrip);
1151             }
1152           else
1153             {
1154               if ((options&EXPORT_SEXP_FORMAT))
1155                 err = build_sexp (out, node->pkt, &indent);
1156               else
1157                 err = build_packet (out, node->pkt);
1158             }
1159
1160           if (err)
1161             {
1162               log_error ("build_packet(%d) failed: %s\n",
1163                          node->pkt->pkttype, gpg_strerror (err));
1164               goto leave;
1165             }
1166
1167           if (!skip_until_subkey)
1168             *any = 1;
1169         }
1170
1171       if ((options&EXPORT_SEXP_FORMAT) && indent)
1172         {
1173           for (; indent; indent--)
1174             iobuf_put (out, ')');
1175           iobuf_put (out, '\n');
1176         }
1177
1178       if (keyblock_out)
1179         {
1180           *keyblock_out = keyblock;
1181           break;
1182         }
1183     }
1184   if ((options&EXPORT_SEXP_FORMAT) && indent)
1185     {
1186       for (; indent; indent--)
1187         iobuf_put (out, ')');
1188       iobuf_put (out, '\n');
1189     }
1190   if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
1191     err = 0;
1192
1193  leave:
1194   gcry_cipher_close (cipherhd);
1195   release_subkey_list (subkey_list);
1196   xfree(desc);
1197   keydb_release (kdbhd);
1198   if (err || !keyblock_out)
1199     release_kbnode( keyblock );
1200   if( !*any )
1201     log_info(_("WARNING: nothing exported\n"));
1202   return err;
1203 }
1204
1205
1206
1207 /* static int */
1208 /* write_sexp_line (iobuf_t out, int *indent, const char *text) */
1209 /* { */
1210 /*   int i; */
1211
1212 /*   for (i=0; i < *indent; i++) */
1213 /*     iobuf_put (out, ' '); */
1214 /*   iobuf_writestr (out, text); */
1215 /*   return 0; */
1216 /* } */
1217
1218 /* static int */
1219 /* write_sexp_keyparm (iobuf_t out, int *indent, const char *name, gcry_mpi_t a) */
1220 /* { */
1221 /*   int rc; */
1222 /*   unsigned char *buffer; */
1223
1224 /*   write_sexp_line (out, indent, "("); */
1225 /*   iobuf_writestr (out, name); */
1226 /*   iobuf_writestr (out, " #"); */
1227
1228 /*   rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, a); */
1229 /*   assert (!rc); */
1230 /*   iobuf_writestr (out, buffer); */
1231 /*   iobuf_writestr (out, "#)"); */
1232 /*   gcry_free (buffer); */
1233 /*   return 0; */
1234 /* } */
1235
1236 static int
1237 build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent)
1238 {
1239   (void)out;
1240   (void)pkt;
1241   (void)indent;
1242
1243   /* FIXME: Not yet implemented.  */
1244   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1245   /* PKT_secret_key *sk = pkt->pkt.secret_key; */
1246   /* char tmpbuf[100]; */
1247
1248   /* if (pkt->pkttype == PKT_SECRET_KEY) */
1249   /*   { */
1250   /*     iobuf_writestr (out, "(openpgp-key\n"); */
1251   /*     (*indent)++; */
1252   /*   } */
1253   /* else */
1254   /*   { */
1255   /*     iobuf_writestr (out, " (subkey\n"); */
1256   /*     (*indent)++; */
1257   /*   } */
1258   /* (*indent)++; */
1259   /* write_sexp_line (out, indent, "(private-key\n"); */
1260   /* (*indent)++; */
1261   /* if (is_RSA (sk->pubkey_algo) && !sk->is_protected) */
1262   /*   { */
1263   /*     write_sexp_line (out, indent, "(rsa\n"); */
1264   /*     (*indent)++; */
1265   /*     write_sexp_keyparm (out, indent, "n", sk->skey[0]); iobuf_put (out,'\n'); */
1266   /*     write_sexp_keyparm (out, indent, "e", sk->skey[1]); iobuf_put (out,'\n'); */
1267   /*     write_sexp_keyparm (out, indent, "d", sk->skey[2]); iobuf_put (out,'\n'); */
1268   /*     write_sexp_keyparm (out, indent, "p", sk->skey[3]); iobuf_put (out,'\n'); */
1269   /*     write_sexp_keyparm (out, indent, "q", sk->skey[4]); iobuf_put (out,'\n'); */
1270   /*     write_sexp_keyparm (out, indent, "u", sk->skey[5]);  */
1271   /*     iobuf_put (out,')'); iobuf_put (out,'\n'); */
1272   /*     (*indent)--; */
1273   /*   } */
1274   /* else if (sk->pubkey_algo == PUBKEY_ALGO_DSA && !sk->is_protected) */
1275   /*   { */
1276   /*     write_sexp_line (out, indent, "(dsa\n"); */
1277   /*     (*indent)++; */
1278   /*     write_sexp_keyparm (out, indent, "p", sk->skey[0]); iobuf_put (out,'\n'); */
1279   /*     write_sexp_keyparm (out, indent, "q", sk->skey[1]); iobuf_put (out,'\n'); */
1280   /*     write_sexp_keyparm (out, indent, "g", sk->skey[2]); iobuf_put (out,'\n'); */
1281   /*     write_sexp_keyparm (out, indent, "y", sk->skey[3]); iobuf_put (out,'\n'); */
1282   /*     write_sexp_keyparm (out, indent, "x", sk->skey[4]); */
1283   /*     iobuf_put (out,')'); iobuf_put (out,'\n'); */
1284   /*     (*indent)--; */
1285   /*   } */
1286   /* else if (sk->pubkey_algo == PUBKEY_ALGO_ECDSA && !sk->is_protected) */
1287   /*   { */
1288   /*     write_sexp_line (out, indent, "(ecdsa\n"); */
1289   /*     (*indent)++;  */
1290   /*     write_sexp_keyparm (out, indent, "c", sk->skey[0]); iobuf_put (out,'\n'); */
1291   /*     write_sexp_keyparm (out, indent, "q", sk->skey[6]); iobuf_put (out,'\n'); */
1292   /*     write_sexp_keyparm (out, indent, "d", sk->skey[7]); */
1293   /*     iobuf_put (out,')'); iobuf_put (out,'\n'); */
1294   /*     (*indent)--; */
1295   /*   } */
1296   /* else if (is_ELGAMAL (sk->pubkey_algo) && !sk->is_protected) */
1297   /*   { */
1298   /*     write_sexp_line (out, indent, "(elg\n"); */
1299   /*     (*indent)++; */
1300   /*     write_sexp_keyparm (out, indent, "p", sk->skey[0]); iobuf_put (out,'\n'); */
1301   /*     write_sexp_keyparm (out, indent, "g", sk->skey[2]); iobuf_put (out,'\n'); */
1302   /*     write_sexp_keyparm (out, indent, "y", sk->skey[3]); iobuf_put (out,'\n'); */
1303   /*     write_sexp_keyparm (out, indent, "x", sk->skey[4]); */
1304   /*     iobuf_put (out,')'); iobuf_put (out,'\n'); */
1305   /*     (*indent)--; */
1306   /*   } */
1307   /* write_sexp_line (out, indent,  "(attrib\n"); (*indent)++; */
1308   /* sprintf (tmpbuf, "(created \"%lu\"", (unsigned long)sk->timestamp); */
1309   /* write_sexp_line (out, indent, tmpbuf); */
1310   /* iobuf_put (out,')'); (*indent)--; /\* close created *\/ */
1311   /* iobuf_put (out,')'); (*indent)--; /\* close attrib *\/ */
1312   /* iobuf_put (out,')'); (*indent)--; /\* close private-key *\/ */
1313   /* if (pkt->pkttype != PKT_SECRET_KEY) */
1314   /*   iobuf_put (out,')'), (*indent)--; /\* close subkey *\/ */
1315   /* iobuf_put (out,'\n'); */
1316
1317   /* return 0; */
1318 }
1319
1320
1321 /* For some packet types we write them in a S-expression format.  This
1322    is still EXPERIMENTAL and subject to change.  */
1323 static int
1324 build_sexp (iobuf_t out, PACKET *pkt, int *indent)
1325 {
1326   int rc;
1327
1328   switch (pkt->pkttype)
1329     {
1330     case PKT_SECRET_KEY:
1331     case PKT_SECRET_SUBKEY:
1332       rc = build_sexp_seckey (out, pkt, indent);
1333       break;
1334     default:
1335       rc = 0;
1336       break;
1337     }
1338   return rc;
1339 }