1 /* write-packet.c - Write OpenPGP packets
2 * Copyright (C) 2001-2012 Free Software Foundation, Inc.
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 3 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 License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
35 stream_write (cdk_stream_t s
, const void *buf
, size_t buflen
)
39 nwritten
= cdk_stream_write (s
, buf
, buflen
);
41 return _cdk_stream_get_errno (s
);
47 stream_read (cdk_stream_t s
, void *buf
, size_t buflen
, size_t * r_nread
)
53 nread
= cdk_stream_read (s
, buf
, buflen
);
55 return _cdk_stream_get_errno (s
);
62 stream_putc (cdk_stream_t s
, int c
)
64 int nwritten
= cdk_stream_putc (s
, c
);
66 return _cdk_stream_get_errno (s
);
72 write_32 (cdk_stream_t out
, u32 u
)
80 return stream_write (out
, buf
, 4);
85 write_16 (cdk_stream_t out
, u16 u
)
91 return stream_write (out
, buf
, 2);
96 calc_mpisize (bigint_t mpi
[MAX_CDK_PK_PARTS
], size_t ncount
)
101 for (i
= 0; i
< ncount
; i
++)
102 size
+= (_gnutls_mpi_get_nbits (mpi
[i
]) + 7) / 8 + 2;
108 write_mpi (cdk_stream_t out
, bigint_t m
)
110 byte buf
[MAX_MPI_BYTES
+ 2];
115 return CDK_Inv_Value
;
116 nbits
= _gnutls_mpi_get_nbits (m
);
117 if (nbits
> MAX_MPI_BITS
|| nbits
< 1)
118 return CDK_MPI_Error
;
120 nread
= MAX_MPI_BYTES
+ 2;
121 err
= _gnutls_mpi_print_pgp (m
, buf
, &nread
);
123 return map_gnutls_error (err
);
124 return stream_write (out
, buf
, nread
);
129 write_mpibuf (cdk_stream_t out
, bigint_t mpi
[MAX_CDK_PK_PARTS
], size_t count
)
134 for (i
= 0; i
< count
; i
++)
136 rc
= write_mpi (out
, mpi
[i
]);
145 pkt_encode_len (cdk_stream_t out
, size_t pktlen
)
154 /* Block mode, partial bodies, with 'DEF_BLOCKSIZE' from main.h */
155 rc
= stream_putc (out
, (0xE0 | DEF_BLOCKBITS
));
157 else if (pktlen
< 192)
158 rc
= stream_putc (out
, pktlen
);
159 else if (pktlen
< 8384)
162 rc
= stream_putc (out
, (pktlen
/ 256) + 192);
164 rc
= stream_putc (out
, (pktlen
% 256));
168 rc
= stream_putc (out
, 255);
170 rc
= write_32 (out
, pktlen
);
178 write_head_new (cdk_stream_t out
, size_t size
, int type
)
184 if (type
< 0 || type
> 63)
185 return CDK_Inv_Packet
;
186 rc
= stream_putc (out
, (0xC0 | type
));
188 rc
= pkt_encode_len (out
, size
);
194 write_head_old (cdk_stream_t out
, size_t size
, int type
)
201 if (type
< 0 || type
> 16)
202 return CDK_Inv_Packet
;
203 ctb
= 0x80 | (type
<< 2);
208 else if (size
< 65536)
212 rc
= stream_putc (out
, ctb
);
218 rc
= stream_putc (out
, size
);
219 else if (size
< 65536)
220 rc
= write_16 (out
, size
);
222 rc
= write_32 (out
, size
);
229 /* Write special PGP2 packet header. PGP2 (wrongly) uses two byte header
230 length for signatures and keys even if the size is < 256. */
232 pkt_write_head2 (cdk_stream_t out
, size_t size
, int type
)
236 rc
= cdk_stream_putc (out
, 0x80 | (type
<< 2) | 1);
238 rc
= cdk_stream_putc (out
, size
>> 8);
240 rc
= cdk_stream_putc (out
, size
& 0xff);
246 pkt_write_head (cdk_stream_t out
, int old_ctb
, size_t size
, int type
)
249 return write_head_old (out
, size
, type
);
250 return write_head_new (out
, size
, type
);
255 write_pubkey_enc (cdk_stream_t out
, cdk_pkt_pubkey_enc_t pke
, int old_ctb
)
263 if (pke
->version
< 2 || pke
->version
> 3)
264 return CDK_Inv_Packet
;
265 if (!KEY_CAN_ENCRYPT (pke
->pubkey_algo
))
269 _gnutls_write_log ("write_pubkey_enc:\n");
271 nenc
= cdk_pk_get_nenc (pke
->pubkey_algo
);
272 size
= 10 + calc_mpisize (pke
->mpi
, nenc
);
273 rc
= pkt_write_head (out
, old_ctb
, size
, CDK_PKT_PUBKEY_ENC
);
277 rc
= stream_putc (out
, pke
->version
);
279 rc
= write_32 (out
, pke
->keyid
[0]);
281 rc
= write_32 (out
, pke
->keyid
[1]);
283 rc
= stream_putc (out
, _cdk_pub_algo_to_pgp (pke
->pubkey_algo
));
285 rc
= write_mpibuf (out
, pke
->mpi
, nenc
);
291 write_mdc (cdk_stream_t out
, cdk_pkt_mdc_t mdc
)
299 _gnutls_write_log ("write_mdc:\n");
301 /* This packet requires a fixed header encoding */
302 rc
= stream_putc (out
, 0xD3); /* packet ID and 1 byte length */
304 rc
= stream_putc (out
, 0x14);
306 rc
= stream_write (out
, mdc
->hash
, DIM (mdc
->hash
));
312 calc_subpktsize (cdk_subpkt_t s
)
316 /* In the count mode, no buffer is returned. */
317 _cdk_subpkt_get_array (s
, 1, &nbytes
);
323 write_v3_sig (cdk_stream_t out
, cdk_pkt_signature_t sig
, int nsig
)
328 size
= 19 + calc_mpisize (sig
->mpi
, nsig
);
329 if (is_RSA (sig
->pubkey_algo
))
330 rc
= pkt_write_head2 (out
, size
, CDK_PKT_SIGNATURE
);
332 rc
= pkt_write_head (out
, 1, size
, CDK_PKT_SIGNATURE
);
334 rc
= stream_putc (out
, sig
->version
);
336 rc
= stream_putc (out
, 5);
338 rc
= stream_putc (out
, sig
->sig_class
);
340 rc
= write_32 (out
, sig
->timestamp
);
342 rc
= write_32 (out
, sig
->keyid
[0]);
344 rc
= write_32 (out
, sig
->keyid
[1]);
346 rc
= stream_putc (out
, _cdk_pub_algo_to_pgp (sig
->pubkey_algo
));
348 rc
= stream_putc (out
, _gnutls_hash_algo_to_pgp (sig
->digest_algo
));
350 rc
= stream_putc (out
, sig
->digest_start
[0]);
352 rc
= stream_putc (out
, sig
->digest_start
[1]);
354 rc
= write_mpibuf (out
, sig
->mpi
, nsig
);
360 write_signature (cdk_stream_t out
, cdk_pkt_signature_t sig
, int old_ctb
)
363 size_t nbytes
, size
, nsig
;
369 if (!KEY_CAN_SIGN (sig
->pubkey_algo
))
371 if (sig
->version
< 2 || sig
->version
> 4)
372 return CDK_Inv_Packet
;
375 _gnutls_write_log ("write_signature:\n");
377 nsig
= cdk_pk_get_nsig (sig
->pubkey_algo
);
380 if (sig
->version
< 4)
381 return write_v3_sig (out
, sig
, nsig
);
383 size
= 10 + calc_subpktsize (sig
->hashed
)
384 + calc_subpktsize (sig
->unhashed
) + calc_mpisize (sig
->mpi
, nsig
);
385 rc
= pkt_write_head (out
, 0, size
, CDK_PKT_SIGNATURE
);
387 rc
= stream_putc (out
, 4);
389 rc
= stream_putc (out
, sig
->sig_class
);
391 rc
= stream_putc (out
, _cdk_pub_algo_to_pgp (sig
->pubkey_algo
));
393 rc
= stream_putc (out
, _gnutls_hash_algo_to_pgp (sig
->digest_algo
));
395 rc
= write_16 (out
, sig
->hashed_size
);
398 buf
= _cdk_subpkt_get_array (sig
->hashed
, 0, &nbytes
);
400 return CDK_Out_Of_Core
;
401 rc
= stream_write (out
, buf
, nbytes
);
405 rc
= write_16 (out
, sig
->unhashed_size
);
408 buf
= _cdk_subpkt_get_array (sig
->unhashed
, 0, &nbytes
);
410 return CDK_Out_Of_Core
;
411 rc
= stream_write (out
, buf
, nbytes
);
415 rc
= stream_putc (out
, sig
->digest_start
[0]);
417 rc
= stream_putc (out
, sig
->digest_start
[1]);
419 rc
= write_mpibuf (out
, sig
->mpi
, nsig
);
425 write_public_key (cdk_stream_t out
, cdk_pkt_pubkey_t pk
,
426 int is_subkey
, int old_ctb
)
428 int pkttype
, ndays
= 0;
429 size_t npkey
= 0, size
= 6;
435 if (pk
->version
< 2 || pk
->version
> 4)
436 return CDK_Inv_Packet
;
439 _gnutls_write_log ("write_public_key: subkey=%d\n", is_subkey
);
441 pkttype
= is_subkey
? CDK_PKT_PUBLIC_SUBKEY
: CDK_PKT_PUBLIC_KEY
;
442 npkey
= cdk_pk_get_npkey (pk
->pubkey_algo
);
446 size
+= 2; /* expire date */
449 size
+= calc_mpisize (pk
->mpi
, npkey
);
451 rc
= pkt_write_head2 (out
, size
, pkttype
);
453 rc
= pkt_write_head (out
, old_ctb
, size
, pkttype
);
455 rc
= stream_putc (out
, pk
->version
);
457 rc
= write_32 (out
, pk
->timestamp
);
458 if (!rc
&& pk
->version
< 4)
461 ndays
= (u16
) ((pk
->expiredate
- pk
->timestamp
) / 86400L);
462 rc
= write_16 (out
, ndays
);
465 rc
= stream_putc (out
, _cdk_pub_algo_to_pgp (pk
->pubkey_algo
));
467 rc
= write_mpibuf (out
, pk
->mpi
, npkey
);
473 calc_s2ksize (cdk_pkt_seckey_t sk
)
477 if (!sk
->is_protected
)
479 switch (sk
->protect
.s2k
->mode
)
487 case CDK_S2K_ITERSALTED
:
490 case CDK_S2K_GNU_EXT
:
494 nbytes
+= sk
->protect
.ivlen
;
495 nbytes
++; /* single cipher byte */
501 write_secret_key (cdk_stream_t out
, cdk_pkt_seckey_t sk
,
502 int is_subkey
, int old_ctb
)
504 cdk_pkt_pubkey_t pk
= NULL
;
505 size_t size
= 6, npkey
, nskey
;
506 int pkttype
, s2k_mode
;
513 return CDK_Inv_Value
;
515 if (pk
->version
< 2 || pk
->version
> 4)
516 return CDK_Inv_Packet
;
519 _gnutls_write_log ("write_secret_key:\n");
521 npkey
= cdk_pk_get_npkey (pk
->pubkey_algo
);
522 nskey
= cdk_pk_get_nskey (pk
->pubkey_algo
);
523 if (!npkey
|| !nskey
)
530 /* If the key is unprotected, the 1 extra byte:
531 1 octet - cipher algorithm byte (0x00)
532 the other bytes depend on the mode:
533 a) simple checksum - 2 octets
534 b) sha-1 checksum - 20 octets */
535 size
= !sk
->is_protected
? size
+ 1 : size
+ 1 + calc_s2ksize (sk
);
536 size
+= calc_mpisize (pk
->mpi
, npkey
);
537 if (sk
->version
== 3 || !sk
->is_protected
)
539 if (sk
->version
== 3)
541 size
+= 2; /* force simple checksum */
542 sk
->protect
.sha1chk
= 0;
545 size
+= sk
->protect
.sha1chk
? 20 : 2;
546 size
+= calc_mpisize (sk
->mpi
, nskey
);
548 else /* We do not know anything about the encrypted mpi's so we
549 treat the data as uint8_t. */
552 pkttype
= is_subkey
? CDK_PKT_SECRET_SUBKEY
: CDK_PKT_SECRET_KEY
;
553 rc
= pkt_write_head (out
, old_ctb
, size
, pkttype
);
555 rc
= stream_putc (out
, pk
->version
);
557 rc
= write_32 (out
, pk
->timestamp
);
558 if (!rc
&& pk
->version
< 4)
562 ndays
= (u16
) ((pk
->expiredate
- pk
->timestamp
) / 86400L);
563 rc
= write_16 (out
, ndays
);
566 rc
= stream_putc (out
, _cdk_pub_algo_to_pgp (pk
->pubkey_algo
));
569 rc
= write_mpibuf (out
, pk
->mpi
, npkey
);
573 if (sk
->is_protected
== 0)
574 rc
= stream_putc (out
, 0x00);
577 if (is_RSA (pk
->pubkey_algo
) && pk
->version
< 4)
578 rc
= stream_putc (out
, _gnutls_cipher_to_pgp (sk
->protect
.algo
));
579 else if (sk
->protect
.s2k
)
581 s2k_mode
= sk
->protect
.s2k
->mode
;
582 rc
= stream_putc (out
, sk
->protect
.sha1chk
? 0xFE : 0xFF);
585 stream_putc (out
, _gnutls_cipher_to_pgp (sk
->protect
.algo
));
587 rc
= stream_putc (out
, sk
->protect
.s2k
->mode
);
589 rc
= stream_putc (out
, sk
->protect
.s2k
->hash_algo
);
590 if (!rc
&& (s2k_mode
== 1 || s2k_mode
== 3))
592 rc
= stream_write (out
, sk
->protect
.s2k
->salt
, 8);
593 if (!rc
&& s2k_mode
== 3)
594 rc
= stream_putc (out
, sk
->protect
.s2k
->count
);
598 return CDK_Inv_Value
;
600 rc
= stream_write (out
, sk
->protect
.iv
, sk
->protect
.ivlen
);
603 if (!rc
&& sk
->is_protected
&& pk
->version
== 4)
605 if (sk
->encdata
&& sk
->enclen
)
606 rc
= stream_write (out
, sk
->encdata
, sk
->enclen
);
611 rc
= write_mpibuf (out
, sk
->mpi
, nskey
);
615 sk
->csum
= _cdk_sk_get_csum (sk
);
616 rc
= write_16 (out
, sk
->csum
);
625 write_compressed (cdk_stream_t out
, cdk_pkt_compressed_t cd
)
633 _gnutls_write_log ("packet: write_compressed\n");
635 /* Use an old (RFC1991) header for this packet. */
636 rc
= pkt_write_head (out
, 1, 0, CDK_PKT_COMPRESSED
);
638 rc
= stream_putc (out
, cd
->algorithm
);
644 write_literal (cdk_stream_t out
, cdk_pkt_literal_t pt
, int old_ctb
)
653 /* We consider a packet without a body as an invalid packet.
654 At least one octet must be present. */
656 return CDK_Inv_Packet
;
659 _gnutls_write_log ("write_literal:\n");
661 size
= 6 + pt
->namelen
+ pt
->len
;
662 rc
= pkt_write_head (out
, old_ctb
, size
, CDK_PKT_LITERAL
);
666 rc
= stream_putc (out
, pt
->mode
);
669 rc
= stream_putc (out
, pt
->namelen
);
674 rc
= stream_write (out
, pt
->name
, pt
->namelen
);
676 rc
= write_32 (out
, pt
->timestamp
);
680 while (!cdk_stream_eof (pt
->buf
) && !rc
)
682 rc
= stream_read (pt
->buf
, buf
, DIM (buf
), &size
);
684 rc
= stream_write (out
, buf
, size
);
687 memset (buf
, 0, sizeof (buf
));
693 write_onepass_sig (cdk_stream_t out
, cdk_pkt_onepass_sig_t sig
)
700 if (sig
->version
!= 3)
701 return CDK_Inv_Packet
;
704 _gnutls_write_log ("write_onepass_sig:\n");
706 rc
= pkt_write_head (out
, 0, 13, CDK_PKT_ONEPASS_SIG
);
708 rc
= stream_putc (out
, sig
->version
);
710 rc
= stream_putc (out
, sig
->sig_class
);
712 rc
= stream_putc (out
, _gnutls_hash_algo_to_pgp (sig
->digest_algo
));
714 rc
= stream_putc (out
, _cdk_pub_algo_to_pgp (sig
->pubkey_algo
));
716 rc
= write_32 (out
, sig
->keyid
[0]);
718 rc
= write_32 (out
, sig
->keyid
[1]);
720 rc
= stream_putc (out
, sig
->last
);
726 write_user_id (cdk_stream_t out
, cdk_pkt_userid_t id
, int old_ctb
,
732 return CDK_Inv_Value
;
734 if (pkttype
== CDK_PKT_ATTRIBUTE
)
737 return CDK_Inv_Value
;
739 pkt_write_head (out
, old_ctb
, id
->attrib_len
+ 6, CDK_PKT_ATTRIBUTE
);
742 /* Write subpacket part. */
743 stream_putc (out
, 255);
744 write_32 (out
, id
->attrib_len
+ 1);
745 stream_putc (out
, 1);
746 rc
= stream_write (out
, id
->attrib_img
, id
->attrib_len
);
751 return CDK_Inv_Value
;
752 rc
= pkt_write_head (out
, old_ctb
, id
->len
, CDK_PKT_USER_ID
);
754 rc
= stream_write (out
, id
->name
, id
->len
);
763 * @out: the output stream handle
764 * @pkt: the packet itself
766 * Write the contents of @pkt into the @out stream.
767 * Return 0 on success.
770 cdk_pkt_write (cdk_stream_t out
, cdk_packet_t pkt
)
775 return CDK_Inv_Value
;
777 _gnutls_write_log ("write packet pkttype=%d\n", pkt
->pkttype
);
778 switch (pkt
->pkttype
)
780 case CDK_PKT_LITERAL
:
781 rc
= write_literal (out
, pkt
->pkt
.literal
, pkt
->old_ctb
);
783 case CDK_PKT_ONEPASS_SIG
:
784 rc
= write_onepass_sig (out
, pkt
->pkt
.onepass_sig
);
787 rc
= write_mdc (out
, pkt
->pkt
.mdc
);
789 case CDK_PKT_PUBKEY_ENC
:
790 rc
= write_pubkey_enc (out
, pkt
->pkt
.pubkey_enc
, pkt
->old_ctb
);
792 case CDK_PKT_SIGNATURE
:
793 rc
= write_signature (out
, pkt
->pkt
.signature
, pkt
->old_ctb
);
795 case CDK_PKT_PUBLIC_KEY
:
796 rc
= write_public_key (out
, pkt
->pkt
.public_key
, 0, pkt
->old_ctb
);
798 case CDK_PKT_PUBLIC_SUBKEY
:
799 rc
= write_public_key (out
, pkt
->pkt
.public_key
, 1, pkt
->old_ctb
);
801 case CDK_PKT_COMPRESSED
:
802 rc
= write_compressed (out
, pkt
->pkt
.compressed
);
804 case CDK_PKT_SECRET_KEY
:
805 rc
= write_secret_key (out
, pkt
->pkt
.secret_key
, 0, pkt
->old_ctb
);
807 case CDK_PKT_SECRET_SUBKEY
:
808 rc
= write_secret_key (out
, pkt
->pkt
.secret_key
, 1, pkt
->old_ctb
);
810 case CDK_PKT_USER_ID
:
811 case CDK_PKT_ATTRIBUTE
:
812 rc
= write_user_id (out
, pkt
->pkt
.user_id
, pkt
->old_ctb
, pkt
->pkttype
);
820 _gnutls_write_log ("write_packet rc=%d pkttype=%d\n", rc
, pkt
->pkttype
);
826 _cdk_pkt_write2 (cdk_stream_t out
, int pkttype
, void *pktctx
)
831 rc
= cdk_pkt_new (&pkt
);
837 case CDK_PKT_PUBLIC_KEY
:
838 case CDK_PKT_PUBLIC_SUBKEY
:
839 pkt
->pkt
.public_key
= pktctx
;
841 case CDK_PKT_SIGNATURE
:
842 pkt
->pkt
.signature
= pktctx
;
844 case CDK_PKT_SECRET_KEY
:
845 case CDK_PKT_SECRET_SUBKEY
:
846 pkt
->pkt
.secret_key
= pktctx
;
849 case CDK_PKT_USER_ID
:
850 pkt
->pkt
.user_id
= pktctx
;
853 pkt
->pkttype
= pkttype
;
854 rc
= cdk_pkt_write (out
, pkt
);
861 _cdk_pkt_write_fp (FILE * out
, cdk_packet_t pkt
)
866 rc
= _cdk_stream_fpopen (out
, 1, &so
);
869 rc
= cdk_pkt_write (so
, pkt
);
870 cdk_stream_close (so
);