afc7fd7f976dad69b4c68c930d0bf1549260956b
[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 2 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, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20  * USA.
21  */
22
23 #include <config.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <assert.h>
29
30 #include "gpg.h"
31 #include "options.h"
32 #include "packet.h"
33 #include "errors.h"
34 #include "keydb.h"
35 #include "util.h"
36 #include "main.h"
37 #include "i18n.h"
38 #include "trustdb.h"
39
40
41 /* An object to keep track of subkeys. */
42 struct subkey_list_s
43 {
44   struct subkey_list_s *next;
45   u32 kid[2];
46 };
47 typedef struct subkey_list_s *subkey_list_t;
48
49
50 static int do_export( strlist_t users, int secret, unsigned int options );
51 static int do_export_stream( IOBUF out, strlist_t users, int secret,
52                              KBNODE *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-reset-subkey-passwd",EXPORT_RESET_SUBKEY_PASSWD,NULL,
69        N_("remove the passphrase from exported subkeys")},
70       {"export-clean",EXPORT_CLEAN,NULL,
71        N_("remove unusable parts from key during export")},
72       {"export-minimal",EXPORT_MINIMAL|EXPORT_CLEAN,NULL,
73        N_("remove as much as possible from key during export")},
74       {"export-sexp-format",EXPORT_SEXP_FORMAT, NULL,
75        N_("export keys in an S-expression based format")},
76       /* Aliases for backward compatibility */
77       {"include-local-sigs",EXPORT_LOCAL_SIGS,NULL,NULL},
78       {"include-attributes",EXPORT_ATTRIBUTES,NULL,NULL},
79       {"include-sensitive-revkeys",EXPORT_SENSITIVE_REVKEYS,NULL,NULL},
80       /* dummy */
81       {"export-unusable-sigs",0,NULL,NULL},
82       {"export-clean-sigs",0,NULL,NULL},
83       {"export-clean-uids",0,NULL,NULL},
84       {NULL,0,NULL,NULL}
85       /* add tags for include revoked and disabled? */
86     };
87
88   return parse_options(str,options,export_opts,noisy);
89 }
90
91
92 /****************
93  * Export the public keys (to standard out or --output).
94  * Depending on opt.armor the output is armored.
95  * options are defined in main.h.
96  * If USERS is NULL, the complete ring will be exported.  */
97 int
98 export_pubkeys( strlist_t users, unsigned int options )
99 {
100     return do_export( users, 0, options );
101 }
102
103 /****************
104  * Export to an already opened stream; return -1 if no keys have
105  * been exported
106  */
107 int
108 export_pubkeys_stream( IOBUF out, strlist_t users,
109                        KBNODE *keyblock_out, unsigned int options )
110 {
111     int any, rc;
112
113     rc = do_export_stream( out, users, 0, keyblock_out, options, &any );
114     if( !rc && !any )
115         rc = -1;
116     return rc;
117 }
118
119 int
120 export_seckeys( strlist_t users )
121 {
122   /* Use only relevant options for the secret key. */
123   unsigned int options = (opt.export_options & EXPORT_SEXP_FORMAT);
124   return do_export( users, 1, options );
125 }
126
127 int
128 export_secsubkeys( strlist_t users )
129 {
130   /* Use only relevant options for the secret key. */
131   unsigned int options = (opt.export_options & EXPORT_SEXP_FORMAT);
132   return do_export( users, 2, options );
133 }
134
135 static int
136 do_export( strlist_t users, int secret, unsigned int options )
137 {
138   IOBUF out = NULL;
139   int any, rc;
140   armor_filter_context_t afx;
141   compress_filter_context_t zfx;
142   
143   memset( &afx, 0, sizeof afx);
144   memset( &zfx, 0, sizeof zfx);
145   
146   rc = open_outfile( NULL, 0, &out );
147   if (rc)
148     return rc;
149
150   if (!(options & EXPORT_SEXP_FORMAT))
151     {
152       if ( opt.armor )
153         {
154           afx.what = secret?5:1;
155           iobuf_push_filter ( out, armor_filter, &afx );
156         }
157       if ( opt.compress_keys )
158         push_compress_filter (out,&zfx,default_compress_algo());
159     }
160
161   rc = do_export_stream ( out, users, secret, NULL, options, &any );
162
163   if ( rc || !any )
164     iobuf_cancel (out);
165   else
166     iobuf_close (out);
167   return rc;
168 }
169
170
171
172 /* Release an entire subkey list. */
173 static void
174 release_subkey_list (subkey_list_t list)
175 {
176   while (list)
177     {
178       subkey_list_t tmp = list->next;;
179       xfree (list);
180       list = tmp;
181     }
182 }
183
184
185 /* Returns true if NODE is a subkey and contained in LIST. */
186 static int
187 subkey_in_list_p (subkey_list_t list, KBNODE node)
188 {
189   if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
190       || node->pkt->pkttype == PKT_SECRET_SUBKEY )
191     {
192       u32 kid[2];
193
194       if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
195         keyid_from_pk (node->pkt->pkt.public_key, kid);
196       else
197         keyid_from_sk (node->pkt->pkt.secret_key, kid);
198       
199       for (; list; list = list->next)
200         if (list->kid[0] == kid[0] && list->kid[1] == kid[1])
201           return 1;
202     }
203   return 0;
204 }
205
206 /* Allocate a new subkey list item from NODE. */
207 static subkey_list_t
208 new_subkey_list_item (KBNODE node)
209 {
210   subkey_list_t list = xcalloc (1, sizeof *list);
211
212   if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
213     keyid_from_pk (node->pkt->pkt.public_key, list->kid);
214   else if (node->pkt->pkttype == PKT_SECRET_SUBKEY)
215     keyid_from_sk (node->pkt->pkt.secret_key, list->kid);
216
217   return list;
218 }
219
220
221 /* Helper function to check whether the subkey at NODE actually
222    matches the description at DESC.  The function returns true if the
223    key under question has been specified by an exact specification
224    (keyID or fingerprint) and does match the one at NODE.  It is
225    assumed that the packet at NODE is either a public or secret
226    subkey. */
227 static int
228 exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node)
229 {
230   u32 kid[2];
231   byte fpr[MAX_FINGERPRINT_LEN];
232   size_t fprlen;
233   int result = 0;
234
235   switch(desc->mode)
236     {
237     case KEYDB_SEARCH_MODE_SHORT_KID:
238     case KEYDB_SEARCH_MODE_LONG_KID:
239       if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
240         keyid_from_pk (node->pkt->pkt.public_key, kid);
241       else
242         keyid_from_sk (node->pkt->pkt.secret_key, kid);
243       break;
244       
245     case KEYDB_SEARCH_MODE_FPR16:
246     case KEYDB_SEARCH_MODE_FPR20:
247     case KEYDB_SEARCH_MODE_FPR:
248       if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
249         fingerprint_from_pk (node->pkt->pkt.public_key, fpr,&fprlen);
250       else
251         fingerprint_from_sk (node->pkt->pkt.secret_key, fpr,&fprlen);
252       break;
253       
254     default:
255       break;
256     }
257   
258   switch(desc->mode)
259     {
260     case KEYDB_SEARCH_MODE_SHORT_KID:
261       if (desc->u.kid[1] == kid[1])
262         result = 1;
263       break;
264
265     case KEYDB_SEARCH_MODE_LONG_KID:
266       if (desc->u.kid[0] == kid[0] && desc->u.kid[1] == kid[1])
267         result = 1;
268       break;
269
270     case KEYDB_SEARCH_MODE_FPR16:
271       if (!memcmp (desc->u.fpr, fpr, 16))
272         result = 1;
273       break;
274
275     case KEYDB_SEARCH_MODE_FPR20:
276     case KEYDB_SEARCH_MODE_FPR:
277       if (!memcmp (desc->u.fpr, fpr, 20))
278         result = 1;
279       break;
280
281     default:
282       break;
283     }
284
285   return result;
286 }
287
288
289 /* If keyblock_out is non-NULL, AND the exit code is zero, then it
290    contains a pointer to the first keyblock found and exported.  No
291    other keyblocks are exported.  The caller must free it. */
292 static int
293 do_export_stream( IOBUF out, strlist_t users, int secret,
294                   KBNODE *keyblock_out, unsigned int options, int *any )
295 {
296     int rc = 0;
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 (classify_user_id (sl->d, desc+ndesc))
323                 ndesc++;
324             else
325                 log_error (_("key \"%s\" not found: %s\n"),
326                            sl->d, g10_errstr (G10ERR_INV_USER_ID));
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                 rc = build_packet (out, node->pkt);
567
568                 node->pkt->pkt.secret_key = sk_save;
569                 free_secret_key (sk);
570               }
571             else
572               {
573                 /* Warn the user if the secret key or any of the secret
574                    subkeys are protected with SHA1 and we have
575                    simple_sk_checksum set. */
576                 if(!sha1_warned && opt.simple_sk_checksum &&
577                    (node->pkt->pkttype==PKT_SECRET_KEY ||
578                     node->pkt->pkttype==PKT_SECRET_SUBKEY) &&
579                    node->pkt->pkt.secret_key->protect.sha1chk)
580                   {
581                     /* I hope this warning doesn't confuse people. */
582                     log_info(_("WARNING: secret key %s does not have a "
583                                "simple SK checksum\n"),keystr(sk_keyid));
584
585                     sha1_warned=1;
586                   }
587
588                 if ((options&EXPORT_SEXP_FORMAT))
589                   rc = build_sexp (out, node->pkt, &indent);
590                 else
591                   rc = build_packet (out, node->pkt);
592               }
593
594             if( rc ) {
595                 log_error("build_packet(%d) failed: %s\n",
596                             node->pkt->pkttype, g10_errstr(rc) );
597                 goto leave;
598             }
599         }
600
601         if ((options&EXPORT_SEXP_FORMAT) && indent)
602           {
603             for (; indent; indent--)
604               iobuf_put (out, ')');
605             iobuf_put (out, '\n');
606           }
607
608         ++*any;
609         if(keyblock_out)
610           {
611             *keyblock_out=keyblock;
612             break;
613           }
614     }
615     if ((options&EXPORT_SEXP_FORMAT) && indent)
616       {
617         for (; indent; indent--)
618           iobuf_put (out, ')');
619         iobuf_put (out, '\n');
620       }
621     if( rc == -1 )
622         rc = 0;
623
624   leave:
625     release_subkey_list (subkey_list);
626     xfree(desc);
627     keydb_release (kdbhd);
628     if(rc || keyblock_out==NULL)
629       release_kbnode( keyblock );
630     if( !*any )
631         log_info(_("WARNING: nothing exported\n"));
632     return rc;
633 }
634
635
636
637 static int
638 write_sexp_line (iobuf_t out, int *indent, const char *text)
639 {
640   int i;
641
642   for (i=0; i < *indent; i++)
643     iobuf_put (out, ' ');
644   iobuf_writestr (out, text);
645   return 0;
646 }
647
648 static int
649 write_sexp_keyparm (iobuf_t out, int *indent, const char *name, gcry_mpi_t a)
650 {
651   int rc;
652   unsigned char *buffer;
653
654   write_sexp_line (out, indent, "(");
655   iobuf_writestr (out, name);
656   iobuf_writestr (out, " #");
657
658   rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, a);
659   assert (!rc);
660   iobuf_writestr (out, buffer);
661   iobuf_writestr (out, "#)");
662   gcry_free (buffer);
663   return 0;
664 }
665
666 static int
667 build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent)
668 {
669   PKT_secret_key *sk = pkt->pkt.secret_key;
670   char tmpbuf[100];
671
672   if (pkt->pkttype == PKT_SECRET_KEY)
673     {
674       iobuf_writestr (out, "(openpgp-key\n");
675       (*indent)++;
676     }
677   else
678     {
679       iobuf_writestr (out, " (subkey\n");
680       (*indent)++;
681     }
682   (*indent)++;
683   write_sexp_line (out, indent, "(private-key\n");
684   (*indent)++;
685   if (is_RSA (sk->pubkey_algo) && !sk->is_protected)
686     {
687       write_sexp_line (out, indent, "(rsa\n");
688       (*indent)++;
689       write_sexp_keyparm (out, indent, "n", sk->skey[0]); iobuf_put (out,'\n');
690       write_sexp_keyparm (out, indent, "e", sk->skey[1]); iobuf_put (out,'\n');
691       write_sexp_keyparm (out, indent, "d", sk->skey[2]); iobuf_put (out,'\n');
692       write_sexp_keyparm (out, indent, "p", sk->skey[3]); iobuf_put (out,'\n');
693       write_sexp_keyparm (out, indent, "q", sk->skey[4]); iobuf_put (out,'\n');
694       write_sexp_keyparm (out, indent, "u", sk->skey[5]); 
695       iobuf_put (out,')'); iobuf_put (out,'\n');
696       (*indent)--;
697     }
698   else if (sk->pubkey_algo == PUBKEY_ALGO_DSA && !sk->is_protected)
699     {
700       write_sexp_line (out, indent, "(dsa\n");
701       (*indent)++;
702       write_sexp_keyparm (out, indent, "p", sk->skey[0]); iobuf_put (out,'\n');
703       write_sexp_keyparm (out, indent, "q", sk->skey[1]); iobuf_put (out,'\n');
704       write_sexp_keyparm (out, indent, "g", sk->skey[2]); iobuf_put (out,'\n');
705       write_sexp_keyparm (out, indent, "y", sk->skey[3]); iobuf_put (out,'\n');
706       write_sexp_keyparm (out, indent, "x", sk->skey[4]);
707       iobuf_put (out,')'); iobuf_put (out,'\n');
708       (*indent)--;
709     }
710   else if (is_ELGAMAL (sk->pubkey_algo) && !sk->is_protected)
711     {
712       write_sexp_line (out, indent, "(elg\n");
713       (*indent)++;
714       write_sexp_keyparm (out, indent, "p", sk->skey[0]); iobuf_put (out,'\n');
715       write_sexp_keyparm (out, indent, "g", sk->skey[2]); iobuf_put (out,'\n');
716       write_sexp_keyparm (out, indent, "y", sk->skey[3]); iobuf_put (out,'\n');
717       write_sexp_keyparm (out, indent, "x", sk->skey[4]);
718       iobuf_put (out,')'); iobuf_put (out,'\n');
719       (*indent)--;
720     }
721   write_sexp_line (out, indent,  "(attrib\n"); (*indent)++;
722   sprintf (tmpbuf, "(created \"%lu\"", (unsigned long)sk->timestamp);
723   write_sexp_line (out, indent, tmpbuf);
724   iobuf_put (out,')'); (*indent)--; /* close created */
725   iobuf_put (out,')'); (*indent)--; /* close attrib */
726   iobuf_put (out,')'); (*indent)--; /* close private-key */
727   if (pkt->pkttype != PKT_SECRET_KEY)
728     iobuf_put (out,')'), (*indent)--; /* close subkey */
729   iobuf_put (out,'\n');
730
731   return 0;
732 }
733
734
735 /* For some packet types we write them in a S-expression format.  This
736    is still EXPERIMENTAL and subject to change.  */
737 static int 
738 build_sexp (iobuf_t out, PACKET *pkt, int *indent)
739 {
740   int rc;
741
742   switch (pkt->pkttype)
743     {
744     case PKT_SECRET_KEY:
745     case PKT_SECRET_SUBKEY:
746       rc = build_sexp_seckey (out, pkt, indent);
747       break;
748     default:
749       rc = 0;
750       break;
751     }
752   return rc;
753 }
754