Add psktool to @direntry. Alphasort @direntry.
[gnutls.git] / lib / opencdk / write-packet.c
blob35b6b0f50c177305caf94cc20c7c1875c953bade
1 /* write-packet.c - Write OpenPGP packets
2 * Copyright (C) 2001, 2002, 2003, 2007, 2008 Free Software Foundation, Inc.
4 * Author: Timo Schulz
6 * This file is part of OpenCDK.
8 * The OpenCDK library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21 * USA
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 #include <string.h>
28 #include <stdio.h>
29 #include <assert.h>
31 #include "opencdk.h"
32 #include "main.h"
35 static int
36 stream_write (cdk_stream_t s, const void *buf, size_t buflen)
38 int nwritten;
40 nwritten = cdk_stream_write (s, buf, buflen);
41 if (nwritten == EOF)
42 return _cdk_stream_get_errno (s);
43 return 0;
47 static int
48 stream_read (cdk_stream_t s, void *buf, size_t buflen, size_t *r_nread)
50 int nread;
52 assert (r_nread);
54 nread = cdk_stream_read (s, buf, buflen);
55 if (nread == EOF)
56 return _cdk_stream_get_errno (s);
57 *r_nread = nread;
58 return 0;
62 static int
63 stream_putc (cdk_stream_t s, int c)
65 int nwritten = cdk_stream_putc (s, c);
66 if (nwritten == EOF)
67 return _cdk_stream_get_errno (s);
68 return 0;
72 static int
73 write_32 (cdk_stream_t out, u32 u)
75 byte buf[4];
77 buf[0] = u >> 24;
78 buf[1] = u >> 16;
79 buf[2] = u >> 8;
80 buf[3] = u;
81 return stream_write (out, buf, 4);
85 static int
86 write_16 (cdk_stream_t out, u16 u)
88 byte buf[2];
90 buf[0] = u >> 8;
91 buf[1] = u;
92 return stream_write (out, buf, 2);
96 static size_t
97 calc_mpisize (gcry_mpi_t mpi[MAX_CDK_PK_PARTS], size_t ncount)
99 size_t size, i;
101 size = 0;
102 for (i = 0; i < ncount; i++)
103 size += (gcry_mpi_get_nbits (mpi[i]) + 7) / 8 + 2;
104 return size;
108 static int
109 write_mpi (cdk_stream_t out, gcry_mpi_t m)
111 byte buf[MAX_MPI_BYTES+2];
112 size_t nbits, nread;
113 gcry_error_t err;
115 if (!out || !m)
116 return CDK_Inv_Value;
117 nbits = gcry_mpi_get_nbits (m);
118 if (nbits > MAX_MPI_BITS || nbits < 1)
119 return CDK_MPI_Error;
120 err = gcry_mpi_print (GCRYMPI_FMT_PGP, buf, MAX_MPI_BYTES+2, &nread, m);
121 if (err)
122 return map_gcry_error (err);
123 return stream_write (out, buf, nread);
127 static cdk_error_t
128 write_mpibuf (cdk_stream_t out, gcry_mpi_t mpi[MAX_CDK_PK_PARTS], size_t count)
130 size_t i;
131 cdk_error_t rc;
133 for (i = 0; i < count; i++)
135 rc = write_mpi (out, mpi[i]);
136 if (rc)
137 return rc;
139 return 0;
143 static cdk_error_t
144 pkt_encode_len (cdk_stream_t out, size_t pktlen)
146 cdk_error_t rc;
148 assert (out);
150 rc = 0;
151 if (!pktlen)
153 /* Block mode, partial bodies, with 'DEF_BLOCKSIZE' from main.h */
154 rc = stream_putc( out, (0xE0|DEF_BLOCKBITS) );
156 else if (pktlen < 192)
157 rc = stream_putc (out, pktlen);
158 else if (pktlen < 8384)
160 pktlen -= 192;
161 rc = stream_putc (out, (pktlen / 256) + 192);
162 if (!rc)
163 rc = stream_putc (out, (pktlen % 256));
165 else
167 rc = stream_putc (out, 255);
168 if (!rc)
169 rc = write_32 (out, pktlen);
172 return rc;
176 static cdk_error_t
177 write_head_new (cdk_stream_t out, size_t size, int type)
179 cdk_error_t rc;
181 assert (out);
183 if (type < 0 || type > 63)
184 return CDK_Inv_Packet;
185 rc = stream_putc (out, (0xC0 | type));
186 if (!rc)
187 rc = pkt_encode_len (out, size);
188 return rc;
192 static cdk_error_t
193 write_head_old (cdk_stream_t out, size_t size, int type)
195 cdk_error_t rc;
196 int ctb;
198 assert (out);
200 if (type < 0 || type > 16)
201 return CDK_Inv_Packet;
202 ctb = 0x80 | (type << 2);
203 if (!size)
204 ctb |= 3;
205 else if (size < 256)
207 else if (size < 65536)
208 ctb |= 1;
209 else
210 ctb |= 2;
211 rc = stream_putc (out, ctb);
212 if (!size)
213 return rc;
214 if (!rc)
216 if (size < 256)
217 rc = stream_putc (out, size);
218 else if (size < 65536)
219 rc = write_16 (out, size);
220 else
221 rc = write_32 (out, size);
224 return rc;
228 /* Write special PGP2 packet header. PGP2 (wrongly) uses two byte header
229 length for signatures and keys even if the size is < 256. */
230 static cdk_error_t
231 pkt_write_head2 (cdk_stream_t out, size_t size, int type)
233 cdk_error_t rc;
235 rc = cdk_stream_putc (out, 0x80 | (type << 2) | 1);
236 if (!rc)
237 rc = cdk_stream_putc (out, size >> 8);
238 if (!rc)
239 rc = cdk_stream_putc (out, size & 0xff);
240 return rc;
244 static int
245 pkt_write_head (cdk_stream_t out, int old_ctb, size_t size, int type)
247 if (old_ctb)
248 return write_head_old (out, size, type);
249 return write_head_new (out, size, type);
253 static cdk_error_t
254 write_encrypted (cdk_stream_t out, cdk_pkt_encrypted_t enc, int old_ctb)
256 size_t nbytes;
257 cdk_error_t rc;
259 assert (out);
260 assert (enc);
262 if (DEBUG_PKT)
263 _cdk_log_debug ("write_encrypted: %lu bytes\n", enc->len);
265 nbytes = enc->len ? (enc->len + enc->extralen) : 0;
266 rc = pkt_write_head (out, old_ctb, nbytes, CDK_PKT_ENCRYPTED);
267 /* The rest of the packet is ciphertext */
268 return rc;
272 static int
273 write_encrypted_mdc (cdk_stream_t out, cdk_pkt_encrypted_t enc)
275 size_t nbytes;
276 cdk_error_t rc;
278 assert (out);
279 assert (enc);
281 if (!enc->mdc_method)
282 return CDK_Inv_Packet;
284 if (DEBUG_PKT)
285 _cdk_log_debug ("write_encrypted_mdc: %lu bytes\n", enc->len);
287 nbytes = enc->len ? (enc->len + enc->extralen + 1) : 0;
288 rc = pkt_write_head (out, 0, nbytes, CDK_PKT_ENCRYPTED_MDC);
289 if (!rc)
290 rc = stream_putc (out, 1); /* version */
291 /* The rest of the packet is ciphertext */
292 return rc;
296 static cdk_error_t
297 write_symkey_enc (cdk_stream_t out, cdk_pkt_symkey_enc_t ske)
299 cdk_s2k_t s2k;
300 size_t size = 0, s2k_size = 0;
301 cdk_error_t rc;
303 assert (out);
304 assert (ske);
306 if (ske->version != 4)
307 return CDK_Inv_Packet;
309 if (DEBUG_PKT)
310 _cdk_log_debug ("write_symkey_enc:\n");
312 s2k = ske->s2k;
313 if (s2k->mode == CDK_S2K_SALTED || s2k->mode == CDK_S2K_ITERSALTED)
314 s2k_size = 8;
315 if (s2k->mode == CDK_S2K_ITERSALTED)
316 s2k_size++;
317 size = 4 + s2k_size + ske->seskeylen;
318 rc = pkt_write_head (out, 0, size, CDK_PKT_SYMKEY_ENC);
319 if (!rc)
320 rc = stream_putc (out, ske->version);
321 if (!rc)
322 rc = stream_putc (out, ske->cipher_algo);
323 if (!rc)
324 rc = stream_putc (out, s2k->mode);
325 if (!rc)
326 rc = stream_putc (out, s2k->hash_algo);
327 if (s2k->mode == CDK_S2K_SALTED || s2k->mode == CDK_S2K_ITERSALTED)
329 rc = stream_write (out, s2k->salt, 8);
330 if (!rc)
332 if (s2k->mode == CDK_S2K_ITERSALTED)
333 rc = stream_putc (out, s2k->count);
336 return rc;
340 static int
341 write_pubkey_enc (cdk_stream_t out, cdk_pkt_pubkey_enc_t pke, int old_ctb)
343 size_t size;
344 int rc, nenc;
346 assert (out);
347 assert (pke);
349 if (pke->version < 2 || pke->version > 3)
350 return CDK_Inv_Packet;
351 if (!KEY_CAN_ENCRYPT (pke->pubkey_algo))
352 return CDK_Inv_Algo;
354 if (DEBUG_PKT)
355 _cdk_log_debug ("write_pubkey_enc:\n");
357 nenc = cdk_pk_get_nenc (pke->pubkey_algo);
358 size = 10 + calc_mpisize (pke->mpi, nenc);
359 rc = pkt_write_head (out, old_ctb, size, CDK_PKT_PUBKEY_ENC);
360 if (rc)
361 return rc;
363 rc = stream_putc (out, pke->version);
364 if (!rc)
365 rc = write_32 (out, pke->keyid[0]);
366 if (!rc)
367 rc = write_32 (out, pke->keyid[1]);
368 if (!rc)
369 rc = stream_putc (out, pke->pubkey_algo);
370 if (!rc)
371 rc = write_mpibuf (out, pke->mpi, nenc);
372 return rc;
376 static cdk_error_t
377 write_mdc (cdk_stream_t out, cdk_pkt_mdc_t mdc)
379 cdk_error_t rc;
381 assert (mdc);
382 assert (out);
384 if (DEBUG_PKT)
385 _cdk_log_debug ("write_mdc:\n");
387 /* This packet requires a fixed header encoding */
388 rc = stream_putc (out, 0xD3); /* packet ID and 1 byte length */
389 if (!rc)
390 rc = stream_putc (out, 0x14);
391 if (!rc)
392 rc = stream_write (out, mdc->hash, DIM (mdc->hash));
393 return rc;
397 static size_t
398 calc_subpktsize (cdk_subpkt_t s)
400 size_t nbytes;
402 /* In the count mode, no buffer is returned. */
403 _cdk_subpkt_get_array (s, 1, &nbytes);
404 return nbytes;
408 static cdk_error_t
409 write_v3_sig (cdk_stream_t out, cdk_pkt_signature_t sig, int nsig)
411 size_t size;
412 cdk_error_t rc;
414 size = 19 + calc_mpisize (sig->mpi, nsig);
415 if (is_RSA (sig->pubkey_algo))
416 rc = pkt_write_head2 (out, size, CDK_PKT_SIGNATURE);
417 else
418 rc = pkt_write_head (out, 1, size, CDK_PKT_SIGNATURE);
419 if (!rc)
420 rc = stream_putc (out, sig->version);
421 if (!rc)
422 rc = stream_putc (out, 5);
423 if (!rc)
424 rc = stream_putc (out, sig->sig_class);
425 if (!rc)
426 rc = write_32 (out, sig->timestamp);
427 if (!rc)
428 rc = write_32 (out, sig->keyid[0]);
429 if (!rc)
430 rc = write_32 (out, sig->keyid[1]);
431 if (!rc)
432 rc = stream_putc (out, sig->pubkey_algo);
433 if (!rc)
434 rc = stream_putc (out, sig->digest_algo);
435 if (!rc)
436 rc = stream_putc (out, sig->digest_start[0]);
437 if (!rc)
438 rc = stream_putc (out, sig->digest_start[1]);
439 if (!rc)
440 rc = write_mpibuf (out, sig->mpi, nsig);
441 return rc;
445 static cdk_error_t
446 write_signature (cdk_stream_t out, cdk_pkt_signature_t sig, int old_ctb)
448 byte *buf;
449 size_t nbytes, size, nsig;
450 cdk_error_t rc;
452 assert (out);
453 assert (sig);
455 if (!KEY_CAN_SIGN (sig->pubkey_algo))
456 return CDK_Inv_Algo;
457 if (sig->version < 2 || sig->version > 4)
458 return CDK_Inv_Packet;
460 if (DEBUG_PKT)
461 _cdk_log_debug ("write_signature:\n");
463 nsig = cdk_pk_get_nsig (sig->pubkey_algo);
464 if (!nsig)
465 return CDK_Inv_Algo;
466 if (sig->version < 4)
467 return write_v3_sig (out, sig, nsig);
469 size = 10 + calc_subpktsize (sig->hashed)
470 + calc_subpktsize (sig->unhashed)
471 + calc_mpisize (sig->mpi, nsig);
472 rc = pkt_write_head (out, 0, size, CDK_PKT_SIGNATURE);
473 if (!rc)
474 rc = stream_putc (out, 4);
475 if (!rc)
476 rc = stream_putc (out, sig->sig_class);
477 if (!rc)
478 rc = stream_putc (out, sig->pubkey_algo);
479 if (!rc)
480 rc = stream_putc (out, sig->digest_algo);
481 if (!rc)
482 rc = write_16 (out, sig->hashed_size);
483 if (!rc)
485 buf = _cdk_subpkt_get_array (sig->hashed, 0, &nbytes);
486 if (!buf)
487 return CDK_Out_Of_Core;
488 rc = stream_write (out, buf, nbytes);
489 cdk_free (buf);
491 if (!rc)
492 rc = write_16 (out, sig->unhashed_size);
493 if (!rc)
495 buf = _cdk_subpkt_get_array (sig->unhashed, 0, &nbytes);
496 if (!buf)
497 return CDK_Out_Of_Core;
498 rc = stream_write (out, buf, nbytes);
499 cdk_free (buf);
501 if (!rc)
502 rc = stream_putc (out, sig->digest_start[0]);
503 if (!rc)
504 rc = stream_putc (out, sig->digest_start[1]);
505 if (!rc)
506 rc = write_mpibuf (out, sig->mpi, nsig);
507 return rc;
511 static cdk_error_t
512 write_public_key (cdk_stream_t out, cdk_pkt_pubkey_t pk,
513 int is_subkey, int old_ctb)
515 int pkttype, ndays = 0;
516 size_t npkey = 0, size = 6;
517 cdk_error_t rc;
519 assert (out);
520 assert (pk);
522 if (pk->version < 2 || pk->version > 4)
523 return CDK_Inv_Packet;
525 if (DEBUG_PKT)
526 _cdk_log_debug ("write_public_key: subkey=%d\n", is_subkey);
528 pkttype = is_subkey? CDK_PKT_PUBLIC_SUBKEY : CDK_PKT_PUBLIC_KEY;
529 npkey = cdk_pk_get_npkey (pk->pubkey_algo);
530 if (!npkey)
531 return CDK_Inv_Algo;
532 if (pk->version < 4)
533 size += 2; /* expire date */
534 if (is_subkey)
535 old_ctb = 0;
536 size += calc_mpisize (pk->mpi, npkey);
537 if (old_ctb)
538 rc = pkt_write_head2 (out, size, pkttype);
539 else
540 rc = pkt_write_head (out, old_ctb, size, pkttype);
541 if (!rc)
542 rc = stream_putc (out, pk->version);
543 if (!rc)
544 rc = write_32 (out, pk->timestamp);
545 if (!rc && pk->version < 4)
547 if (pk->expiredate)
548 ndays = (u16) ((pk->expiredate - pk->timestamp) / 86400L);
549 rc = write_16 (out, ndays);
551 if (!rc)
552 rc = stream_putc (out, pk->pubkey_algo);
553 if (!rc)
554 rc = write_mpibuf (out, pk->mpi, npkey);
555 return rc;
559 static int
560 calc_s2ksize (cdk_pkt_seckey_t sk)
562 size_t nbytes = 0;
564 if (!sk->is_protected)
565 return 0;
566 switch (sk->protect.s2k->mode)
568 case CDK_S2K_SIMPLE : nbytes = 2; break;
569 case CDK_S2K_SALTED : nbytes = 10; break;
570 case CDK_S2K_ITERSALTED: nbytes = 11; break;
572 nbytes += sk->protect.ivlen;
573 nbytes++; /* single cipher byte */
574 return nbytes;
578 static cdk_error_t
579 write_secret_key( cdk_stream_t out, cdk_pkt_seckey_t sk,
580 int is_subkey, int old_ctb )
582 cdk_pkt_pubkey_t pk = NULL;
583 size_t size = 6, npkey, nskey;
584 int pkttype, s2k_mode;
585 cdk_error_t rc;
587 assert (out);
588 assert (sk);
590 if (!sk->pk)
591 return CDK_Inv_Value;
592 pk = sk->pk;
593 if (pk->version < 2 || pk->version > 4)
594 return CDK_Inv_Packet;
596 if (DEBUG_PKT)
597 _cdk_log_debug ("write_secret_key:\n");
599 npkey = cdk_pk_get_npkey (pk->pubkey_algo);
600 nskey = cdk_pk_get_nskey (pk->pubkey_algo);
601 if (!npkey || !nskey)
602 return CDK_Inv_Algo;
603 if (pk->version < 4)
604 size += 2;
605 /* If the key is unprotected, the 1 extra byte:
606 1 octet - cipher algorithm byte (0x00)
607 the other bytes depend on the mode:
608 a) simple checksum - 2 octets
609 b) sha-1 checksum - 20 octets */
610 size = !sk->is_protected? size + 1 : size + 1 + calc_s2ksize (sk);
611 size += calc_mpisize (pk->mpi, npkey);
612 if (sk->version == 3 || !sk->is_protected)
614 if (sk->version == 3)
616 size += 2; /* force simple checksum */
617 sk->protect.sha1chk = 0;
619 else
620 size += sk->protect.sha1chk? 20 : 2;
621 size += calc_mpisize (sk->mpi, nskey);
623 else /* We do not know anything about the encrypted mpi's so we
624 treat the data as opaque. */
625 size += sk->enclen;
627 pkttype = is_subkey? CDK_PKT_SECRET_SUBKEY : CDK_PKT_SECRET_KEY;
628 rc = pkt_write_head (out, old_ctb, size, pkttype);
629 if (!rc)
630 rc = stream_putc (out, pk->version);
631 if (!rc)
632 rc = write_32 (out, pk->timestamp);
633 if (!rc && pk->version < 4)
635 u16 ndays = 0;
636 if (pk->expiredate)
637 ndays = (u16) ((pk->expiredate - pk->timestamp) / 86400L);
638 rc = write_16 (out, ndays);
640 if (!rc)
641 rc = stream_putc (out, pk->pubkey_algo);
642 if( !rc )
643 rc = write_mpibuf (out, pk->mpi, npkey);
644 if (sk->is_protected == 0)
645 rc = stream_putc (out, 0x00);
646 else
648 if (is_RSA (pk->pubkey_algo) && pk->version < 4)
649 stream_putc (out, sk->protect.algo);
650 else if (sk->protect.s2k)
652 s2k_mode = sk->protect.s2k->mode;
653 rc = stream_putc (out, sk->protect.sha1chk? 0xFE : 0xFF);
654 if (!rc)
655 rc = stream_putc (out, sk->protect.algo);
656 if (!rc)
657 rc = stream_putc (out, sk->protect.s2k->mode);
658 if (!rc)
659 rc = stream_putc( out, sk->protect.s2k->hash_algo);
660 if (!rc && (s2k_mode == 1 || s2k_mode == 3))
662 rc = stream_write (out, sk->protect.s2k->salt, 8);
663 if (!rc && s2k_mode == 3)
664 rc = stream_putc (out, sk->protect.s2k->count);
667 else
668 return CDK_Inv_Value;
669 rc = stream_write (out, sk->protect.iv, sk->protect.ivlen);
671 if (!rc && sk->is_protected && pk->version == 4)
673 if (sk->encdata && sk->enclen)
674 rc = stream_write (out, sk->encdata, sk->enclen);
676 else
678 if (!rc)
679 rc = write_mpibuf (out, sk->mpi, nskey);
680 if (!rc)
682 if (!sk->csum)
683 sk->csum = _cdk_sk_get_csum (sk);
684 rc = write_16 (out, sk->csum);
688 return rc;
692 static cdk_error_t
693 write_compressed (cdk_stream_t out, cdk_pkt_compressed_t cd )
695 cdk_error_t rc;
697 assert (out);
698 assert (cd);
700 if (DEBUG_PKT)
701 _cdk_log_debug ("packet: write_compressed\n");
703 /* Use an old (RFC1991) header for this packet. */
704 rc = pkt_write_head (out, 1, 0, CDK_PKT_COMPRESSED);
705 if (!rc)
706 rc = stream_putc (out, cd->algorithm);
707 return rc;
711 static cdk_error_t
712 write_literal (cdk_stream_t out, cdk_pkt_literal_t pt, int old_ctb)
714 byte buf[BUFSIZE];
715 size_t size;
716 cdk_error_t rc;
718 assert (out);
719 assert (pt);
721 /* We consider a packet without a body as an invalid packet.
722 At least one octet must be present. */
723 if (!pt->len)
724 return CDK_Inv_Packet;
726 if (DEBUG_PKT)
727 _cdk_log_debug ("write_literal:\n");
729 size = 6 + pt->namelen + pt->len;
730 rc = pkt_write_head (out, old_ctb, size, CDK_PKT_LITERAL);
731 if (rc)
732 return rc;
734 rc = stream_putc (out, pt->mode);
735 if (rc)
736 return rc;
737 rc = stream_putc (out, pt->namelen);
738 if (rc)
739 return rc;
741 if (pt->namelen > 0)
742 rc = stream_write (out, pt->name, pt->namelen);
743 if (!rc)
744 rc = write_32 (out, pt->timestamp);
745 if (rc)
746 return rc;
748 while (!cdk_stream_eof (pt->buf) && !rc)
750 rc = stream_read (pt->buf, buf, DIM (buf), &size);
751 if (!rc)
752 rc = stream_write (out, buf, size);
755 wipemem (buf, sizeof (buf));
756 return rc;
760 static cdk_error_t
761 write_onepass_sig (cdk_stream_t out, cdk_pkt_onepass_sig_t sig)
763 cdk_error_t rc;
765 assert (out);
766 assert (sig);
768 if (sig->version != 3)
769 return CDK_Inv_Packet;
771 if (DEBUG_PKT)
772 _cdk_log_debug ("write_onepass_sig:\n");
774 rc = pkt_write_head (out, 0, 13, CDK_PKT_ONEPASS_SIG);
775 if (!rc)
776 rc = stream_putc (out, sig->version);
777 if (!rc)
778 rc = stream_putc (out, sig->sig_class);
779 if (!rc)
780 rc = stream_putc (out, sig->digest_algo);
781 if (!rc)
782 rc = stream_putc (out, sig->pubkey_algo);
783 if (!rc)
784 rc = write_32 (out, sig->keyid[0]);
785 if (!rc)
786 rc = write_32 (out, sig->keyid[1]);
787 if (!rc)
788 rc = stream_putc (out, sig->last);
789 return rc;
793 static cdk_error_t
794 write_user_id (cdk_stream_t out, cdk_pkt_userid_t id, int old_ctb, int pkttype)
796 cdk_error_t rc;
798 if (!out || !id)
799 return CDK_Inv_Value;
801 if (pkttype == CDK_PKT_ATTRIBUTE)
803 if (!id->attrib_img)
804 return CDK_Inv_Value;
805 rc = pkt_write_head (out, old_ctb, id->attrib_len+6, CDK_PKT_ATTRIBUTE);
806 if (rc)
807 return rc;
808 /* Write subpacket part. */
809 stream_putc (out, 255);
810 write_32 (out, id->attrib_len+1);
811 stream_putc (out, 1);
812 rc = stream_write (out, id->attrib_img, id->attrib_len);
814 else
816 if (!id->name)
817 return CDK_Inv_Value;
818 rc = pkt_write_head (out, old_ctb, id->len, CDK_PKT_USER_ID);
819 if (!rc)
820 rc = stream_write (out, id->name, id->len);
823 return rc;
828 * cdk_pkt_write:
829 * @out: the output stream handle
830 * @pkt: the packet itself
832 * Write the contents of @pkt into the @out stream.
833 * Return 0 on success.
835 cdk_error_t
836 cdk_pkt_write (cdk_stream_t out, cdk_packet_t pkt)
838 cdk_error_t rc;
840 if (!out || !pkt)
841 return CDK_Inv_Value;
843 _cdk_log_debug ("write packet pkttype=%d\n", pkt->pkttype);
844 switch (pkt->pkttype)
846 case CDK_PKT_LITERAL:
847 rc = write_literal (out, pkt->pkt.literal, pkt->old_ctb);
848 break;
849 case CDK_PKT_ONEPASS_SIG:
850 rc = write_onepass_sig (out, pkt->pkt.onepass_sig);
851 break;
852 case CDK_PKT_MDC:
853 rc = write_mdc (out, pkt->pkt.mdc);
854 break;
855 case CDK_PKT_SYMKEY_ENC:
856 rc = write_symkey_enc (out, pkt->pkt.symkey_enc);
857 break;
858 case CDK_PKT_ENCRYPTED:
859 rc = write_encrypted (out, pkt->pkt.encrypted, pkt->old_ctb);
860 break;
861 case CDK_PKT_ENCRYPTED_MDC:
862 rc = write_encrypted_mdc (out, pkt->pkt.encrypted);
863 break;
864 case CDK_PKT_PUBKEY_ENC:
865 rc = write_pubkey_enc (out, pkt->pkt.pubkey_enc, pkt->old_ctb);
866 break;
867 case CDK_PKT_SIGNATURE:
868 rc = write_signature (out, pkt->pkt.signature, pkt->old_ctb);
869 break;
870 case CDK_PKT_PUBLIC_KEY:
871 rc = write_public_key (out, pkt->pkt.public_key, 0, pkt->old_ctb);
872 break;
873 case CDK_PKT_PUBLIC_SUBKEY:
874 rc = write_public_key (out, pkt->pkt.public_key, 1, pkt->old_ctb);
875 break;
876 case CDK_PKT_COMPRESSED:
877 rc = write_compressed (out, pkt->pkt.compressed);
878 break;
879 case CDK_PKT_SECRET_KEY:
880 rc = write_secret_key (out, pkt->pkt.secret_key, 0, pkt->old_ctb);
881 break;
882 case CDK_PKT_SECRET_SUBKEY:
883 rc = write_secret_key (out, pkt->pkt.secret_key, 1, pkt->old_ctb);
884 break;
885 case CDK_PKT_USER_ID:
886 case CDK_PKT_ATTRIBUTE:
887 rc = write_user_id (out, pkt->pkt.user_id, pkt->old_ctb, pkt->pkttype);
888 break;
889 default:
890 rc = CDK_Inv_Packet;
891 break;
894 if (DEBUG_PKT)
895 _cdk_log_debug ("write_packet rc=%d pkttype=%d\n", rc, pkt->pkttype);
896 return rc;
900 cdk_error_t
901 _cdk_pkt_write2 (cdk_stream_t out, int pkttype, void *pktctx)
903 cdk_packet_t pkt;
904 cdk_error_t rc;
906 rc = cdk_pkt_new (&pkt);
907 if (rc)
908 return rc;
910 switch (pkttype)
912 case CDK_PKT_PUBLIC_KEY:
913 case CDK_PKT_PUBLIC_SUBKEY:
914 pkt->pkt.public_key = pktctx;
915 break;
916 case CDK_PKT_SIGNATURE:
917 pkt->pkt.signature = pktctx;
918 break;
919 case CDK_PKT_SECRET_KEY:
920 case CDK_PKT_SECRET_SUBKEY:
921 pkt->pkt.secret_key = pktctx;
922 break;
924 case CDK_PKT_USER_ID:
925 pkt->pkt.user_id = pktctx;
926 break;
928 pkt->pkttype = pkttype;
929 rc = cdk_pkt_write (out, pkt);
930 cdk_free (pkt);
931 return rc;
935 cdk_error_t
936 _cdk_pkt_write_fp (FILE *out, cdk_packet_t pkt)
938 cdk_stream_t so;
939 cdk_error_t rc;
941 rc = _cdk_stream_fpopen (out, 1, &so);
942 if (rc)
943 return rc;
944 rc = cdk_pkt_write (so, pkt);
945 cdk_stream_close (so);
946 return rc;