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