Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / crypto / external / bsd / netpgp / dist / src / lib / writer.c
blob988a77f9719dbeb9d70faa998a867d75ae869280
1 /*-
2 * Copyright (c) 2009 The NetBSD Foundation, Inc.
3 * All rights reserved.
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Alistair Crooks (agc@NetBSD.org)
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
30 * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
31 * All rights reserved.
32 * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
33 * their moral rights under the UK Copyright Design and Patents Act 1988 to
34 * be recorded as the authors of this copyright work.
36 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
37 * use this file except in compliance with the License.
39 * You may obtain a copy of the License at
40 * http://www.apache.org/licenses/LICENSE-2.0
42 * Unless required by applicable law or agreed to in writing, software
43 * distributed under the License is distributed on an "AS IS" BASIS,
44 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
46 * See the License for the specific language governing permissions and
47 * limitations under the License.
50 /** \file
51 * This file contains the base functions used by the writers.
53 #include "config.h"
55 #ifdef HAVE_SYS_CDEFS_H
56 #include <sys/cdefs.h>
57 #endif
59 #if defined(__NetBSD__)
60 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
61 __RCSID("$NetBSD: writer.c,v 1.15 2009/10/07 16:19:51 agc Exp $");
62 #endif
64 #include <sys/types.h>
66 #include <stdlib.h>
67 #include <string.h>
69 #ifdef HAVE_UNISTD_H
70 #include <unistd.h>
71 #endif
73 #ifdef HAVE_OPENSSL_CAST_H
74 #include <openssl/cast.h>
75 #endif
77 #include "create.h"
78 #include "writer.h"
79 #include "keyring.h"
80 #include "signature.h"
81 #include "packet.h"
82 #include "packet-parse.h"
83 #include "readerwriter.h"
84 #include "memory.h"
85 #include "netpgpdefs.h"
86 #include "version.h"
87 #include "netpgpdigest.h"
91 * return 1 if OK, otherwise 0
93 static unsigned
94 base_write(const void *src, unsigned len, __ops_output_t *out)
96 return out->writer.writer(src, len, &out->errors, &out->writer);
99 /**
100 * \ingroup Core_WritePackets
102 * \param src
103 * \param len
104 * \param output
105 * \return 1 if OK, otherwise 0
108 unsigned
109 __ops_write(__ops_output_t *output, const void *src, unsigned len)
111 return base_write(src, len, output);
115 * \ingroup Core_WritePackets
116 * \param n
117 * \param len
118 * \param output
119 * \return 1 if OK, otherwise 0
122 unsigned
123 __ops_write_scalar(__ops_output_t *output, unsigned n, unsigned len)
125 unsigned char c;
127 while (len-- > 0) {
128 c = n >> (len * 8);
129 if (!base_write(&c, 1, output)) {
130 return 0;
133 return 1;
137 * \ingroup Core_WritePackets
138 * \param bn
139 * \param output
140 * \return 1 if OK, otherwise 0
143 unsigned
144 __ops_write_mpi(__ops_output_t *output, const BIGNUM *bn)
146 unsigned char buf[NETPGP_BUFSIZ];
147 unsigned bits = (unsigned)BN_num_bits(bn);
149 if (bits > 65535) {
150 (void) fprintf(stderr, "__ops_write_mpi: too large %u\n", bits);
151 return 0;
153 BN_bn2bin(bn, buf);
154 return __ops_write_scalar(output, bits, 2) &&
155 __ops_write(output, buf, (bits + 7) / 8);
159 * \ingroup Core_WritePackets
160 * \param tag
161 * \param output
162 * \return 1 if OK, otherwise 0
165 unsigned
166 __ops_write_ptag(__ops_output_t *output, __ops_content_tag_t tag)
168 unsigned char c;
170 c = tag | OPS_PTAG_ALWAYS_SET | OPS_PTAG_NEW_FORMAT;
171 return base_write(&c, 1, output);
175 * \ingroup Core_WritePackets
176 * \param len
177 * \param output
178 * \return 1 if OK, otherwise 0
181 unsigned
182 __ops_write_length(__ops_output_t *output, unsigned len)
184 unsigned char c[2];
186 if (len < 192) {
187 c[0] = len;
188 return base_write(c, 1, output);
190 if (len < 8192 + 192) {
191 c[0] = ((len - 192) >> 8) + 192;
192 c[1] = (len - 192) % 256;
193 return base_write(c, 2, output);
195 return __ops_write_scalar(output, 0xff, 1) &&
196 __ops_write_scalar(output, len, 4);
200 * Note that we finalise from the top down, so we don't use writers below
201 * that have already been finalised
203 unsigned
204 writer_info_finalise(__ops_error_t **errors, __ops_writer_t *writer)
206 unsigned ret = 1;
208 if (writer->finaliser) {
209 ret = writer->finaliser(errors, writer);
210 writer->finaliser = NULL;
212 if (writer->next && !writer_info_finalise(errors, writer->next)) {
213 writer->finaliser = NULL;
214 return 0;
216 return ret;
219 void
220 writer_info_delete(__ops_writer_t *writer)
222 /* we should have finalised before deleting */
223 if (writer->finaliser) {
224 (void) fprintf(stderr, "writer_info_delete: not finalised\n");
225 return;
227 if (writer->next) {
228 writer_info_delete(writer->next);
229 free(writer->next);
230 writer->next = NULL;
232 if (writer->destroyer) {
233 writer->destroyer(writer);
234 writer->destroyer = NULL;
236 writer->writer = NULL;
240 * \ingroup Core_Writers
242 * Set a writer in output. There should not be another writer set.
244 * \param output The output structure
245 * \param writer
246 * \param finaliser
247 * \param destroyer
248 * \param arg The argument for the writer and destroyer
250 void
251 __ops_writer_set(__ops_output_t *output,
252 __ops_writer_func_t *writer,
253 __ops_writer_finaliser_t *finaliser,
254 __ops_writer_destroyer_t *destroyer,
255 void *arg)
257 if (output->writer.writer) {
258 (void) fprintf(stderr, "__ops_writer_set: already set\n");
259 } else {
260 output->writer.writer = writer;
261 output->writer.finaliser = finaliser;
262 output->writer.destroyer = destroyer;
263 output->writer.arg = arg;
268 * \ingroup Core_Writers
270 * Push a writer in output. There must already be another writer set.
272 * \param output The output structure
273 * \param writer
274 * \param finaliser
275 * \param destroyer
276 * \param arg The argument for the writer and destroyer
278 void
279 __ops_writer_push(__ops_output_t *output,
280 __ops_writer_func_t *writer,
281 __ops_writer_finaliser_t *finaliser,
282 __ops_writer_destroyer_t *destroyer,
283 void *arg)
285 __ops_writer_t *copy;
287 if ((copy = calloc(1, sizeof(*copy))) == NULL) {
288 (void) fprintf(stderr, "__ops_writer_push: bad alloc\n");
289 } else if (output->writer.writer == NULL) {
290 (void) fprintf(stderr, "__ops_writer_push: no orig writer\n");
291 } else {
292 *copy = output->writer;
293 output->writer.next = copy;
295 output->writer.writer = writer;
296 output->writer.finaliser = finaliser;
297 output->writer.destroyer = destroyer;
298 output->writer.arg = arg;
302 void
303 __ops_writer_pop(__ops_output_t *output)
305 __ops_writer_t *next;
307 /* Make sure the finaliser has been called. */
308 if (output->writer.finaliser) {
309 (void) fprintf(stderr,
310 "__ops_writer_pop: finaliser not called\n");
311 } else if (output->writer.next == NULL) {
312 (void) fprintf(stderr,
313 "__ops_writer_pop: not a stacked writer\n");
314 } else {
315 if (output->writer.destroyer) {
316 output->writer.destroyer(&output->writer);
318 next = output->writer.next;
319 output->writer = *next;
320 free(next);
325 * \ingroup Core_Writers
327 * Close the writer currently set in output.
329 * \param output The output structure
331 unsigned
332 __ops_writer_close(__ops_output_t *output)
334 unsigned ret = writer_info_finalise(&output->errors, &output->writer);
336 writer_info_delete(&output->writer);
337 return ret;
341 * \ingroup Core_Writers
343 * Get the arg supplied to __ops_createinfo_set_writer().
345 * \param writer The writer_info structure
346 * \return The arg
348 void *
349 __ops_writer_get_arg(__ops_writer_t *writer)
351 return writer->arg;
355 * \ingroup Core_Writers
357 * Write to the next writer down in the stack.
359 * \param src The data to write.
360 * \param len The length of src.
361 * \param errors A place to store errors.
362 * \param writer The writer_info structure.
363 * \return Success - if 0, then errors should contain the error.
365 unsigned
366 __ops_stacked_write(const void *src, unsigned len,
367 __ops_error_t ** errors, __ops_writer_t *writer)
369 return writer->next->writer(src, len, errors, writer->next);
373 * \ingroup Core_Writers
375 * Free the arg. Many writers just have a calloc()ed lump of storage, this
376 * function releases it.
378 * \param writer the info structure.
380 static void
381 generic_destroyer(__ops_writer_t *writer)
383 free(__ops_writer_get_arg(writer));
387 * \ingroup Core_Writers
389 * A writer that just writes to the next one down. Useful for when you
390 * want to insert just a finaliser into the stack.
392 unsigned
393 __ops_writer_passthrough(const unsigned char *src,
394 unsigned len,
395 __ops_error_t **errors,
396 __ops_writer_t *writer)
398 return __ops_stacked_write(src, len, errors, writer);
401 /**************************************************************************/
404 * \struct dashesc_t
406 typedef struct {
407 unsigned seen_nl:1;
408 unsigned seen_cr:1;
409 __ops_create_sig_t *sig;
410 __ops_memory_t *trailing;
411 } dashesc_t;
413 static unsigned
414 dash_esc_writer(const unsigned char *src,
415 unsigned len,
416 __ops_error_t **errors,
417 __ops_writer_t *writer)
419 dashesc_t *dash = __ops_writer_get_arg(writer);
420 unsigned n;
422 if (__ops_get_debug_level(__FILE__)) {
423 unsigned int i = 0;
425 (void) fprintf(stderr, "dash_esc_writer writing %u:\n", len);
426 for (i = 0; i < len; i++) {
427 fprintf(stderr, "0x%02x ", src[i]);
428 if (((i + 1) % 16) == 0) {
429 (void) fprintf(stderr, "\n");
430 } else if (((i + 1) % 8) == 0) {
431 (void) fprintf(stderr, " ");
434 (void) fprintf(stderr, "\n");
436 /* XXX: make this efficient */
437 for (n = 0; n < len; ++n) {
438 unsigned l;
440 if (dash->seen_nl) {
441 if (src[n] == '-' &&
442 !__ops_stacked_write("- ", 2, errors, writer)) {
443 return 0;
445 dash->seen_nl = 0;
447 dash->seen_nl = src[n] == '\n';
449 if (dash->seen_nl && !dash->seen_cr) {
450 if (!__ops_stacked_write("\r", 1, errors, writer)) {
451 return 0;
453 __ops_sig_add_data(dash->sig, "\r", 1);
455 dash->seen_cr = src[n] == '\r';
457 if (!__ops_stacked_write(&src[n], 1, errors, writer)) {
458 return 0;
461 /* trailing whitespace isn't included in the signature */
462 if (src[n] == ' ' || src[n] == '\t') {
463 __ops_memory_add(dash->trailing, &src[n], 1);
464 } else {
465 if ((l = __ops_mem_len(dash->trailing)) != 0) {
466 if (!dash->seen_nl && !dash->seen_cr) {
467 __ops_sig_add_data(dash->sig,
468 __ops_mem_data(dash->trailing), l);
470 __ops_memory_clear(dash->trailing);
472 __ops_sig_add_data(dash->sig, &src[n], 1);
475 return 1;
479 * \param writer
481 static void
482 dash_escaped_destroyer(__ops_writer_t *writer)
484 dashesc_t *dash;
486 dash = __ops_writer_get_arg(writer);
487 __ops_memory_free(dash->trailing);
488 free(dash);
492 * \ingroup Core_WritersNext
493 * \brief Push Clearsigned Writer onto stack
494 * \param output
495 * \param sig
497 unsigned
498 __ops_writer_push_clearsigned(__ops_output_t *output, __ops_create_sig_t *sig)
500 static const char header[] =
501 "-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: ";
502 const char *hash;
503 dashesc_t *dash;
504 unsigned ret;
506 hash = __ops_text_from_hash(__ops_sig_get_hash(sig));
507 if ((dash = calloc(1, sizeof(*dash))) == NULL) {
508 OPS_ERROR(&output->errors, OPS_E_W, "Bad alloc");
509 return 0;
511 ret = (__ops_write(output, header, sizeof(header) - 1) &&
512 __ops_write(output, hash, strlen(hash)) &&
513 __ops_write(output, "\r\n\r\n", 4));
515 if (ret == 0) {
516 OPS_ERROR(&output->errors, OPS_E_W,
517 "Error pushing clearsigned header");
518 free(dash);
519 return ret;
521 dash->seen_nl = 1;
522 dash->sig = sig;
523 dash->trailing = __ops_memory_new();
524 __ops_writer_push(output, dash_esc_writer, NULL,
525 dash_escaped_destroyer, dash);
526 return ret;
531 * \struct base64_t
533 typedef struct {
534 unsigned pos;
535 unsigned char t;
536 unsigned checksum;
537 } base64_t;
539 static const char b64map[] =
540 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
542 static unsigned
543 base64_writer(const unsigned char *src,
544 unsigned len,
545 __ops_error_t **errors,
546 __ops_writer_t *writer)
548 base64_t *base64 = __ops_writer_get_arg(writer);
549 unsigned n;
551 for (n = 0; n < len;) {
552 base64->checksum = __ops_crc24(base64->checksum, src[n]);
553 if (base64->pos == 0) {
554 /* XXXXXX00 00000000 00000000 */
555 if (!__ops_stacked_write(&b64map[(unsigned)src[n] >> 2],
556 1, errors, writer)) {
557 return 0;
560 /* 000000XX xxxx0000 00000000 */
561 base64->t = (src[n++] & 3) << 4;
562 base64->pos = 1;
563 } else if (base64->pos == 1) {
564 /* 000000xx XXXX0000 00000000 */
565 base64->t += (unsigned)src[n] >> 4;
566 if (!__ops_stacked_write(&b64map[base64->t], 1,
567 errors, writer)) {
568 return 0;
571 /* 00000000 0000XXXX xx000000 */
572 base64->t = (src[n++] & 0xf) << 2;
573 base64->pos = 2;
574 } else if (base64->pos == 2) {
575 /* 00000000 0000xxxx XX000000 */
576 base64->t += (unsigned)src[n] >> 6;
577 if (!__ops_stacked_write(&b64map[base64->t], 1,
578 errors, writer)) {
579 return 0;
582 /* 00000000 00000000 00XXXXXX */
583 if (!__ops_stacked_write(&b64map[src[n++] & 0x3f], 1,
584 errors, writer)) {
585 return 0;
588 base64->pos = 0;
592 return 1;
595 static unsigned
596 sig_finaliser(__ops_error_t **errors, __ops_writer_t *writer)
598 static const char trail[] = "\r\n-----END PGP SIGNATURE-----\r\n";
599 unsigned char c[3];
600 base64_t *base64;
602 base64 = __ops_writer_get_arg(writer);
603 if (base64->pos) {
604 if (!__ops_stacked_write(&b64map[base64->t], 1, errors,
605 writer)) {
606 return 0;
608 if (base64->pos == 1 &&
609 !__ops_stacked_write("==", 2, errors, writer)) {
610 return 0;
612 if (base64->pos == 2 &&
613 !__ops_stacked_write("=", 1, errors, writer)) {
614 return 0;
617 /* Ready for the checksum */
618 if (!__ops_stacked_write("\r\n=", 3, errors, writer)) {
619 return 0;
622 base64->pos = 0; /* get ready to write the checksum */
624 c[0] = base64->checksum >> 16;
625 c[1] = base64->checksum >> 8;
626 c[2] = base64->checksum;
627 /* push the checksum through our own writer */
628 if (!base64_writer(c, 3, errors, writer)) {
629 return 0;
632 return __ops_stacked_write(trail, sizeof(trail) - 1, errors, writer);
636 * \struct linebreak_t
638 typedef struct {
639 unsigned pos;
640 } linebreak_t;
642 #define BREAKPOS 76
644 static unsigned
645 linebreak_writer(const unsigned char *src,
646 unsigned len,
647 __ops_error_t ** errors,
648 __ops_writer_t * writer)
650 linebreak_t *linebreak = __ops_writer_get_arg(writer);
651 unsigned n;
653 for (n = 0; n < len; ++n, ++linebreak->pos) {
654 if (src[n] == '\r' || src[n] == '\n') {
655 linebreak->pos = 0;
657 if (linebreak->pos == BREAKPOS) {
658 if (!__ops_stacked_write("\r\n", 2, errors, writer)) {
659 return 0;
661 linebreak->pos = 0;
663 if (!__ops_stacked_write(&src[n], 1, errors, writer)) {
664 return 0;
668 return 1;
672 * \ingroup Core_WritersNext
673 * \brief Push armoured signature on stack
674 * \param output
676 unsigned
677 __ops_writer_use_armored_sig(__ops_output_t *output)
679 static const char header[] =
680 "\r\n-----BEGIN PGP SIGNATURE-----\r\nVersion: "
681 NETPGP_VERSION_STRING
682 "\r\n\r\n";
683 linebreak_t *linebreak;
684 base64_t *base64;
686 __ops_writer_pop(output);
687 if (__ops_write(output, header, sizeof(header) - 1) == 0) {
688 OPS_ERROR(&output->errors, OPS_E_W,
689 "Error switching to armoured signature");
690 return 0;
692 if ((linebreak = calloc(1, sizeof(*linebreak))) == NULL) {
693 OPS_ERROR(&output->errors, OPS_E_W,
694 "__ops_writer_use_armored_sig: Bad alloc");
695 return 0;
697 __ops_writer_push(output, linebreak_writer, NULL,
698 generic_destroyer,
699 linebreak);
700 base64 = calloc(1, sizeof(*base64));
701 if (!base64) {
702 OPS_MEMORY_ERROR(&output->errors);
703 return 0;
705 base64->checksum = CRC24_INIT;
706 __ops_writer_push(output, base64_writer, sig_finaliser,
707 generic_destroyer, base64);
708 return 1;
711 static unsigned
712 armoured_message_finaliser(__ops_error_t **errors, __ops_writer_t *writer)
714 /* TODO: This is same as sig_finaliser apart from trailer. */
715 static const char *trailer = "\r\n-----END PGP MESSAGE-----\r\n";
716 unsigned char c[3];
717 base64_t *base64;
719 base64 = __ops_writer_get_arg(writer);
720 if (base64->pos) {
721 if (!__ops_stacked_write(&b64map[base64->t], 1, errors,
722 writer)) {
723 return 0;
725 if (base64->pos == 1 &&
726 !__ops_stacked_write("==", 2, errors, writer)) {
727 return 0;
729 if (base64->pos == 2 &&
730 !__ops_stacked_write("=", 1, errors, writer)) {
731 return 0;
734 /* Ready for the checksum */
735 if (!__ops_stacked_write("\r\n=", 3, errors, writer)) {
736 return 0;
739 base64->pos = 0; /* get ready to write the checksum */
741 c[0] = base64->checksum >> 16;
742 c[1] = base64->checksum >> 8;
743 c[2] = base64->checksum;
744 /* push the checksum through our own writer */
745 if (!base64_writer(c, 3, errors, writer)) {
746 return 0;
749 return __ops_stacked_write(trailer, strlen(trailer), errors, writer);
753 \ingroup Core_WritersNext
754 \brief Write a PGP MESSAGE
755 \todo replace with generic function
757 void
758 __ops_writer_push_armor_msg(__ops_output_t *output)
760 static const char header[] = "-----BEGIN PGP MESSAGE-----\r\n";
761 linebreak_t *linebreak;
762 base64_t *base64;
764 __ops_write(output, header, sizeof(header) - 1);
765 __ops_write(output, "\r\n", 2);
766 if ((linebreak = calloc(1, sizeof(*linebreak))) == NULL) {
767 (void) fprintf(stderr,
768 "__ops_writer_push_armor_msg: bad lb alloc\n");
769 return;
771 __ops_writer_push(output, linebreak_writer, NULL,
772 generic_destroyer,
773 linebreak);
774 if ((base64 = calloc(1, sizeof(*base64))) == NULL) {
775 (void) fprintf(stderr,
776 "__ops_writer_push_armor_msg: bad alloc\n");
777 return;
779 base64->checksum = CRC24_INIT;
780 __ops_writer_push(output, base64_writer,
781 armoured_message_finaliser, generic_destroyer,
782 base64);
785 static unsigned
786 armoured_finaliser(__ops_armor_type_t type,
787 __ops_error_t **errors,
788 __ops_writer_t *writer)
790 static const char tail_pubkey[] =
791 "\r\n-----END PGP PUBLIC KEY BLOCK-----\r\n";
792 static const char tail_private_key[] =
793 "\r\n-----END PGP PRIVATE KEY BLOCK-----\r\n";
794 unsigned char c[3];
795 unsigned int sz_tail = 0;
796 const char *tail = NULL;
797 base64_t *base64;
799 switch (type) {
800 case OPS_PGP_PUBLIC_KEY_BLOCK:
801 tail = tail_pubkey;
802 sz_tail = sizeof(tail_pubkey) - 1;
803 break;
805 case OPS_PGP_PRIVATE_KEY_BLOCK:
806 tail = tail_private_key;
807 sz_tail = sizeof(tail_private_key) - 1;
808 break;
810 default:
811 (void) fprintf(stderr, "armoured_finaliser: unusual type\n");
812 return 0;
814 base64 = __ops_writer_get_arg(writer);
815 if (base64->pos) {
816 if (!__ops_stacked_write(&b64map[base64->t], 1, errors,
817 writer)) {
818 return 0;
820 if (base64->pos == 1 && !__ops_stacked_write("==", 2, errors,
821 writer)) {
822 return 0;
824 if (base64->pos == 2 && !__ops_stacked_write("=", 1, errors,
825 writer)) {
826 return 0;
829 /* Ready for the checksum */
830 if (!__ops_stacked_write("\r\n=", 3, errors, writer)) {
831 return 0;
833 base64->pos = 0; /* get ready to write the checksum */
834 c[0] = base64->checksum >> 16;
835 c[1] = base64->checksum >> 8;
836 c[2] = base64->checksum;
837 /* push the checksum through our own writer */
838 if (!base64_writer(c, 3, errors, writer)) {
839 return 0;
841 return __ops_stacked_write(tail, sz_tail, errors, writer);
844 static unsigned
845 armored_pubkey_fini(__ops_error_t **errors, __ops_writer_t *writer)
847 return armoured_finaliser(OPS_PGP_PUBLIC_KEY_BLOCK, errors, writer);
850 static unsigned
851 armored_privkey_fini(__ops_error_t **errors, __ops_writer_t *writer)
853 return armoured_finaliser(OPS_PGP_PRIVATE_KEY_BLOCK, errors, writer);
856 /* \todo use this for other armoured types */
858 \ingroup Core_WritersNext
859 \brief Push Armoured Writer on stack (generic)
861 void
862 __ops_writer_push_armoured(__ops_output_t *output, __ops_armor_type_t type)
864 static char hdr_pubkey[] =
865 "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: "
866 NETPGP_VERSION_STRING
867 "\r\n\r\n";
868 static char hdr_private_key[] =
869 "-----BEGIN PGP PRIVATE KEY BLOCK-----\r\nVersion: "
870 NETPGP_VERSION_STRING
871 "\r\n\r\n";
872 unsigned int sz_hdr = 0;
873 unsigned (*finaliser) (__ops_error_t **, __ops_writer_t *);
874 base64_t *base64;
875 linebreak_t *linebreak;
876 char *header = NULL;
878 finaliser = NULL;
879 switch (type) {
880 case OPS_PGP_PUBLIC_KEY_BLOCK:
881 header = hdr_pubkey;
882 sz_hdr = sizeof(hdr_pubkey) - 1;
883 finaliser = armored_pubkey_fini;
884 break;
886 case OPS_PGP_PRIVATE_KEY_BLOCK:
887 header = hdr_private_key;
888 sz_hdr = sizeof(hdr_private_key) - 1;
889 finaliser = armored_privkey_fini;
890 break;
892 default:
893 (void) fprintf(stderr,
894 "__ops_writer_push_armoured: unusual type\n");
895 return;
897 if ((linebreak = calloc(1, sizeof(*linebreak))) == NULL) {
898 (void) fprintf(stderr,
899 "__ops_writer_push_armoured: bad alloc\n");
900 return;
902 __ops_write(output, header, sz_hdr);
903 __ops_writer_push(output, linebreak_writer, NULL,
904 generic_destroyer,
905 linebreak);
906 if ((base64 = calloc(1, sizeof(*base64))) == NULL) {
907 (void) fprintf(stderr,
908 "__ops_writer_push_armoured: bad alloc\n");
909 return;
911 base64->checksum = CRC24_INIT;
912 __ops_writer_push(output, base64_writer, finaliser,
913 generic_destroyer, base64);
916 /**************************************************************************/
918 typedef struct {
919 __ops_crypt_t *crypt;
920 int free_crypt;
921 } crypt_t;
924 * This writer simply takes plaintext as input,
925 * encrypts it with the given key
926 * and outputs the resulting encrypted text
928 static unsigned
929 encrypt_writer(const unsigned char *src,
930 unsigned len,
931 __ops_error_t **errors,
932 __ops_writer_t *writer)
934 #define BUFSZ 1024 /* arbitrary number */
935 unsigned char encbuf[BUFSZ];
936 unsigned remaining;
937 unsigned done = 0;
938 crypt_t *pgp_encrypt;
940 remaining = len;
941 pgp_encrypt = (crypt_t *) __ops_writer_get_arg(writer);
942 if (!__ops_is_sa_supported(pgp_encrypt->crypt->alg)) {
943 (void) fprintf(stderr, "encrypt_writer: not supported\n");
944 return 0;
946 while (remaining > 0) {
947 unsigned size = (remaining < BUFSZ) ? remaining : BUFSZ;
949 /* memcpy(buf,src,size); // \todo copy needed here? */
950 pgp_encrypt->crypt->cfb_encrypt(pgp_encrypt->crypt, encbuf,
951 src + done, size);
953 if (__ops_get_debug_level(__FILE__)) {
954 int i = 0;
956 (void) fprintf(stderr, "WRITING:\nunencrypted: ");
957 for (i = 0; i < 16; i++) {
958 (void) fprintf(stderr, "%2x ", src[done + i]);
960 (void) fprintf(stderr, "\nencrypted: ");
961 for (i = 0; i < 16; i++) {
962 (void) fprintf(stderr, "%2x ", encbuf[i]);
964 (void) fprintf(stderr, "\n");
966 if (!__ops_stacked_write(encbuf, size, errors, writer)) {
967 if (__ops_get_debug_level(__FILE__)) {
968 fprintf(stderr,
969 "encrypted_writer: stacked write\n");
971 return 0;
973 remaining -= size;
974 done += size;
977 return 1;
980 static void
981 encrypt_destroyer(__ops_writer_t *writer)
983 crypt_t *pgp_encrypt = (crypt_t *) __ops_writer_get_arg(writer);
985 if (pgp_encrypt->free_crypt) {
986 free(pgp_encrypt->crypt);
988 free(pgp_encrypt);
992 \ingroup Core_WritersNext
993 \brief Push Encrypted Writer onto stack (create SE packets)
995 void
996 __ops_push_enc_crypt(__ops_output_t *output, __ops_crypt_t *pgp_crypt)
998 /* Create encrypt to be used with this writer */
999 /* Remember to free this in the destroyer */
1000 crypt_t *pgp_encrypt;
1002 if ((pgp_encrypt = calloc(1, sizeof(*pgp_encrypt))) == NULL) {
1003 (void) fprintf(stderr, "__ops_push_enc_crypt: bad alloc\n");
1004 } else {
1005 /* Setup the encrypt */
1006 pgp_encrypt->crypt = pgp_crypt;
1007 pgp_encrypt->free_crypt = 0;
1008 /* And push writer on stack */
1009 __ops_writer_push(output, encrypt_writer, NULL,
1010 encrypt_destroyer, pgp_encrypt);
1014 /**************************************************************************/
1016 typedef struct {
1017 __ops_crypt_t *crypt;
1018 } encrypt_se_ip_t;
1020 static unsigned encrypt_se_ip_writer(const unsigned char *,
1021 unsigned,
1022 __ops_error_t **,
1023 __ops_writer_t *);
1024 static void encrypt_se_ip_destroyer(__ops_writer_t *);
1026 /* */
1029 \ingroup Core_WritersNext
1030 \brief Push Encrypted SE IP Writer onto stack
1032 void
1033 __ops_push_enc_se_ip(__ops_output_t *output, const __ops_key_t *pubkey)
1035 unsigned char *iv;
1036 __ops_crypt_t *encrypted;
1037 /* Create se_ip to be used with this writer */
1038 /* Remember to free this in the destroyer */
1039 encrypt_se_ip_t *se_ip;
1040 __ops_pk_sesskey_t *encrypted_pk_sesskey;
1042 if ((se_ip = calloc(1, sizeof(*se_ip))) == NULL) {
1043 (void) fprintf(stderr, "__ops_push_enc_se_ip: bad alloc\n");
1044 return;
1047 /* Create and write encrypted PK session key */
1048 encrypted_pk_sesskey = __ops_create_pk_sesskey(pubkey);
1049 __ops_write_pk_sesskey(output, encrypted_pk_sesskey);
1051 /* Setup the se_ip */
1052 if ((encrypted = calloc(1, sizeof(*encrypted))) == NULL) {
1053 free(se_ip);
1054 (void) fprintf(stderr, "__ops_push_enc_se_ip: bad alloc\n");
1055 return;
1057 __ops_crypt_any(encrypted, encrypted_pk_sesskey->symm_alg);
1058 if ((iv = calloc(1, encrypted->blocksize)) == NULL) {
1059 free(se_ip);
1060 free(encrypted);
1061 (void) fprintf(stderr, "__ops_push_enc_se_ip: bad alloc\n");
1062 return;
1064 encrypted->set_iv(encrypted, iv);
1065 encrypted->set_crypt_key(encrypted, &encrypted_pk_sesskey->key[0]);
1066 __ops_encrypt_init(encrypted);
1068 se_ip->crypt = encrypted;
1070 /* And push writer on stack */
1071 __ops_writer_push(output, encrypt_se_ip_writer, NULL,
1072 encrypt_se_ip_destroyer, se_ip);
1073 /* tidy up */
1074 free(encrypted_pk_sesskey);
1075 free(iv);
1078 static unsigned
1079 encrypt_se_ip_writer(const unsigned char *src,
1080 unsigned len,
1081 __ops_error_t **errors,
1082 __ops_writer_t *writer)
1084 const unsigned int bufsz = 128;
1085 encrypt_se_ip_t *se_ip = __ops_writer_get_arg(writer);
1086 __ops_output_t *litoutput;
1087 __ops_output_t *zoutput;
1088 __ops_output_t *output;
1089 __ops_memory_t *litmem;
1090 __ops_memory_t *zmem;
1091 __ops_memory_t *localmem;
1092 unsigned ret = 1;
1094 __ops_setup_memory_write(&litoutput, &litmem, bufsz);
1095 __ops_setup_memory_write(&zoutput, &zmem, bufsz);
1096 __ops_setup_memory_write(&output, &localmem, bufsz);
1098 /* create literal data packet from source data */
1099 __ops_write_litdata(litoutput, src, (const int)len, OPS_LDT_BINARY);
1100 if (__ops_mem_len(litmem) <= len) {
1101 (void) fprintf(stderr, "encrypt_se_ip_writer: bad len\n");
1102 return 0;
1105 /* create compressed packet from literal data packet */
1106 __ops_writez(__ops_mem_data(litmem), __ops_mem_len(litmem), zoutput);
1108 /* create SE IP packet set from this compressed literal data */
1109 __ops_write_se_ip_pktset(__ops_mem_data(zmem),
1110 __ops_mem_len(zmem),
1111 se_ip->crypt, output);
1112 if (__ops_mem_len(localmem) <= __ops_mem_len(zmem)) {
1113 (void) fprintf(stderr,
1114 "encrypt_se_ip_writer: bad comp len\n");
1115 return 0;
1118 /* now write memory to next writer */
1119 ret = __ops_stacked_write(__ops_mem_data(localmem),
1120 __ops_mem_len(localmem),
1121 errors, writer);
1123 __ops_memory_free(localmem);
1124 __ops_memory_free(zmem);
1125 __ops_memory_free(litmem);
1127 return ret;
1130 static void
1131 encrypt_se_ip_destroyer(__ops_writer_t *writer)
1133 encrypt_se_ip_t *se_ip;
1135 se_ip = __ops_writer_get_arg(writer);
1136 free(se_ip->crypt);
1137 free(se_ip);
1140 unsigned
1141 __ops_write_se_ip_pktset(const unsigned char *data,
1142 const unsigned int len,
1143 __ops_crypt_t *crypted,
1144 __ops_output_t *output)
1146 __ops_output_t *mdcoutput;
1147 __ops_memory_t *mdc;
1148 unsigned char hashed[OPS_SHA1_HASH_SIZE];
1149 unsigned char *preamble;
1150 const size_t sz_mdc = 1 + 1 + OPS_SHA1_HASH_SIZE;
1151 size_t sz_preamble;
1152 size_t sz_buf;
1154 sz_preamble = crypted->blocksize + 2;
1155 if ((preamble = calloc(1, sz_preamble)) == NULL) {
1156 (void) fprintf(stderr, "__ops_write_se_ip_pktset: bad alloc\n");
1157 return 0;
1159 sz_buf = sz_preamble + len + sz_mdc;
1161 if (!__ops_write_ptag(output, OPS_PTAG_CT_SE_IP_DATA) ||
1162 !__ops_write_length(output, 1 + sz_buf) ||
1163 !__ops_write_scalar(output, SE_IP_DATA_VERSION, 1)) {
1164 free(preamble);
1165 return 0;
1167 __ops_random(preamble, crypted->blocksize);
1168 preamble[crypted->blocksize] = preamble[crypted->blocksize - 2];
1169 preamble[crypted->blocksize + 1] = preamble[crypted->blocksize - 1];
1171 if (__ops_get_debug_level(__FILE__)) {
1172 unsigned int i;
1174 fprintf(stderr, "\npreamble: ");
1175 for (i = 0; i < sz_preamble; i++) {
1176 fprintf(stderr, " 0x%02x", preamble[i]);
1178 fprintf(stderr, "\n");
1181 /* now construct MDC packet and add to the end of the buffer */
1182 __ops_setup_memory_write(&mdcoutput, &mdc, sz_mdc);
1183 __ops_calc_mdc_hash(preamble, sz_preamble, data, len, &hashed[0]);
1184 __ops_write_mdc(hashed, mdcoutput);
1186 if (__ops_get_debug_level(__FILE__)) {
1187 unsigned int i;
1188 size_t sz_plaintext = len;
1189 size_t sz_mdc2 = 1 + 1 + OPS_SHA1_HASH_SIZE;
1190 unsigned char *digest;
1192 (void) fprintf(stderr, "\nplaintext: ");
1193 for (i = 0; i < sz_plaintext; i++) {
1194 (void) fprintf(stderr, " 0x%02x", data[i]);
1196 (void) fprintf(stderr, "\n");
1198 (void) fprintf(stderr, "\nmdc: ");
1199 digest = __ops_mem_data(mdc);
1200 for (i = 0; i < sz_mdc2; i++) {
1201 (void) fprintf(stderr, " 0x%02x", digest[i]);
1203 (void) fprintf(stderr, "\n");
1206 /* and write it out */
1207 __ops_push_enc_crypt(output, crypted);
1208 if (__ops_get_debug_level(__FILE__)) {
1209 (void) fprintf(stderr,
1210 "writing %" PRIsize "u + %u + %" PRIsize "u\n",
1211 sz_preamble, len, __ops_mem_len(mdc));
1213 if (!__ops_write(output, preamble, sz_preamble) ||
1214 !__ops_write(output, data, len) ||
1215 !__ops_write(output, __ops_mem_data(mdc), __ops_mem_len(mdc))) {
1216 /* \todo fix cleanup here and in old code functions */
1217 return 0;
1220 __ops_writer_pop(output);
1222 /* cleanup */
1223 __ops_teardown_memory_write(mdcoutput, mdc);
1224 free(preamble);
1226 return 1;
1229 typedef struct {
1230 int fd;
1231 } writer_fd_t;
1233 static unsigned
1234 fd_writer(const unsigned char *src, unsigned len,
1235 __ops_error_t **errors,
1236 __ops_writer_t *writer)
1238 writer_fd_t *writerfd;
1239 int n;
1241 writerfd = __ops_writer_get_arg(writer);
1242 n = write(writerfd->fd, src, len);
1243 if (n == -1) {
1244 OPS_SYSTEM_ERROR_1(errors, OPS_E_W_WRITE_FAILED, "write",
1245 "file descriptor %d", writerfd->fd);
1246 return 0;
1248 if ((unsigned) n != len) {
1249 OPS_ERROR_1(errors, OPS_E_W_WRITE_TOO_SHORT,
1250 "file descriptor %d", writerfd->fd);
1251 return 0;
1253 return 1;
1256 static void
1257 writer_fd_destroyer(__ops_writer_t *writer)
1259 free(__ops_writer_get_arg(writer));
1263 * \ingroup Core_WritersFirst
1264 * \brief Write to a File
1266 * Set the writer in output to be a stock writer that writes to a file
1267 * descriptor. If another writer has already been set, then that is
1268 * first destroyed.
1270 * \param output The output structure
1271 * \param fd The file descriptor
1275 void
1276 __ops_writer_set_fd(__ops_output_t *output, int fd)
1278 writer_fd_t *writer;
1280 if ((writer = calloc(1, sizeof(*writer))) == NULL) {
1281 (void) fprintf(stderr, "__ops_writer_set_fd: bad alloc\n");
1282 } else {
1283 writer->fd = fd;
1284 __ops_writer_set(output, fd_writer, NULL, writer_fd_destroyer, writer);
1288 static unsigned
1289 memory_writer(const unsigned char *src,
1290 unsigned len,
1291 __ops_error_t **errors,
1292 __ops_writer_t *writer)
1294 __ops_memory_t *mem;
1296 __OPS_USED(errors);
1297 mem = __ops_writer_get_arg(writer);
1298 __ops_memory_add(mem, src, len);
1299 return 1;
1303 * \ingroup Core_WritersFirst
1304 * \brief Write to memory
1306 * Set a memory writer.
1308 * \param output The output structure
1309 * \param mem The memory structure
1310 * \note It is the caller's responsiblity to call __ops_memory_free(mem)
1311 * \sa __ops_memory_free()
1314 void
1315 __ops_writer_set_memory(__ops_output_t *output, __ops_memory_t *mem)
1317 __ops_writer_set(output, memory_writer, NULL, NULL, mem);
1320 /**************************************************************************/
1322 typedef struct {
1323 __ops_hash_alg_t hash_alg;
1324 __ops_hash_t hash;
1325 unsigned char *hashed;
1326 } skey_checksum_t;
1328 static unsigned
1329 skey_checksum_writer(const unsigned char *src,
1330 const unsigned len,
1331 __ops_error_t **errors,
1332 __ops_writer_t *writer)
1334 skey_checksum_t *sum;
1335 unsigned ret = 1;
1337 sum = __ops_writer_get_arg(writer);
1338 /* add contents to hash */
1339 sum->hash.add(&sum->hash, src, len);
1340 /* write to next stacked writer */
1341 ret = __ops_stacked_write(src, len, errors, writer);
1342 /* tidy up and return */
1343 return ret;
1346 static unsigned
1347 skey_checksum_finaliser(__ops_error_t **errors, __ops_writer_t *writer)
1349 skey_checksum_t *sum;
1351 sum = __ops_writer_get_arg(writer);
1352 if (errors) {
1353 printf("errors in skey_checksum_finaliser\n");
1355 sum->hash.finish(&sum->hash, sum->hashed);
1356 return 1;
1359 static void
1360 skey_checksum_destroyer(__ops_writer_t *writer)
1362 skey_checksum_t *sum;
1364 sum = __ops_writer_get_arg(writer);
1365 free(sum);
1369 \ingroup Core_WritersNext
1370 \param output
1371 \param seckey
1373 void
1374 __ops_push_checksum_writer(__ops_output_t *output, __ops_seckey_t *seckey)
1376 /* XXX: push a SHA-1 checksum writer (and change s2k to 254). */
1377 skey_checksum_t *sum;
1379 if ((sum = calloc(1, sizeof(*sum))) == NULL) {
1380 (void) fprintf(stderr, "__ops_push_checksum_writer: bad alloc\n");
1381 } else {
1382 /* configure the arg */
1383 sum->hash_alg = seckey->hash_alg;
1384 sum->hashed = seckey->checkhash;
1385 /* init the hash */
1386 __ops_hash_any(&sum->hash, sum->hash_alg);
1387 if (!sum->hash.init(&sum->hash)) {
1388 (void) fprintf(stderr,
1389 "__ops_push_checksum_writer: bad hash init\n");
1390 /* just continue and die */
1391 /* XXX - agc - no way to return failure */
1393 __ops_writer_push(output, skey_checksum_writer,
1394 skey_checksum_finaliser, skey_checksum_destroyer, sum);
1398 /**************************************************************************/
1400 #define MAX_PARTIAL_DATA_LENGTH 1073741824
1402 typedef struct {
1403 __ops_crypt_t *crypt;
1404 __ops_memory_t *mem_data;
1405 __ops_memory_t *litmem;
1406 __ops_output_t *litoutput;
1407 __ops_memory_t *se_ip_mem;
1408 __ops_output_t *se_ip_out;
1409 __ops_hash_t hash;
1410 } str_enc_se_ip_t;
1413 static unsigned
1414 str_enc_se_ip_writer(const unsigned char *src,
1415 unsigned len,
1416 __ops_error_t **errors,
1417 __ops_writer_t *writer);
1419 static unsigned
1420 str_enc_se_ip_finaliser(__ops_error_t **errors,
1421 __ops_writer_t * writer);
1423 static void str_enc_se_ip_destroyer(__ops_writer_t *writer);
1425 /* */
1428 \ingroup Core_WritersNext
1429 \param output
1430 \param pubkey
1432 void
1433 __ops_push_stream_enc_se_ip(__ops_output_t *output, const __ops_key_t *pubkey)
1435 __ops_pk_sesskey_t *encrypted_pk_sesskey;
1436 const unsigned int bufsz = 1024;
1437 str_enc_se_ip_t *se_ip;
1438 __ops_crypt_t *encrypted;
1439 unsigned char *iv;
1441 if ((se_ip = calloc(1, sizeof(*se_ip))) == NULL) {
1442 (void) fprintf(stderr,
1443 "__ops_push_stream_enc_se_ip: bad alloc\n");
1444 return;
1446 encrypted_pk_sesskey = __ops_create_pk_sesskey(pubkey);
1447 __ops_write_pk_sesskey(output, encrypted_pk_sesskey);
1449 /* Setup the se_ip */
1450 if ((encrypted = calloc(1, sizeof(*encrypted))) == NULL) {
1451 free(se_ip);
1452 (void) fprintf(stderr,
1453 "__ops_push_stream_enc_se_ip: bad alloc\n");
1454 return;
1456 __ops_crypt_any(encrypted, encrypted_pk_sesskey->symm_alg);
1457 if ((iv = calloc(1, encrypted->blocksize)) == NULL) {
1458 free(encrypted);
1459 free(se_ip);
1460 (void) fprintf(stderr,
1461 "__ops_push_stream_enc_se_ip: bad alloc\n");
1462 return;
1464 encrypted->set_iv(encrypted, iv);
1465 encrypted->set_crypt_key(encrypted, &encrypted_pk_sesskey->key[0]);
1466 __ops_encrypt_init(encrypted);
1468 se_ip->crypt = encrypted;
1470 se_ip->mem_data = __ops_memory_new();
1471 __ops_memory_init(se_ip->mem_data, bufsz);
1473 se_ip->litmem = NULL;
1474 se_ip->litoutput = NULL;
1476 __ops_setup_memory_write(&se_ip->se_ip_out, &se_ip->se_ip_mem, bufsz);
1478 /* And push writer on stack */
1479 __ops_writer_push(output,
1480 str_enc_se_ip_writer,
1481 str_enc_se_ip_finaliser,
1482 str_enc_se_ip_destroyer, se_ip);
1483 /* tidy up */
1484 free(encrypted_pk_sesskey);
1485 free(iv);
1489 /* calculate the partial data length */
1490 static unsigned int
1491 __ops_partial_data_len(unsigned int len)
1493 unsigned int mask = MAX_PARTIAL_DATA_LENGTH;
1494 int i;
1496 if (len == 0) {
1497 (void) fprintf(stderr, "__ops_partial_data_len: 0 len\n");
1498 return 0;
1500 if (len > MAX_PARTIAL_DATA_LENGTH) {
1501 return MAX_PARTIAL_DATA_LENGTH;
1503 for (i = 0; i <= 30; i++) {
1504 if (mask & len) {
1505 break;
1507 mask >>= 1;
1509 return mask;
1512 static unsigned
1513 __ops_write_partial_len(unsigned int len, __ops_output_t *output)
1515 /* len must be a power of 2 from 0 to 30 */
1516 unsigned char c;
1517 int i;
1519 for (i = 0; i <= 30; i++) {
1520 if ((len >> i) & 1) {
1521 break;
1524 c = 224 + i;
1525 return __ops_write(output, &c, 1);
1528 static unsigned
1529 stream_write_litdata(__ops_output_t *output,
1530 const unsigned char *data,
1531 unsigned len)
1533 while (len > 0) {
1534 size_t pdlen = __ops_partial_data_len(len);
1536 __ops_write_partial_len(pdlen, output);
1537 __ops_write(output, data, pdlen);
1538 data += pdlen;
1539 len -= pdlen;
1541 return 1;
1544 static unsigned
1545 stream_write_litdata_first(__ops_output_t *output,
1546 const unsigned char *data,
1547 unsigned int len,
1548 const __ops_litdata_type_t type)
1550 /* \todo add filename */
1551 /* \todo add date */
1552 /* \todo do we need to check text data for <cr><lf> line endings ? */
1554 size_t sz_towrite;
1555 size_t sz_pd;
1557 sz_towrite = 1 + 1 + 4 + len;
1558 sz_pd = __ops_partial_data_len(sz_towrite);
1559 if (sz_pd < 512) {
1560 (void) fprintf(stderr,
1561 "stream_write_litdata_first: bad sz_pd\n");
1562 return 0;
1564 __ops_write_ptag(output, OPS_PTAG_CT_LITDATA);
1565 __ops_write_partial_len(sz_pd, output);
1566 __ops_write_scalar(output, (unsigned)type, 1);
1567 __ops_write_scalar(output, 0, 1);
1568 __ops_write_scalar(output, 0, 4);
1569 __ops_write(output, data, sz_pd - 6);
1571 data += (sz_pd - 6);
1572 sz_towrite -= sz_pd;
1574 return stream_write_litdata(output, data, sz_towrite);
1577 static unsigned
1578 stream_write_litdata_last(__ops_output_t *output,
1579 const unsigned char *data,
1580 unsigned int len)
1582 __ops_write_length(output, len);
1583 return __ops_write(output, data, len);
1586 static unsigned
1587 stream_write_se_ip(__ops_output_t *output,
1588 const unsigned char *data,
1589 unsigned int len,
1590 str_enc_se_ip_t *se_ip)
1592 size_t pdlen;
1594 while (len > 0) {
1595 pdlen = __ops_partial_data_len(len);
1596 __ops_write_partial_len(pdlen, output);
1598 __ops_push_enc_crypt(output, se_ip->crypt);
1599 __ops_write(output, data, pdlen);
1600 __ops_writer_pop(output);
1602 se_ip->hash.add(&se_ip->hash, data, pdlen);
1604 data += pdlen;
1605 len -= pdlen;
1607 return 1;
1610 static unsigned
1611 stream_write_se_ip_first(__ops_output_t *output,
1612 const unsigned char *data,
1613 unsigned int len,
1614 str_enc_se_ip_t *se_ip)
1616 unsigned char *preamble;
1617 size_t blocksize;
1618 size_t sz_preamble;
1619 size_t sz_towrite;
1620 size_t sz_pd;
1622 blocksize = se_ip->crypt->blocksize;
1623 sz_preamble = blocksize + 2;
1624 sz_towrite = sz_preamble + 1 + len;
1625 if ((preamble = calloc(1, sz_preamble)) == NULL) {
1626 (void) fprintf(stderr,
1627 "stream_write_se_ip_first: bad alloc\n");
1628 return 0;
1630 sz_pd = __ops_partial_data_len(sz_towrite);
1631 if (sz_pd < 512) {
1632 free(preamble);
1633 (void) fprintf(stderr,
1634 "stream_write_se_ip_first: bad sz_pd\n");
1635 return 0;
1637 __ops_write_ptag(output, OPS_PTAG_CT_SE_IP_DATA);
1638 __ops_write_partial_len(sz_pd, output);
1639 __ops_write_scalar(output, SE_IP_DATA_VERSION, 1);
1640 __ops_push_enc_crypt(output, se_ip->crypt);
1642 __ops_random(preamble, blocksize);
1643 preamble[blocksize] = preamble[blocksize - 2];
1644 preamble[blocksize + 1] = preamble[blocksize - 1];
1645 __ops_hash_any(&se_ip->hash, OPS_HASH_SHA1);
1646 if (!se_ip->hash.init(&se_ip->hash)) {
1647 free(preamble);
1648 (void) fprintf(stderr,
1649 "stream_write_se_ip_first: bad hash init\n");
1650 return 0;
1652 __ops_write(output, preamble, sz_preamble);
1653 se_ip->hash.add(&se_ip->hash, preamble, sz_preamble);
1654 __ops_write(output, data, sz_pd - sz_preamble - 1);
1655 se_ip->hash.add(&se_ip->hash, data, sz_pd - sz_preamble - 1);
1656 data += (sz_pd - sz_preamble - 1);
1657 sz_towrite -= sz_pd;
1658 __ops_writer_pop(output);
1659 stream_write_se_ip(output, data, sz_towrite, se_ip);
1660 free(preamble);
1661 return 1;
1664 static unsigned
1665 stream_write_se_ip_last(__ops_output_t *output,
1666 const unsigned char *data,
1667 unsigned int len,
1668 str_enc_se_ip_t *se_ip)
1670 __ops_output_t *mdcoutput;
1671 __ops_memory_t *mdcmem;
1672 unsigned char c;
1673 unsigned char hashed[OPS_SHA1_HASH_SIZE];
1674 const size_t sz_mdc = 1 + 1 + OPS_SHA1_HASH_SIZE;
1675 size_t sz_buf = len + sz_mdc;
1677 se_ip->hash.add(&se_ip->hash, data, len);
1679 /* MDC packet tag */
1680 c = MDC_PKT_TAG;
1681 se_ip->hash.add(&se_ip->hash, &c, 1);
1683 /* MDC packet len */
1684 c = OPS_SHA1_HASH_SIZE;
1685 se_ip->hash.add(&se_ip->hash, &c, 1);
1687 /* finish */
1688 se_ip->hash.finish(&se_ip->hash, hashed);
1690 __ops_setup_memory_write(&mdcoutput, &mdcmem, sz_mdc);
1691 __ops_write_mdc(hashed, mdcoutput);
1693 /* write length of last se_ip chunk */
1694 __ops_write_length(output, sz_buf);
1696 /* encode everting */
1697 __ops_push_enc_crypt(output, se_ip->crypt);
1699 __ops_write(output, data, len);
1700 __ops_write(output, __ops_mem_data(mdcmem), __ops_mem_len(mdcmem));
1702 __ops_writer_pop(output);
1704 __ops_teardown_memory_write(mdcoutput, mdcmem);
1706 return 1;
1709 static unsigned
1710 str_enc_se_ip_writer(const unsigned char *src,
1711 unsigned len,
1712 __ops_error_t **errors,
1713 __ops_writer_t *writer)
1715 str_enc_se_ip_t *se_ip = __ops_writer_get_arg(writer);
1716 unsigned ret = 1;
1718 if (se_ip->litoutput == NULL) { /* first literal data chunk
1719 * is not yet written */
1720 size_t datalength;
1722 __ops_memory_add(se_ip->mem_data, src, len);
1723 datalength = __ops_mem_len(se_ip->mem_data);
1725 /* 4.2.2.4. Partial Body Lengths */
1726 /* The first partial length MUST be at least 512 octets long. */
1727 if (datalength < 512) {
1728 return 1; /* will wait for more data or
1729 * end of stream */
1731 __ops_setup_memory_write(&se_ip->litoutput,
1732 &se_ip->litmem, datalength + 32);
1733 stream_write_litdata_first(se_ip->litoutput,
1734 __ops_mem_data(se_ip->mem_data),
1735 datalength,
1736 OPS_LDT_BINARY);
1738 stream_write_se_ip_first(se_ip->se_ip_out,
1739 __ops_mem_data(se_ip->litmem),
1740 __ops_mem_len(se_ip->litmem), se_ip);
1741 } else {
1742 stream_write_litdata(se_ip->litoutput, src, len);
1743 stream_write_se_ip(se_ip->se_ip_out,
1744 __ops_mem_data(se_ip->litmem),
1745 __ops_mem_len(se_ip->litmem), se_ip);
1748 /* now write memory to next writer */
1749 ret = __ops_stacked_write(__ops_mem_data(se_ip->se_ip_mem),
1750 __ops_mem_len(se_ip->se_ip_mem),
1751 errors, writer);
1753 __ops_memory_clear(se_ip->litmem);
1754 __ops_memory_clear(se_ip->se_ip_mem);
1756 return ret;
1759 static unsigned
1760 str_enc_se_ip_finaliser(__ops_error_t **errors, __ops_writer_t *writer)
1762 str_enc_se_ip_t *se_ip = __ops_writer_get_arg(writer);
1763 /* write last chunk of data */
1765 if (se_ip->litoutput == NULL) {
1766 /* first literal data chunk was not written */
1767 /* so we know the total length of data, write a simple packet */
1769 /* create literal data packet from buffered data */
1770 __ops_setup_memory_write(&se_ip->litoutput, &se_ip->litmem,
1771 __ops_mem_len(se_ip->mem_data) + 32);
1773 __ops_write_litdata(se_ip->litoutput,
1774 __ops_mem_data(se_ip->mem_data),
1775 (const int)__ops_mem_len(se_ip->mem_data),
1776 OPS_LDT_BINARY);
1778 /* create SE IP packet set from this literal data */
1779 __ops_write_se_ip_pktset(
1780 __ops_mem_data(se_ip->litmem),
1781 __ops_mem_len(se_ip->litmem),
1782 se_ip->crypt, se_ip->se_ip_out);
1784 } else {
1785 /* finish writing */
1786 stream_write_litdata_last(se_ip->litoutput, NULL, 0);
1787 stream_write_se_ip_last(se_ip->se_ip_out,
1788 __ops_mem_data(se_ip->litmem),
1789 __ops_mem_len(se_ip->litmem), se_ip);
1792 /* now write memory to next writer */
1793 return __ops_stacked_write(__ops_mem_data(se_ip->se_ip_mem),
1794 __ops_mem_len(se_ip->se_ip_mem),
1795 errors, writer);
1798 static void
1799 str_enc_se_ip_destroyer(__ops_writer_t *writer)
1801 str_enc_se_ip_t *se_ip = __ops_writer_get_arg(writer);
1803 __ops_memory_free(se_ip->mem_data);
1804 __ops_teardown_memory_write(se_ip->litoutput, se_ip->litmem);
1805 __ops_teardown_memory_write(se_ip->se_ip_out, se_ip->se_ip_mem);
1807 se_ip->crypt->decrypt_finish(se_ip->crypt);
1809 free(se_ip->crypt);
1810 free(se_ip);