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