Comment changes.
[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( 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     PACKET pkt;
297     KBNODE keyblock = NULL;
298     KBNODE kbctx, node;
299     size_t ndesc, descindex;
300     KEYDB_SEARCH_DESC *desc = NULL;
301     subkey_list_t subkey_list = NULL;  /* Track alreay processed subkeys. */
302     KEYDB_HANDLE kdbhd;
303     strlist_t sl;
304     int indent = 0;
305
306     *any = 0;
307     init_packet( &pkt );
308     kdbhd = keydb_new (secret);
309
310     if (!users) {
311         ndesc = 1;
312         desc = xcalloc ( ndesc, sizeof *desc );
313         desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
314     }
315     else {
316         for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++) 
317             ;
318         desc = xmalloc ( ndesc * sizeof *desc);
319         
320         for (ndesc=0, sl=users; sl; sl = sl->next) {
321             if (classify_user_id (sl->d, desc+ndesc))
322                 ndesc++;
323             else
324                 log_error (_("key \"%s\" not found: %s\n"),
325                            sl->d, g10_errstr (G10ERR_INV_USER_ID));
326         }
327
328         /* It would be nice to see which of the given users did
329            actually match one in the keyring.  To implement this we
330            need to have a found flag for each entry in desc and to set
331            this we must check all those entries after a match to mark
332            all matched one - currently we stop at the first match.  To
333            do this we need an extra flag to enable this feature so */
334     }
335
336 #ifdef ENABLE_SELINUX_HACKS
337     if (secret) {
338         log_error (_("exporting secret keys not allowed\n"));
339         rc = G10ERR_GENERAL;
340         goto leave;
341     }
342 #endif
343
344     while (!(rc = keydb_search2 (kdbhd, desc, ndesc, &descindex))) {
345         int sha1_warned=0,skip_until_subkey=0;
346         u32 sk_keyid[2];
347
348         if (!users) 
349             desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
350
351         /* Read the keyblock. */
352         rc = keydb_get_keyblock (kdbhd, &keyblock );
353         if( rc ) {
354             log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
355             goto leave;
356         }
357
358         if((node=find_kbnode(keyblock,PKT_SECRET_KEY)))
359           {
360             PKT_secret_key *sk=node->pkt->pkt.secret_key;
361
362             keyid_from_sk(sk,sk_keyid);
363
364             /* We can't apply GNU mode 1001 on an unprotected key. */
365             if( secret == 2 && !sk->is_protected )
366               {
367                 log_info(_("key %s: not protected - skipped\n"),
368                          keystr(sk_keyid));
369                 continue;
370               }
371
372             /* No v3 keys with GNU mode 1001. */
373             if( secret == 2 && sk->version == 3 )
374               {
375                 log_info(_("key %s: PGP 2.x style key - skipped\n"),
376                          keystr(sk_keyid));
377                 continue;
378               }
379
380             /* It does not make sense to export a key with a primary
381                key on card using a non-key stub.  We simply skip those
382                keys when used with --export-secret-subkeys. */
383             if (secret == 2 && sk->is_protected
384                 && sk->protect.s2k.mode == 1002 ) 
385               {
386                 log_info(_("key %s: key material on-card - skipped\n"),
387                          keystr(sk_keyid));
388                 continue;
389               }
390           }
391         else
392           {
393             /* It's a public key export, so do the cleaning if
394                requested.  Note that both export-clean and
395                export-minimal only apply to UID sigs (0x10, 0x11,
396                0x12, and 0x13).  A designated revocation is never
397                stripped, even with export-minimal set. */
398
399             if(options&EXPORT_CLEAN)
400               clean_key(keyblock,opt.verbose,options&EXPORT_MINIMAL,NULL,NULL);
401           }
402
403         /* And write it. */
404         for( kbctx=NULL; (node = walk_kbnode( keyblock, &kbctx, 0 )); ) {
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
445                        separate 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               /* Skip until we get to something that is not an attrib
503                  or a signature on an attrib */
504               while(kbctx->next && kbctx->next->pkt->pkttype==PKT_SIGNATURE) {
505                 kbctx=kbctx->next;
506               }
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 using GNU protection mode 1001
515                  */
516                 int save_mode = node->pkt->pkt.secret_key->protect.s2k.mode;
517                 node->pkt->pkt.secret_key->protect.s2k.mode = 1001;
518                 if ((options&EXPORT_SEXP_FORMAT))
519                   rc = build_sexp (out, node->pkt, &indent);
520                 else
521                   rc = build_packet (out, node->pkt);
522                 node->pkt->pkt.secret_key->protect.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
529                    useful in cases of a subkey copied to an unattended
530                    machine where a passphrase is not required. */
531                 PKT_secret_key *sk_save, *sk;
532
533                 sk_save = node->pkt->pkt.secret_key;
534                 sk = copy_secret_key (NULL, sk_save);
535                 node->pkt->pkt.secret_key = sk;
536
537                 log_info (_("about to export an unprotected subkey\n"));
538                 switch (is_secret_key_protected (sk))
539                   {
540                   case -1:
541                     rc = G10ERR_PUBKEY_ALGO;
542                     break;
543                   case 0:
544                     break;
545                   default:
546                     if (sk->protect.s2k.mode == 1001)
547                       ; /* No secret parts. */
548                     else if( sk->protect.s2k.mode == 1002 ) 
549                       ; /* Card key stub. */
550                     else 
551                       {
552                         rc = check_secret_key( sk, 0 );
553                       }
554                     break;
555                   }
556                 if (rc)
557                   {
558                     node->pkt->pkt.secret_key = sk_save;
559                     free_secret_key (sk);
560                     log_error (_("failed to unprotect the subkey: %s\n"),
561                                g10_errstr (rc));
562                     goto leave;
563                   }
564
565                 if ((options&EXPORT_SEXP_FORMAT))
566                   rc = build_sexp (out, node->pkt, &indent);
567                 else
568                   rc = build_packet (out, node->pkt);
569
570                 node->pkt->pkt.secret_key = sk_save;
571                 free_secret_key (sk);
572               }
573             else
574               {
575                 /* Warn the user if the secret key or any of the secret
576                    subkeys are protected with SHA1 and we have
577                    simple_sk_checksum set. */
578                 if(!sha1_warned && opt.simple_sk_checksum &&
579                    (node->pkt->pkttype==PKT_SECRET_KEY ||
580                     node->pkt->pkttype==PKT_SECRET_SUBKEY) &&
581                    node->pkt->pkt.secret_key->protect.sha1chk)
582                   {
583                     /* I hope this warning doesn't confuse people. */
584                     log_info(_("WARNING: secret key %s does not have a "
585                                "simple SK checksum\n"),keystr(sk_keyid));
586
587                     sha1_warned=1;
588                   }
589
590                 if ((options&EXPORT_SEXP_FORMAT))
591                   rc = build_sexp (out, node->pkt, &indent);
592                 else
593                   rc = build_packet (out, node->pkt);
594               }
595
596             if( rc ) {
597                 log_error("build_packet(%d) failed: %s\n",
598                             node->pkt->pkttype, g10_errstr(rc) );
599                 goto leave;
600             }
601         }
602
603         if ((options&EXPORT_SEXP_FORMAT) && indent)
604           {
605             for (; indent; indent--)
606               iobuf_put (out, ')');
607             iobuf_put (out, '\n');
608           }
609
610         ++*any;
611         if(keyblock_out)
612           {
613             *keyblock_out=keyblock;
614             break;
615           }
616     }
617     if ((options&EXPORT_SEXP_FORMAT) && indent)
618       {
619         for (; indent; indent--)
620           iobuf_put (out, ')');
621         iobuf_put (out, '\n');
622       }
623     if( rc == -1 )
624         rc = 0;
625
626   leave:
627     release_subkey_list (subkey_list);
628     xfree(desc);
629     keydb_release (kdbhd);
630     if(rc || keyblock_out==NULL)
631       release_kbnode( keyblock );
632     if( !*any )
633         log_info(_("WARNING: nothing exported\n"));
634     return rc;
635 }
636
637
638
639 static int
640 write_sexp_line (iobuf_t out, int *indent, const char *text)
641 {
642   int i;
643
644   for (i=0; i < *indent; i++)
645     iobuf_put (out, ' ');
646   iobuf_writestr (out, text);
647   return 0;
648 }
649
650 static int
651 write_sexp_keyparm (iobuf_t out, int *indent, const char *name, gcry_mpi_t a)
652 {
653   int rc;
654   unsigned char *buffer;
655
656   write_sexp_line (out, indent, "(");
657   iobuf_writestr (out, name);
658   iobuf_writestr (out, " #");
659
660   rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, a);
661   assert (!rc);
662   iobuf_writestr (out, buffer);
663   iobuf_writestr (out, "#)");
664   gcry_free (buffer);
665   return 0;
666 }
667
668 static int
669 build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent)
670 {
671   PKT_secret_key *sk = pkt->pkt.secret_key;
672   char tmpbuf[100];
673
674   if (pkt->pkttype == PKT_SECRET_KEY)
675     {
676       iobuf_writestr (out, "(openpgp-key\n");
677       (*indent)++;
678     }
679   else
680     {
681       iobuf_writestr (out, " (subkey\n");
682       (*indent)++;
683     }
684   (*indent)++;
685   write_sexp_line (out, indent, "(private-key\n");
686   (*indent)++;
687   if (is_RSA (sk->pubkey_algo) && !sk->is_protected)
688     {
689       write_sexp_line (out, indent, "(rsa\n");
690       (*indent)++;
691       write_sexp_keyparm (out, indent, "n", sk->skey[0]); iobuf_put (out,'\n');
692       write_sexp_keyparm (out, indent, "e", sk->skey[1]); iobuf_put (out,'\n');
693       write_sexp_keyparm (out, indent, "d", sk->skey[2]); iobuf_put (out,'\n');
694       write_sexp_keyparm (out, indent, "p", sk->skey[3]); iobuf_put (out,'\n');
695       write_sexp_keyparm (out, indent, "q", sk->skey[4]); iobuf_put (out,'\n');
696       write_sexp_keyparm (out, indent, "u", sk->skey[5]); 
697       iobuf_put (out,')'); iobuf_put (out,'\n');
698       (*indent)--;
699     }
700   else if (sk->pubkey_algo == PUBKEY_ALGO_DSA && !sk->is_protected)
701     {
702       write_sexp_line (out, indent, "(dsa\n");
703       (*indent)++;
704       write_sexp_keyparm (out, indent, "p", sk->skey[0]); iobuf_put (out,'\n');
705       write_sexp_keyparm (out, indent, "q", sk->skey[1]); iobuf_put (out,'\n');
706       write_sexp_keyparm (out, indent, "g", sk->skey[2]); iobuf_put (out,'\n');
707       write_sexp_keyparm (out, indent, "y", sk->skey[3]); iobuf_put (out,'\n');
708       write_sexp_keyparm (out, indent, "x", sk->skey[4]);
709       iobuf_put (out,')'); iobuf_put (out,'\n');
710       (*indent)--;
711     }
712   else if (is_ELGAMAL (sk->pubkey_algo) && !sk->is_protected)
713     {
714       write_sexp_line (out, indent, "(elg\n");
715       (*indent)++;
716       write_sexp_keyparm (out, indent, "p", sk->skey[0]); iobuf_put (out,'\n');
717       write_sexp_keyparm (out, indent, "g", sk->skey[2]); iobuf_put (out,'\n');
718       write_sexp_keyparm (out, indent, "y", sk->skey[3]); iobuf_put (out,'\n');
719       write_sexp_keyparm (out, indent, "x", sk->skey[4]);
720       iobuf_put (out,')'); iobuf_put (out,'\n');
721       (*indent)--;
722     }
723   write_sexp_line (out, indent,  "(attrib\n"); (*indent)++;
724   sprintf (tmpbuf, "(created \"%lu\"", (unsigned long)sk->timestamp);
725   write_sexp_line (out, indent, tmpbuf);
726   iobuf_put (out,')'); (*indent)--; /* close created */
727   iobuf_put (out,')'); (*indent)--; /* close attrib */
728   iobuf_put (out,')'); (*indent)--; /* close private-key */
729   if (pkt->pkttype != PKT_SECRET_KEY)
730     iobuf_put (out,')'), (*indent)--; /* close subkey */
731   iobuf_put (out,'\n');
732
733   return 0;
734 }
735
736
737 /* For some packet types we write them in a S-expression format.  This
738    is still EXPERIMENTAL and subject to change.  */
739 static int 
740 build_sexp (iobuf_t out, PACKET *pkt, int *indent)
741 {
742   int rc;
743
744   switch (pkt->pkttype)
745     {
746     case PKT_SECRET_KEY:
747     case PKT_SECRET_SUBKEY:
748       rc = build_sexp_seckey (out, pkt, indent);
749       break;
750     default:
751       rc = 0;
752       break;
753     }
754   return rc;
755 }
756