Removed more secret key related code.
[gnupg.git] / g10 / export.c
1 /* export.c
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
3  *               2005 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
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( strlist_t users, int secret, unsigned int options );
49 static int do_export_stream( IOBUF out, strlist_t users, int secret,
50                              KBNODE *keyblock_out, unsigned int options,
51                              int *any );
52 static int build_sexp (iobuf_t out, PACKET *pkt, int *indent);
53
54
55 int
56 parse_export_options(char *str,unsigned int *options,int noisy)
57 {
58   struct parse_options export_opts[]=
59     {
60       {"export-local-sigs",EXPORT_LOCAL_SIGS,NULL,
61        N_("export signatures that are marked as local-only")},
62       {"export-attributes",EXPORT_ATTRIBUTES,NULL,
63        N_("export attribute user IDs (generally photo IDs)")},
64       {"export-sensitive-revkeys",EXPORT_SENSITIVE_REVKEYS,NULL,
65        N_("export revocation keys marked as \"sensitive\"")},
66       {"export-reset-subkey-passwd",EXPORT_RESET_SUBKEY_PASSWD,NULL,
67        N_("remove the passphrase from exported subkeys")},
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( strlist_t users, unsigned int options )
97 {
98     return do_export( 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( IOBUF out, strlist_t users,
107                        KBNODE *keyblock_out, unsigned int options )
108 {
109     int any, rc;
110
111     rc = do_export_stream( out, users, 0, keyblock_out, options, &any );
112     if( !rc && !any )
113         rc = -1;
114     return rc;
115 }
116
117 int
118 export_seckeys( strlist_t users )
119 {
120   /* Use only relevant options for the secret key. */
121   unsigned int options = (opt.export_options & EXPORT_SEXP_FORMAT);
122   return do_export( users, 1, options );
123 }
124
125 int
126 export_secsubkeys( strlist_t users )
127 {
128   /* Use only relevant options for the secret key. */
129   unsigned int options = (opt.export_options & EXPORT_SEXP_FORMAT);
130   return do_export( users, 2, options );
131 }
132
133 static int
134 do_export( strlist_t users, int secret, unsigned int options )
135 {
136   IOBUF out = NULL;
137   int any, rc;
138   armor_filter_context_t *afx = NULL;
139   compress_filter_context_t zfx;
140   
141   memset( &zfx, 0, sizeof zfx);
142   
143   rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, &out );
144   if (rc)
145     return rc;
146
147   if (!(options & EXPORT_SEXP_FORMAT))
148     {
149       if ( opt.armor )
150         {
151           afx = new_armor_context ();
152           afx->what = secret? 5 : 1;
153           push_armor_filter (afx, out);
154         }
155       if ( opt.compress_keys )
156         push_compress_filter (out,&zfx,default_compress_algo());
157     }
158
159   rc = do_export_stream ( out, users, secret, NULL, options, &any );
160
161   if ( rc || !any )
162     iobuf_cancel (out);
163   else
164     iobuf_close (out);
165   release_armor_context (afx);
166   return rc;
167 }
168
169
170
171 /* Release an entire subkey list. */
172 static void
173 release_subkey_list (subkey_list_t list)
174 {
175   while (list)
176     {
177       subkey_list_t tmp = list->next;;
178       xfree (list);
179       list = tmp;
180     }
181 }
182
183
184 /* Returns true if NODE is a subkey and contained in LIST. */
185 static int
186 subkey_in_list_p (subkey_list_t list, KBNODE node)
187 {
188   if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
189       || node->pkt->pkttype == PKT_SECRET_SUBKEY )
190     {
191       u32 kid[2];
192
193       keyid_from_pk (node->pkt->pkt.public_key, kid);
194       
195       for (; list; list = list->next)
196         if (list->kid[0] == kid[0] && list->kid[1] == kid[1])
197           return 1;
198     }
199   return 0;
200 }
201
202 /* Allocate a new subkey list item from NODE. */
203 static subkey_list_t
204 new_subkey_list_item (KBNODE node)
205 {
206   subkey_list_t list = xcalloc (1, sizeof *list);
207
208   if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
209       || node->pkt->pkttype == PKT_SECRET_SUBKEY)
210     keyid_from_pk (node->pkt->pkt.public_key, list->kid);
211
212   return list;
213 }
214
215
216 /* Helper function to check whether the subkey at NODE actually
217    matches the description at DESC.  The function returns true if the
218    key under question has been specified by an exact specification
219    (keyID or fingerprint) and does match the one at NODE.  It is
220    assumed that the packet at NODE is either a public or secret
221    subkey. */
222 static int
223 exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node)
224 {
225   u32 kid[2];
226   byte fpr[MAX_FINGERPRINT_LEN];
227   size_t fprlen;
228   int result = 0;
229
230   switch(desc->mode)
231     {
232     case KEYDB_SEARCH_MODE_SHORT_KID:
233     case KEYDB_SEARCH_MODE_LONG_KID:
234       keyid_from_pk (node->pkt->pkt.public_key, kid);
235       break;
236       
237     case KEYDB_SEARCH_MODE_FPR16:
238     case KEYDB_SEARCH_MODE_FPR20:
239     case KEYDB_SEARCH_MODE_FPR:
240       fingerprint_from_pk (node->pkt->pkt.public_key, fpr,&fprlen);
241       break;
242       
243     default:
244       break;
245     }
246   
247   switch(desc->mode)
248     {
249     case KEYDB_SEARCH_MODE_SHORT_KID:
250       if (desc->u.kid[1] == kid[1])
251         result = 1;
252       break;
253
254     case KEYDB_SEARCH_MODE_LONG_KID:
255       if (desc->u.kid[0] == kid[0] && desc->u.kid[1] == kid[1])
256         result = 1;
257       break;
258
259     case KEYDB_SEARCH_MODE_FPR16:
260       if (!memcmp (desc->u.fpr, fpr, 16))
261         result = 1;
262       break;
263
264     case KEYDB_SEARCH_MODE_FPR20:
265     case KEYDB_SEARCH_MODE_FPR:
266       if (!memcmp (desc->u.fpr, fpr, 20))
267         result = 1;
268       break;
269
270     default:
271       break;
272     }
273
274   return result;
275 }
276
277
278 /* If keyblock_out is non-NULL, AND the exit code is zero, then it
279    contains a pointer to the first keyblock found and exported.  No
280    other keyblocks are exported.  The caller must free it.  */
281 static int
282 do_export_stream (iobuf_t out, strlist_t users, int secret,
283                   kbnode_t *keyblock_out, unsigned int options, int *any)
284 {
285   gpg_error_t err = 0;
286   PACKET pkt;
287   KBNODE keyblock = NULL;
288   KBNODE kbctx, node;
289   size_t ndesc, descindex;
290   KEYDB_SEARCH_DESC *desc = NULL;
291   subkey_list_t subkey_list = NULL;  /* Track already processed subkeys. */
292   KEYDB_HANDLE kdbhd;
293   strlist_t sl;
294   int indent = 0;
295
296   *any = 0;
297   init_packet (&pkt);
298   kdbhd = keydb_new ();
299
300   if (!users) 
301     {
302       ndesc = 1;
303       desc = xcalloc (ndesc, sizeof *desc);
304       desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
305     }
306   else
307     {
308       for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++) 
309         ;
310       desc = xmalloc ( ndesc * sizeof *desc);
311         
312       for (ndesc=0, sl=users; sl; sl = sl->next)
313         {
314           if (!(err=classify_user_id (sl->d, desc+ndesc)))
315             ndesc++;
316           else
317             log_error (_("key \"%s\" not found: %s\n"),
318                        sl->d, gpg_strerror (err));
319         }
320
321       /* It would be nice to see which of the given users did actually
322          match one in the keyring.  To implement this we need to have
323          a found flag for each entry in desc.  To set this flag we
324          must check all those entries after a match to mark all
325          matched one - currently we stop at the first match.  To do
326          this we need an extra flag to enable this feature.  */
327     }
328
329 #ifdef ENABLE_SELINUX_HACKS
330   if (secret)
331     {
332       log_error (_("exporting secret keys not allowed\n"));
333       err = G10ERR_GENERAL;
334       goto leave;
335     }
336 #endif
337
338   while (!(err = keydb_search2 (kdbhd, desc, ndesc, &descindex))) 
339     {
340       int sha1_warned = 0;
341       int skip_until_subkey = 0;
342       u32 keyid[2];
343
344       if (!users) 
345         desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
346
347       /* Read the keyblock. */
348       err = keydb_get_keyblock (kdbhd, &keyblock);
349       if (err) 
350         {
351           log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
352           goto leave;
353         }
354
355       if ((node=find_kbnode(keyblock, PKT_SECRET_KEY)))
356         {
357           PKT_public_key *pk = node->pkt->pkt.public_key;
358
359           keyid_from_pk (pk, keyid);
360
361           /* We can't apply GNU mode 1001 on an unprotected key. */
362           if( secret == 2
363               && pk->seckey_info && !pk->seckey_info->is_protected )
364             {
365               log_info (_("key %s: not protected - skipped\n"),
366                         keystr (keyid));
367               continue;
368             }
369
370           /* No v3 keys with GNU mode 1001. */
371           if( secret == 2 && pk->version == 3 )
372             {
373               log_info(_("key %s: PGP 2.x style key - skipped\n"),
374                        keystr (keyid));
375               continue;
376             }
377
378           /* It does not make sense to export a key with a primary
379              key on card using a non-key stub.  We simply skip those
380              keys when used with --export-secret-subkeys. */
381           if (secret == 2
382               && pk->seckey_info && pk->seckey_info->is_protected
383               && pk->seckey_info->s2k.mode == 1002 ) 
384             {
385               log_info(_("key %s: key material on-card - skipped\n"),
386                        keystr (keyid));
387               continue;
388             }
389         }
390       else
391         {
392           /* It's a public key export, so do the cleaning if
393              requested.  Note that both export-clean and
394              export-minimal only apply to UID sigs (0x10, 0x11, 0x12,
395              and 0x13).  A designated revocation is never stripped,
396              even with export-minimal set.  */
397           if ( (options & EXPORT_CLEAN) )
398             clean_key (keyblock, opt.verbose, options&EXPORT_MINIMAL,
399                        NULL, NULL);
400         }
401
402       /* And write it. */
403       for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); ) 
404         {
405           if (skip_until_subkey)
406             {
407               if (node->pkt->pkttype==PKT_PUBLIC_SUBKEY
408                   || node->pkt->pkttype==PKT_SECRET_SUBKEY)
409                 skip_until_subkey = 0;
410               else
411                 continue;
412             }
413
414           /* We used to use comment packets, but not any longer.  In
415              case we still have comments on a key, strip them here
416              before we call build_packet(). */
417           if (node->pkt->pkttype == PKT_COMMENT)
418             continue;
419
420           /* Make sure that ring_trust packets never get exported. */
421           if (node->pkt->pkttype == PKT_RING_TRUST)
422             continue;
423
424           /* If exact is set, then we only export what was requested
425              (plus the primary key, if the user didn't specifically
426              request it). */
427           if (desc[descindex].exact
428               && (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
429                   || node->pkt->pkttype == PKT_SECRET_SUBKEY))
430             {
431               if (!exact_subkey_match_p (desc+descindex, node))
432                 {
433                   /* Before skipping this subkey, check whether any
434                      other description wants an exact match on a
435                      subkey and include that subkey into the output
436                      too.  Need to add this subkey to a list so that
437                      it won't get processed a second time.
438                    
439                      So the first step here is to check that list and
440                      skip in any case if the key is in that list.
441
442                      We need this whole mess because the import
443                      function is not able to merge secret keys and
444                      thus it is useless to output them as two separate
445                      keys and have import merge them.  */
446                   if (subkey_in_list_p (subkey_list, node))  
447                     skip_until_subkey = 1; /* Already processed this one. */
448                   else
449                     {
450                       size_t j;
451
452                       for (j=0; j < ndesc; j++)
453                         if (j != descindex && desc[j].exact
454                             && exact_subkey_match_p (desc+j, node))
455                           break;
456                       if (!(j < ndesc))
457                         skip_until_subkey = 1; /* No other one matching. */ 
458                     }
459                 }
460
461               if(skip_until_subkey)
462                 continue;
463
464               /* Mark this one as processed. */
465               {
466                 subkey_list_t tmp = new_subkey_list_item (node);
467                 tmp->next = subkey_list;
468                 subkey_list = tmp;
469               }
470             }
471
472           if (node->pkt->pkttype == PKT_SIGNATURE)
473             {
474               /* Do not export packets which are marked as not
475                  exportable.  */
476               if (!(options&EXPORT_LOCAL_SIGS)
477                   && !node->pkt->pkt.signature->flags.exportable)
478                 continue; /* not exportable */
479
480               /* Do not export packets with a "sensitive" revocation
481                  key unless the user wants us to.  Note that we do
482                  export these when issuing the actual revocation
483                  (see revoke.c). */
484               if (!(options&EXPORT_SENSITIVE_REVKEYS)
485                   && node->pkt->pkt.signature->revkey)
486                 {
487                   int i;
488                   
489                   for (i=0;i<node->pkt->pkt.signature->numrevkeys;i++)
490                     if ( (node->pkt->pkt.signature->revkey[i]->class & 0x40))
491                       break;
492
493                   if (i < node->pkt->pkt.signature->numrevkeys)
494                     continue;
495                 }
496             }
497
498           /* Don't export attribs? */
499           if (!(options&EXPORT_ATTRIBUTES)
500               && node->pkt->pkttype == PKT_USER_ID
501               && node->pkt->pkt.user_id->attrib_data )
502             {
503               /* Skip until we get to something that is not an attrib
504                  or a signature on an attrib */
505               while (kbctx->next && kbctx->next->pkt->pkttype==PKT_SIGNATURE)
506                 kbctx = kbctx->next;
507  
508               continue;
509             }
510
511           if (secret == 2 && node->pkt->pkttype == PKT_SECRET_KEY)
512             {
513               /* We don't want to export the secret parts of the
514                * primary key, this is done by temporary switching to
515                * GNU protection mode 1001.  */
516               int save_mode = node->pkt->pkt.public_key->seckey_info->s2k.mode;
517               node->pkt->pkt.public_key->seckey_info->s2k.mode = 1001;
518               if ((options&EXPORT_SEXP_FORMAT))
519                 err = build_sexp (out, node->pkt, &indent);
520               else
521                 err = build_packet (out, node->pkt);
522               node->pkt->pkt.public_key->seckey_info->s2k.mode = save_mode;
523             }
524           else if (secret == 2 && node->pkt->pkttype == PKT_SECRET_SUBKEY
525                    && (opt.export_options&EXPORT_RESET_SUBKEY_PASSWD))
526             {
527               /* If the subkey is protected reset the passphrase to
528                  export an unprotected subkey.  This feature is useful
529                  in cases of a subkey copied to an unattended machine
530                  where a passphrase is not required. */
531               err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
532               goto leave;
533 #warning We need to implement this              
534               /* PKT_secret_key *sk_save, *sk; */
535
536               /* sk_save = node->pkt->pkt.secret_key; */
537               /* sk = copy_secret_key (NULL, sk_save); */
538               /* node->pkt->pkt.secret_key = sk; */
539
540               /* log_info (_("about to export an unprotected subkey\n")); */
541               /* switch (is_secret_key_protected (sk)) */
542               /*   { */
543               /*   case -1: */
544               /*     err = gpg_error (GPG_ERR_PUBKEY_ALGO); */
545               /*     break; */
546               /*   case 0: */
547               /*     break; */
548               /*   default: */
549               /*     if (sk->protect.s2k.mode == 1001) */
550               /*       ; /\* No secret parts. *\/ */
551               /*     else if( sk->protect.s2k.mode == 1002 )  */
552               /*       ; /\* Card key stub. *\/ */
553               /*     else  */
554               /*       { */
555               /*         /\* err = check_secret_key( sk, 0 ); *\/ */
556               /*       } */
557               /*     break; */
558               /*   } */
559               /* if (err) */
560               /*   { */
561               /*     node->pkt->pkt.secret_key = sk_save; */
562               /*     free_secret_key (sk); */
563               /*     log_error (_("failed to unprotect the subkey: %s\n"), */
564               /*                g10_errstr (rc)); */
565               /*     goto leave; */
566               /*   } */
567
568               /* if ((options&EXPORT_SEXP_FORMAT)) */
569               /*   err = build_sexp (out, node->pkt, &indent); */
570               /* else */
571               /*   err = build_packet (out, node->pkt); */
572
573               /* node->pkt->pkt.secret_key = sk_save; */
574               /* free_secret_key (sk); */
575             }
576           else
577             {
578               /* Warn the user if the secret key or any of the secret
579                  subkeys are protected with SHA1 and we have
580                  simple_sk_checksum set. */
581               if (!sha1_warned && opt.simple_sk_checksum &&
582                   (node->pkt->pkttype == PKT_SECRET_KEY
583                    || node->pkt->pkttype == PKT_SECRET_SUBKEY)
584                   && node->pkt->pkt.public_key->seckey_info->sha1chk)
585                 {
586                   /* I hope this warning doesn't confuse people. */
587                   log_info(_("WARNING: secret key %s does not have a "
588                              "simple SK checksum\n"), keystr (keyid));
589
590                   sha1_warned = 1;
591                 }
592
593               if ((options&EXPORT_SEXP_FORMAT))
594                 err = build_sexp (out, node->pkt, &indent);
595               else
596                 err = build_packet (out, node->pkt);
597             }
598
599           if (err)
600             {
601               log_error ("build_packet(%d) failed: %s\n",
602                          node->pkt->pkttype, gpg_strerror (err));
603               goto leave;
604             }
605         }
606
607       if ((options&EXPORT_SEXP_FORMAT) && indent)
608         {
609           for (; indent; indent--)
610             iobuf_put (out, ')');
611           iobuf_put (out, '\n');
612         }
613
614       ++*any;
615       if(keyblock_out)
616         {
617           *keyblock_out=keyblock;
618           break;
619         }
620     }
621   if ((options&EXPORT_SEXP_FORMAT) && indent)
622     {
623       for (; indent; indent--)
624         iobuf_put (out, ')');
625       iobuf_put (out, '\n');
626     }
627   if( err == -1 )
628     err = 0;
629
630  leave:
631   release_subkey_list (subkey_list);
632   xfree(desc);
633   keydb_release (kdbhd);
634   if (err || !keyblock_out)
635     release_kbnode( keyblock );
636   if( !*any )
637     log_info(_("WARNING: nothing exported\n"));
638   return err;
639 }
640
641
642
643 /* static int */
644 /* write_sexp_line (iobuf_t out, int *indent, const char *text) */
645 /* { */
646 /*   int i; */
647
648 /*   for (i=0; i < *indent; i++) */
649 /*     iobuf_put (out, ' '); */
650 /*   iobuf_writestr (out, text); */
651 /*   return 0; */
652 /* } */
653
654 /* static int */
655 /* write_sexp_keyparm (iobuf_t out, int *indent, const char *name, gcry_mpi_t a) */
656 /* { */
657 /*   int rc; */
658 /*   unsigned char *buffer; */
659
660 /*   write_sexp_line (out, indent, "("); */
661 /*   iobuf_writestr (out, name); */
662 /*   iobuf_writestr (out, " #"); */
663
664 /*   rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, a); */
665 /*   assert (!rc); */
666 /*   iobuf_writestr (out, buffer); */
667 /*   iobuf_writestr (out, "#)"); */
668 /*   gcry_free (buffer); */
669 /*   return 0; */
670 /* } */
671
672 static int
673 build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent)
674 {
675   /* FIXME: Not yet implemented.  */
676   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
677   /* PKT_secret_key *sk = pkt->pkt.secret_key; */
678   /* char tmpbuf[100]; */
679
680   /* if (pkt->pkttype == PKT_SECRET_KEY) */
681   /*   { */
682   /*     iobuf_writestr (out, "(openpgp-key\n"); */
683   /*     (*indent)++; */
684   /*   } */
685   /* else */
686   /*   { */
687   /*     iobuf_writestr (out, " (subkey\n"); */
688   /*     (*indent)++; */
689   /*   } */
690   /* (*indent)++; */
691   /* write_sexp_line (out, indent, "(private-key\n"); */
692   /* (*indent)++; */
693   /* if (is_RSA (sk->pubkey_algo) && !sk->is_protected) */
694   /*   { */
695   /*     write_sexp_line (out, indent, "(rsa\n"); */
696   /*     (*indent)++; */
697   /*     write_sexp_keyparm (out, indent, "n", sk->skey[0]); iobuf_put (out,'\n'); */
698   /*     write_sexp_keyparm (out, indent, "e", sk->skey[1]); iobuf_put (out,'\n'); */
699   /*     write_sexp_keyparm (out, indent, "d", sk->skey[2]); iobuf_put (out,'\n'); */
700   /*     write_sexp_keyparm (out, indent, "p", sk->skey[3]); iobuf_put (out,'\n'); */
701   /*     write_sexp_keyparm (out, indent, "q", sk->skey[4]); iobuf_put (out,'\n'); */
702   /*     write_sexp_keyparm (out, indent, "u", sk->skey[5]);  */
703   /*     iobuf_put (out,')'); iobuf_put (out,'\n'); */
704   /*     (*indent)--; */
705   /*   } */
706   /* else if (sk->pubkey_algo == PUBKEY_ALGO_DSA && !sk->is_protected) */
707   /*   { */
708   /*     write_sexp_line (out, indent, "(dsa\n"); */
709   /*     (*indent)++; */
710   /*     write_sexp_keyparm (out, indent, "p", sk->skey[0]); iobuf_put (out,'\n'); */
711   /*     write_sexp_keyparm (out, indent, "q", sk->skey[1]); iobuf_put (out,'\n'); */
712   /*     write_sexp_keyparm (out, indent, "g", sk->skey[2]); iobuf_put (out,'\n'); */
713   /*     write_sexp_keyparm (out, indent, "y", sk->skey[3]); iobuf_put (out,'\n'); */
714   /*     write_sexp_keyparm (out, indent, "x", sk->skey[4]); */
715   /*     iobuf_put (out,')'); iobuf_put (out,'\n'); */
716   /*     (*indent)--; */
717   /*   } */
718   /* else if (is_ELGAMAL (sk->pubkey_algo) && !sk->is_protected) */
719   /*   { */
720   /*     write_sexp_line (out, indent, "(elg\n"); */
721   /*     (*indent)++; */
722   /*     write_sexp_keyparm (out, indent, "p", sk->skey[0]); iobuf_put (out,'\n'); */
723   /*     write_sexp_keyparm (out, indent, "g", sk->skey[2]); iobuf_put (out,'\n'); */
724   /*     write_sexp_keyparm (out, indent, "y", sk->skey[3]); iobuf_put (out,'\n'); */
725   /*     write_sexp_keyparm (out, indent, "x", sk->skey[4]); */
726   /*     iobuf_put (out,')'); iobuf_put (out,'\n'); */
727   /*     (*indent)--; */
728   /*   } */
729   /* write_sexp_line (out, indent,  "(attrib\n"); (*indent)++; */
730   /* sprintf (tmpbuf, "(created \"%lu\"", (unsigned long)sk->timestamp); */
731   /* write_sexp_line (out, indent, tmpbuf); */
732   /* iobuf_put (out,')'); (*indent)--; /\* close created *\/ */
733   /* iobuf_put (out,')'); (*indent)--; /\* close attrib *\/ */
734   /* iobuf_put (out,')'); (*indent)--; /\* close private-key *\/ */
735   /* if (pkt->pkttype != PKT_SECRET_KEY) */
736   /*   iobuf_put (out,')'), (*indent)--; /\* close subkey *\/ */
737   /* iobuf_put (out,'\n'); */
738
739   /* return 0; */
740 }
741
742
743 /* For some packet types we write them in a S-expression format.  This
744    is still EXPERIMENTAL and subject to change.  */
745 static int 
746 build_sexp (iobuf_t out, PACKET *pkt, int *indent)
747 {
748   int rc;
749
750   switch (pkt->pkttype)
751     {
752     case PKT_SECRET_KEY:
753     case PKT_SECRET_SUBKEY:
754       rc = build_sexp_seckey (out, pkt, indent);
755       break;
756     default:
757       rc = 0;
758       break;
759     }
760   return rc;
761 }
762