2006-09-06 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / g10 / export.c
blob2760ea0543084634f751663b1d1bb2b5bac307ec
1 /* export.c
2 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
3 * 2005 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
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.
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.
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.
23 #include <config.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <assert.h>
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"
41 /* An object to keep track of subkeys. */
42 struct subkey_list_s
44 struct subkey_list_s *next;
45 u32 kid[2];
47 typedef struct subkey_list_s *subkey_list_t;
50 static int do_export( STRLIST users, int secret, unsigned int options );
51 static int do_export_stream( IOBUF out, STRLIST 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);
57 int
58 parse_export_options(char *str,unsigned int *options,int noisy)
60 struct parse_options export_opts[]=
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? */
88 return parse_options(str,options,export_opts,noisy);
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 users, unsigned int options )
100 return do_export( users, 0, options );
103 /****************
104 * Export to an already opened stream; return -1 if no keys have
105 * been exported
108 export_pubkeys_stream( IOBUF out, STRLIST users,
109 KBNODE *keyblock_out, unsigned int options )
111 int any, rc;
113 rc = do_export_stream( out, users, 0, keyblock_out, options, &any );
114 if( !rc && !any )
115 rc = -1;
116 return rc;
120 export_seckeys( STRLIST users )
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 );
128 export_secsubkeys( STRLIST users )
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 );
135 static int
136 do_export( STRLIST users, int secret, unsigned int options )
138 IOBUF out = NULL;
139 int any, rc;
140 armor_filter_context_t afx;
141 compress_filter_context_t zfx;
143 memset( &afx, 0, sizeof afx);
144 memset( &zfx, 0, sizeof zfx);
146 rc = open_outfile( NULL, 0, &out );
147 if (rc)
148 return rc;
150 if (!(options & EXPORT_SEXP_FORMAT))
152 if ( opt.armor )
154 afx.what = secret?5:1;
155 iobuf_push_filter ( out, armor_filter, &afx );
157 if ( opt.compress_keys )
158 push_compress_filter (out,&zfx,default_compress_algo());
161 rc = do_export_stream ( out, users, secret, NULL, options, &any );
163 if ( rc || !any )
164 iobuf_cancel (out);
165 else
166 iobuf_close (out);
167 return rc;
172 /* Release an entire subkey list. */
173 static void
174 release_subkey_list (subkey_list_t list)
176 while (list)
178 subkey_list_t tmp = list->next;;
179 xfree (list);
180 list = tmp;
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)
189 if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
190 || node->pkt->pkttype == PKT_SECRET_SUBKEY )
192 u32 kid[2];
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);
199 for (; list; list = list->next)
200 if (list->kid[0] == kid[0] && list->kid[1] == kid[1])
201 return 1;
203 return 0;
206 /* Allocate a new subkey list item from NODE. */
207 static subkey_list_t
208 new_subkey_list_item (KBNODE node)
210 subkey_list_t list = xcalloc (1, sizeof *list);
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);
217 return list;
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)
230 u32 kid[2];
231 byte fpr[MAX_FINGERPRINT_LEN];
232 size_t fprlen;
233 int result = 0;
235 switch(desc->mode)
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;
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;
254 default:
255 break;
258 switch(desc->mode)
260 case KEYDB_SEARCH_MODE_SHORT_KID:
261 if (desc->u.kid[1] == kid[1])
262 result = 1;
263 break;
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;
270 case KEYDB_SEARCH_MODE_FPR16:
271 if (!memcmp (desc->u.fpr, fpr, 16))
272 result = 1;
273 break;
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;
281 default:
282 break;
285 return result;
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 users, int secret,
294 KBNODE *keyblock_out, unsigned int options, int *any )
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 sl;
305 int indent = 0;
307 *any = 0;
308 init_packet( &pkt );
309 kdbhd = keydb_new (secret);
311 if (!users) {
312 ndesc = 1;
313 desc = xcalloc ( ndesc, sizeof *desc );
314 desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
316 else {
317 for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
319 desc = xmalloc ( ndesc * sizeof *desc);
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));
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 */
337 #ifdef ENABLE_SELINUX_HACKS
338 if (secret) {
339 log_error (_("exporting secret keys not allowed\n"));
340 rc = G10ERR_GENERAL;
341 goto leave;
343 #endif
345 while (!(rc = keydb_search2 (kdbhd, desc, ndesc, &descindex))) {
346 int sha1_warned=0,skip_until_subkey=0;
347 u32 sk_keyid[2];
349 if (!users)
350 desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
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;
359 if((node=find_kbnode(keyblock,PKT_SECRET_KEY)))
361 PKT_secret_key *sk=node->pkt->pkt.secret_key;
363 keyid_from_sk(sk,sk_keyid);
365 /* We can't apply GNU mode 1001 on an unprotected key. */
366 if( secret == 2 && !sk->is_protected )
368 log_info(_("key %s: not protected - skipped\n"),
369 keystr(sk_keyid));
370 continue;
373 /* No v3 keys with GNU mode 1001. */
374 if( secret == 2 && sk->version == 3 )
376 log_info(_("key %s: PGP 2.x style key - skipped\n"),
377 keystr(sk_keyid));
378 continue;
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 )
387 log_info(_("key %s: key material on-card - skipped\n"),
388 keystr(sk_keyid));
389 continue;
392 else
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. */
400 if(options&EXPORT_CLEAN)
401 clean_key(keyblock,opt.verbose,options&EXPORT_MINIMAL,NULL,NULL);
404 /* And write it. */
405 for( kbctx=NULL; (node = walk_kbnode( keyblock, &kbctx, 0 )); ) {
406 if( skip_until_subkey )
408 if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY
409 || node->pkt->pkttype==PKT_SECRET_SUBKEY)
410 skip_until_subkey=0;
411 else
412 continue;
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;
421 /* Make sure that ring_trust packets never get exported. */
422 if (node->pkt->pkttype == PKT_RING_TRUST)
423 continue;
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))
432 if (!exact_subkey_match_p (desc+descindex, node))
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.
440 So the first step here is to check that list and
441 skip in any case if the key is in that list.
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
451 size_t j;
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. */
462 if(skip_until_subkey)
463 continue;
465 /* Mark this one as processed. */
467 subkey_list_t tmp = new_subkey_list_item (node);
468 tmp->next = subkey_list;
469 subkey_list = tmp;
473 if(node->pkt->pkttype==PKT_SIGNATURE)
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 */
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)
488 int i;
490 for(i=0;i<node->pkt->pkt.signature->numrevkeys;i++)
491 if(node->pkt->pkt.signature->revkey[i]->class & 0x40)
492 break;
494 if(i<node->pkt->pkt.signature->numrevkeys)
495 continue;
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;
509 continue;
512 if( secret == 2 && node->pkt->pkttype == PKT_SECRET_KEY )
514 /* We don't want to export the secret parts of the
515 * primary key, this is done by using GNU protection mode 1001
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;
525 else if (secret == 2 && node->pkt->pkttype == PKT_SECRET_SUBKEY
526 && (opt.export_options&EXPORT_RESET_SUBKEY_PASSWD))
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;
534 sk_save = node->pkt->pkt.secret_key;
535 sk = copy_secret_key (NULL, sk_save);
536 node->pkt->pkt.secret_key = sk;
538 log_info (_("about to export an unprotected subkey\n"));
539 switch (is_secret_key_protected (sk))
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
553 rc = check_secret_key( sk, 0 );
555 break;
557 if (rc)
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;
566 rc = build_packet (out, node->pkt);
568 node->pkt->pkt.secret_key = sk_save;
569 free_secret_key (sk);
571 else
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)
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));
585 sha1_warned=1;
588 if ((options&EXPORT_SEXP_FORMAT))
589 rc = build_sexp (out, node->pkt, &indent);
590 else
591 rc = build_packet (out, node->pkt);
594 if( rc ) {
595 log_error("build_packet(%d) failed: %s\n",
596 node->pkt->pkttype, g10_errstr(rc) );
597 goto leave;
601 if ((options&EXPORT_SEXP_FORMAT) && indent)
603 for (; indent; indent--)
604 iobuf_put (out, ')');
605 iobuf_put (out, '\n');
608 ++*any;
609 if(keyblock_out)
611 *keyblock_out=keyblock;
612 break;
615 if ((options&EXPORT_SEXP_FORMAT) && indent)
617 for (; indent; indent--)
618 iobuf_put (out, ')');
619 iobuf_put (out, '\n');
621 if( rc == -1 )
622 rc = 0;
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;
637 static int
638 write_sexp_line (iobuf_t out, int *indent, const char *text)
640 int i;
642 for (i=0; i < *indent; i++)
643 iobuf_put (out, ' ');
644 iobuf_writestr (out, text);
645 return 0;
648 static int
649 write_sexp_keyparm (iobuf_t out, int *indent, const char *name, gcry_mpi_t a)
651 int rc;
652 unsigned char *buffer;
654 write_sexp_line (out, indent, "(");
655 iobuf_writestr (out, name);
656 iobuf_writestr (out, " #");
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;
666 static int
667 build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent)
669 PKT_secret_key *sk = pkt->pkt.secret_key;
670 char tmpbuf[100];
672 if (pkt->pkttype == PKT_SECRET_KEY)
674 iobuf_writestr (out, "(openpgp-key\n");
675 (*indent)++;
677 else
679 iobuf_writestr (out, " (subkey\n");
680 (*indent)++;
682 (*indent)++;
683 write_sexp_line (out, indent, "(private-key\n");
684 (*indent)++;
685 if (is_RSA (sk->pubkey_algo) && !sk->is_protected)
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)--;
698 else if (sk->pubkey_algo == PUBKEY_ALGO_DSA && !sk->is_protected)
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)--;
710 else if (is_ELGAMAL (sk->pubkey_algo) && !sk->is_protected)
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)--;
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');
731 return 0;
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)
740 int rc;
742 switch (pkt->pkttype)
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;
752 return rc;