writer.c revision 1.27
1/*- 2 * Copyright (c) 2009 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Alistair Crooks (agc@NetBSD.org) 7 * 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. 16 * 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. 28 */ 29/* 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. 35 * 36 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 37 * use this file except in compliance with the License. 38 * 39 * You may obtain a copy of the License at 40 * http://www.apache.org/licenses/LICENSE-2.0 41 * 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. 45 * 46 * See the License for the specific language governing permissions and 47 * limitations under the License. 48 */ 49 50/** \file 51 * This file contains the base functions used by the writers. 52 */ 53#include "config.h" 54 55#ifdef HAVE_SYS_CDEFS_H 56#include <sys/cdefs.h> 57#endif 58 59#if defined(__NetBSD__) 60__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved."); 61__RCSID("$NetBSD: writer.c,v 1.27 2010/08/15 16:10:56 agc Exp $"); 62#endif 63 64#include <sys/types.h> 65 66#include <stdlib.h> 67#include <string.h> 68 69#ifdef HAVE_UNISTD_H 70#include <unistd.h> 71#endif 72 73#ifdef HAVE_OPENSSL_CAST_H 74#include <openssl/cast.h> 75#endif 76 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" 88 89 90/* 91 * return 1 if OK, otherwise 0 92 */ 93static unsigned 94base_write(__ops_output_t *out, const void *src, unsigned len) 95{ 96 return out->writer.writer(src, len, &out->errors, &out->writer); 97} 98 99/** 100 * \ingroup Core_WritePackets 101 * 102 * \param src 103 * \param len 104 * \param output 105 * \return 1 if OK, otherwise 0 106 */ 107 108unsigned 109__ops_write(__ops_output_t *output, const void *src, unsigned len) 110{ 111 return base_write(output, src, len); 112} 113 114/** 115 * \ingroup Core_WritePackets 116 * \param n 117 * \param len 118 * \param output 119 * \return 1 if OK, otherwise 0 120 */ 121 122unsigned 123__ops_write_scalar(__ops_output_t *output, unsigned n, unsigned len) 124{ 125 uint8_t c; 126 127 while (len-- > 0) { 128 c = n >> (len * 8); 129 if (!base_write(output, &c, 1)) { 130 return 0; 131 } 132 } 133 return 1; 134} 135 136/** 137 * \ingroup Core_WritePackets 138 * \param bn 139 * \param output 140 * \return 1 if OK, otherwise 0 141 */ 142 143unsigned 144__ops_write_mpi(__ops_output_t *output, const BIGNUM *bn) 145{ 146 unsigned bits; 147 uint8_t buf[NETPGP_BUFSIZ]; 148 149 bits = (unsigned)BN_num_bits(bn); 150 if (bits > 65535) { 151 (void) fprintf(stderr, "__ops_write_mpi: too large %u\n", bits); 152 return 0; 153 } 154 BN_bn2bin(bn, buf); 155 return __ops_write_scalar(output, bits, 2) && 156 __ops_write(output, buf, (bits + 7) / 8); 157} 158 159/** 160 * \ingroup Core_WritePackets 161 * \param tag 162 * \param output 163 * \return 1 if OK, otherwise 0 164 */ 165 166unsigned 167__ops_write_ptag(__ops_output_t *output, __ops_content_enum tag) 168{ 169 uint8_t c; 170 171 c = tag | OPS_PTAG_ALWAYS_SET | OPS_PTAG_NEW_FORMAT; 172 return base_write(output, &c, 1); 173} 174 175/** 176 * \ingroup Core_WritePackets 177 * \param len 178 * \param output 179 * \return 1 if OK, otherwise 0 180 */ 181 182unsigned 183__ops_write_length(__ops_output_t *output, unsigned len) 184{ 185 uint8_t c[2]; 186 187 if (len < 192) { 188 c[0] = len; 189 return base_write(output, c, 1); 190 } 191 if (len < 8192 + 192) { 192 c[0] = ((len - 192) >> 8) + 192; 193 c[1] = (len - 192) % 256; 194 return base_write(output, c, 2); 195 } 196 return __ops_write_scalar(output, 0xff, 1) && 197 __ops_write_scalar(output, len, 4); 198} 199 200/* 201 * Note that we finalise from the top down, so we don't use writers below 202 * that have already been finalised 203 */ 204unsigned 205__ops_writer_info_finalise(__ops_error_t **errors, __ops_writer_t *writer) 206{ 207 unsigned ret = 1; 208 209 if (writer->finaliser) { 210 ret = writer->finaliser(errors, writer); 211 writer->finaliser = NULL; 212 } 213 if (writer->next && !__ops_writer_info_finalise(errors, writer->next)) { 214 writer->finaliser = NULL; 215 return 0; 216 } 217 return ret; 218} 219 220void 221__ops_writer_info_delete(__ops_writer_t *writer) 222{ 223 /* we should have finalised before deleting */ 224 if (writer->finaliser) { 225 (void) fprintf(stderr, "__ops_writer_info_delete: not done\n"); 226 return; 227 } 228 if (writer->next) { 229 __ops_writer_info_delete(writer->next); 230 free(writer->next); 231 writer->next = NULL; 232 } 233 if (writer->destroyer) { 234 writer->destroyer(writer); 235 writer->destroyer = NULL; 236 } 237 writer->writer = NULL; 238} 239 240/** 241 * \ingroup Core_Writers 242 * 243 * Set a writer in output. There should not be another writer set. 244 * 245 * \param output The output structure 246 * \param writer 247 * \param finaliser 248 * \param destroyer 249 * \param arg The argument for the writer and destroyer 250 */ 251void 252__ops_writer_set(__ops_output_t *output, 253 __ops_writer_func_t *writer, 254 __ops_writer_finaliser_t *finaliser, 255 __ops_writer_destroyer_t *destroyer, 256 void *arg) 257{ 258 if (output->writer.writer) { 259 (void) fprintf(stderr, "__ops_writer_set: already set\n"); 260 } else { 261 output->writer.writer = writer; 262 output->writer.finaliser = finaliser; 263 output->writer.destroyer = destroyer; 264 output->writer.arg = arg; 265 } 266} 267 268/** 269 * \ingroup Core_Writers 270 * 271 * Push a writer in output. There must already be another writer set. 272 * 273 * \param output The output structure 274 * \param writer 275 * \param finaliser 276 * \param destroyer 277 * \param arg The argument for the writer and destroyer 278 */ 279void 280__ops_writer_push(__ops_output_t *output, 281 __ops_writer_func_t *writer, 282 __ops_writer_finaliser_t *finaliser, 283 __ops_writer_destroyer_t *destroyer, 284 void *arg) 285{ 286 __ops_writer_t *copy; 287 288 if ((copy = calloc(1, sizeof(*copy))) == NULL) { 289 (void) fprintf(stderr, "__ops_writer_push: bad alloc\n"); 290 } else if (output->writer.writer == NULL) { 291 (void) fprintf(stderr, "__ops_writer_push: no orig writer\n"); 292 } else { 293 *copy = output->writer; 294 output->writer.next = copy; 295 296 output->writer.writer = writer; 297 output->writer.finaliser = finaliser; 298 output->writer.destroyer = destroyer; 299 output->writer.arg = arg; 300 } 301} 302 303void 304__ops_writer_pop(__ops_output_t *output) 305{ 306 __ops_writer_t *next; 307 308 /* Make sure the finaliser has been called. */ 309 if (output->writer.finaliser) { 310 (void) fprintf(stderr, 311 "__ops_writer_pop: finaliser not called\n"); 312 } else if (output->writer.next == NULL) { 313 (void) fprintf(stderr, 314 "__ops_writer_pop: not a stacked writer\n"); 315 } else { 316 if (output->writer.destroyer) { 317 output->writer.destroyer(&output->writer); 318 } 319 next = output->writer.next; 320 output->writer = *next; 321 free(next); 322 } 323} 324 325/** 326 * \ingroup Core_Writers 327 * 328 * Close the writer currently set in output. 329 * 330 * \param output The output structure 331 */ 332unsigned 333__ops_writer_close(__ops_output_t *output) 334{ 335 unsigned ret; 336 337 ret = __ops_writer_info_finalise(&output->errors, &output->writer); 338 __ops_writer_info_delete(&output->writer); 339 return ret; 340} 341 342/** 343 * \ingroup Core_Writers 344 * 345 * Get the arg supplied to __ops_createinfo_set_writer(). 346 * 347 * \param writer The writer_info structure 348 * \return The arg 349 */ 350void * 351__ops_writer_get_arg(__ops_writer_t *writer) 352{ 353 return writer->arg; 354} 355 356/** 357 * \ingroup Core_Writers 358 * 359 * Write to the next writer down in the stack. 360 * 361 * \param src The data to write. 362 * \param len The length of src. 363 * \param errors A place to store errors. 364 * \param writer The writer_info structure. 365 * \return Success - if 0, then errors should contain the error. 366 */ 367static unsigned 368stacked_write(__ops_writer_t *writer, const void *src, unsigned len, 369 __ops_error_t ** errors) 370{ 371 return writer->next->writer(src, len, errors, writer->next); 372} 373 374/** 375 * \ingroup Core_Writers 376 * 377 * Free the arg. Many writers just have a calloc()ed lump of storage, this 378 * function releases it. 379 * 380 * \param writer the info structure. 381 */ 382static void 383generic_destroyer(__ops_writer_t *writer) 384{ 385 free(__ops_writer_get_arg(writer)); 386} 387 388/** 389 * \ingroup Core_Writers 390 * 391 * A writer that just writes to the next one down. Useful for when you 392 * want to insert just a finaliser into the stack. 393 */ 394unsigned 395__ops_writer_passthrough(const uint8_t *src, 396 unsigned len, 397 __ops_error_t **errors, 398 __ops_writer_t *writer) 399{ 400 return stacked_write(writer, src, len, errors); 401} 402 403/**************************************************************************/ 404 405/** 406 * \struct dashesc_t 407 */ 408typedef struct { 409 unsigned seen_nl:1; 410 unsigned seen_cr:1; 411 __ops_create_sig_t *sig; 412 __ops_memory_t *trailing; 413} dashesc_t; 414 415static unsigned 416dash_esc_writer(const uint8_t *src, 417 unsigned len, 418 __ops_error_t **errors, 419 __ops_writer_t *writer) 420{ 421 dashesc_t *dash = __ops_writer_get_arg(writer); 422 unsigned n; 423 424 if (__ops_get_debug_level(__FILE__)) { 425 unsigned i = 0; 426 427 (void) fprintf(stderr, "dash_esc_writer writing %u:\n", len); 428 for (i = 0; i < len; i++) { 429 fprintf(stderr, "0x%02x ", src[i]); 430 if (((i + 1) % 16) == 0) { 431 (void) fprintf(stderr, "\n"); 432 } else if (((i + 1) % 8) == 0) { 433 (void) fprintf(stderr, " "); 434 } 435 } 436 (void) fprintf(stderr, "\n"); 437 } 438 /* XXX: make this efficient */ 439 for (n = 0; n < len; ++n) { 440 unsigned l; 441 442 if (dash->seen_nl) { 443 if (src[n] == '-' && 444 !stacked_write(writer, "- ", 2, errors)) { 445 return 0; 446 } 447 dash->seen_nl = 0; 448 } 449 dash->seen_nl = src[n] == '\n'; 450 451 if (dash->seen_nl && !dash->seen_cr) { 452 if (!stacked_write(writer, "\r", 1, errors)) { 453 return 0; 454 } 455 __ops_sig_add_data(dash->sig, "\r", 1); 456 } 457 dash->seen_cr = src[n] == '\r'; 458 459 if (!stacked_write(writer, &src[n], 1, errors)) { 460 return 0; 461 } 462 463 /* trailing whitespace isn't included in the signature */ 464 if (src[n] == ' ' || src[n] == '\t') { 465 __ops_memory_add(dash->trailing, &src[n], 1); 466 } else { 467 if ((l = (unsigned)__ops_mem_len(dash->trailing)) != 0) { 468 if (!dash->seen_nl && !dash->seen_cr) { 469 __ops_sig_add_data(dash->sig, 470 __ops_mem_data(dash->trailing), l); 471 } 472 __ops_memory_clear(dash->trailing); 473 } 474 __ops_sig_add_data(dash->sig, &src[n], 1); 475 } 476 } 477 return 1; 478} 479 480/** 481 * \param writer 482 */ 483static void 484dash_escaped_destroyer(__ops_writer_t *writer) 485{ 486 dashesc_t *dash; 487 488 dash = __ops_writer_get_arg(writer); 489 __ops_memory_free(dash->trailing); 490 free(dash); 491} 492 493/** 494 * \ingroup Core_WritersNext 495 * \brief Push Clearsigned Writer onto stack 496 * \param output 497 * \param sig 498 */ 499unsigned 500__ops_writer_push_clearsigned(__ops_output_t *output, __ops_create_sig_t *sig) 501{ 502 static const char header[] = 503 "-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: "; 504 const char *hash; 505 dashesc_t *dash; 506 unsigned ret; 507 508 hash = __ops_text_from_hash(__ops_sig_get_hash(sig)); 509 if ((dash = calloc(1, sizeof(*dash))) == NULL) { 510 OPS_ERROR(&output->errors, OPS_E_W, "Bad alloc"); 511 return 0; 512 } 513 ret = (__ops_write(output, header, (unsigned)(sizeof(header) - 1)) && 514 __ops_write(output, hash, (unsigned)strlen(hash)) && 515 __ops_write(output, "\r\n\r\n", 4)); 516 517 if (ret == 0) { 518 OPS_ERROR(&output->errors, OPS_E_W, 519 "Error pushing clearsigned header"); 520 free(dash); 521 return ret; 522 } 523 dash->seen_nl = 1; 524 dash->sig = sig; 525 dash->trailing = __ops_memory_new(); 526 __ops_writer_push(output, dash_esc_writer, NULL, 527 dash_escaped_destroyer, dash); 528 return ret; 529} 530 531 532/** 533 * \struct base64_t 534 */ 535typedef struct { 536 unsigned pos; 537 uint8_t t; 538 unsigned checksum; 539} base64_t; 540 541static const char b64map[] = 542 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 543 544static unsigned 545base64_writer(const uint8_t *src, 546 unsigned len, 547 __ops_error_t **errors, 548 __ops_writer_t *writer) 549{ 550 base64_t *base64; 551 unsigned n; 552 553 base64 = __ops_writer_get_arg(writer); 554 for (n = 0; n < len;) { 555 base64->checksum = __ops_crc24(base64->checksum, src[n]); 556 if (base64->pos == 0) { 557 /* XXXXXX00 00000000 00000000 */ 558 if (!stacked_write(writer, 559 &b64map[(unsigned)src[n] >> 2], 560 1, errors)) { 561 return 0; 562 } 563 564 /* 000000XX xxxx0000 00000000 */ 565 base64->t = (src[n++] & 3) << 4; 566 base64->pos = 1; 567 } else if (base64->pos == 1) { 568 /* 000000xx XXXX0000 00000000 */ 569 base64->t += (unsigned)src[n] >> 4; 570 if (!stacked_write(writer, &b64map[base64->t], 1, 571 errors)) { 572 return 0; 573 } 574 575 /* 00000000 0000XXXX xx000000 */ 576 base64->t = (src[n++] & 0xf) << 2; 577 base64->pos = 2; 578 } else if (base64->pos == 2) { 579 /* 00000000 0000xxxx XX000000 */ 580 base64->t += (unsigned)src[n] >> 6; 581 if (!stacked_write(writer, &b64map[base64->t], 1, 582 errors)) { 583 return 0; 584 } 585 586 /* 00000000 00000000 00XXXXXX */ 587 if (!stacked_write(writer, 588 &b64map[src[n++] & 0x3f], 1, errors)) { 589 return 0; 590 } 591 592 base64->pos = 0; 593 } 594 } 595 596 return 1; 597} 598 599static unsigned 600sig_finaliser(__ops_error_t **errors, __ops_writer_t *writer) 601{ 602 static const char trail[] = "\r\n-----END PGP SIGNATURE-----\r\n"; 603 base64_t *base64; 604 uint8_t c[3]; 605 606 base64 = __ops_writer_get_arg(writer); 607 if (base64->pos) { 608 if (!stacked_write(writer, &b64map[base64->t], 1, errors)) { 609 return 0; 610 } 611 if (base64->pos == 1 && 612 !stacked_write(writer, "==", 2, errors)) { 613 return 0; 614 } 615 if (base64->pos == 2 && 616 !stacked_write(writer, "=", 1, errors)) { 617 return 0; 618 } 619 } 620 /* Ready for the checksum */ 621 if (!stacked_write(writer, "\r\n=", 3, errors)) { 622 return 0; 623 } 624 625 base64->pos = 0; /* get ready to write the checksum */ 626 627 c[0] = base64->checksum >> 16; 628 c[1] = base64->checksum >> 8; 629 c[2] = base64->checksum; 630 /* push the checksum through our own writer */ 631 if (!base64_writer(c, 3, errors, writer)) { 632 return 0; 633 } 634 635 return stacked_write(writer, trail, (unsigned)(sizeof(trail) - 1), errors); 636} 637 638/** 639 * \struct linebreak_t 640 */ 641typedef struct { 642 unsigned pos; 643} linebreak_t; 644 645#define BREAKPOS 76 646 647static unsigned 648linebreak_writer(const uint8_t *src, 649 unsigned len, 650 __ops_error_t **errors, 651 __ops_writer_t *writer) 652{ 653 linebreak_t *linebreak; 654 unsigned n; 655 656 linebreak = __ops_writer_get_arg(writer); 657 for (n = 0; n < len; ++n, ++linebreak->pos) { 658 if (src[n] == '\r' || src[n] == '\n') { 659 linebreak->pos = 0; 660 } 661 if (linebreak->pos == BREAKPOS) { 662 if (!stacked_write(writer, "\r\n", 2, errors)) { 663 return 0; 664 } 665 linebreak->pos = 0; 666 } 667 if (!stacked_write(writer, &src[n], 1, errors)) { 668 return 0; 669 } 670 } 671 672 return 1; 673} 674 675/** 676 * \ingroup Core_WritersNext 677 * \brief Push armoured signature on stack 678 * \param output 679 */ 680unsigned 681__ops_writer_use_armored_sig(__ops_output_t *output) 682{ 683 static const char header[] = 684 "\r\n-----BEGIN PGP SIGNATURE-----\r\nVersion: " 685 NETPGP_VERSION_STRING 686 "\r\n\r\n"; 687 linebreak_t *linebreak; 688 base64_t *base64; 689 690 __ops_writer_pop(output); 691 if (__ops_write(output, header, (unsigned)(sizeof(header) - 1)) == 0) { 692 OPS_ERROR(&output->errors, OPS_E_W, 693 "Error switching to armoured signature"); 694 return 0; 695 } 696 if ((linebreak = calloc(1, sizeof(*linebreak))) == NULL) { 697 OPS_ERROR(&output->errors, OPS_E_W, 698 "__ops_writer_use_armored_sig: Bad alloc"); 699 return 0; 700 } 701 __ops_writer_push(output, linebreak_writer, NULL, 702 generic_destroyer, 703 linebreak); 704 base64 = calloc(1, sizeof(*base64)); 705 if (!base64) { 706 OPS_MEMORY_ERROR(&output->errors); 707 return 0; 708 } 709 base64->checksum = CRC24_INIT; 710 __ops_writer_push(output, base64_writer, sig_finaliser, 711 generic_destroyer, base64); 712 return 1; 713} 714 715static unsigned 716armoured_message_finaliser(__ops_error_t **errors, __ops_writer_t *writer) 717{ 718 /* TODO: This is same as sig_finaliser apart from trailer. */ 719 static const char trailer[] = 720 "\r\n-----END PGP MESSAGE-----\r\n"; 721 base64_t *base64; 722 uint8_t c[3]; 723 724 base64 = __ops_writer_get_arg(writer); 725 if (base64->pos) { 726 if (!stacked_write(writer, &b64map[base64->t], 1, errors)) { 727 return 0; 728 } 729 if (base64->pos == 1 && 730 !stacked_write(writer, "==", 2, errors)) { 731 return 0; 732 } 733 if (base64->pos == 2 && 734 !stacked_write(writer, "=", 1, errors)) { 735 return 0; 736 } 737 } 738 /* Ready for the checksum */ 739 if (!stacked_write(writer, "\r\n=", 3, errors)) { 740 return 0; 741 } 742 743 base64->pos = 0; /* get ready to write the checksum */ 744 745 c[0] = base64->checksum >> 16; 746 c[1] = base64->checksum >> 8; 747 c[2] = base64->checksum; 748 /* push the checksum through our own writer */ 749 if (!base64_writer(c, 3, errors, writer)) { 750 return 0; 751 } 752 753 return stacked_write(writer, trailer, (unsigned)strlen(trailer), errors); 754} 755 756/** 757 \ingroup Core_WritersNext 758 \brief Write a PGP MESSAGE 759 \todo replace with generic function 760*/ 761void 762__ops_writer_push_armor_msg(__ops_output_t *output) 763{ 764 static const char header[] = "-----BEGIN PGP MESSAGE-----\r\n"; 765 linebreak_t *linebreak; 766 base64_t *base64; 767 768 __ops_write(output, header, (unsigned)(sizeof(header) - 1)); 769 __ops_write(output, "\r\n", 2); 770 if ((linebreak = calloc(1, sizeof(*linebreak))) == NULL) { 771 (void) fprintf(stderr, 772 "__ops_writer_push_armor_msg: bad lb alloc\n"); 773 return; 774 } 775 __ops_writer_push(output, linebreak_writer, NULL, 776 generic_destroyer, 777 linebreak); 778 if ((base64 = calloc(1, sizeof(*base64))) == NULL) { 779 (void) fprintf(stderr, 780 "__ops_writer_push_armor_msg: bad alloc\n"); 781 return; 782 } 783 base64->checksum = CRC24_INIT; 784 __ops_writer_push(output, base64_writer, 785 armoured_message_finaliser, generic_destroyer, 786 base64); 787} 788 789static unsigned 790armoured_finaliser(__ops_armor_type_t type, 791 __ops_error_t **errors, 792 __ops_writer_t *writer) 793{ 794 static const char tail_pubkey[] = 795 "\r\n-----END PGP PUBLIC KEY BLOCK-----\r\n"; 796 static const char tail_private_key[] = 797 "\r\n-----END PGP PRIVATE KEY BLOCK-----\r\n"; 798 const char *tail = NULL; 799 unsigned tailsize = 0; 800 base64_t *base64; 801 uint8_t c[3]; 802 803 switch (type) { 804 case OPS_PGP_PUBLIC_KEY_BLOCK: 805 tail = tail_pubkey; 806 tailsize = sizeof(tail_pubkey) - 1; 807 break; 808 809 case OPS_PGP_PRIVATE_KEY_BLOCK: 810 tail = tail_private_key; 811 tailsize = sizeof(tail_private_key) - 1; 812 break; 813 814 default: 815 (void) fprintf(stderr, "armoured_finaliser: unusual type\n"); 816 return 0; 817 } 818 base64 = __ops_writer_get_arg(writer); 819 if (base64->pos) { 820 if (!stacked_write(writer, &b64map[base64->t], 1, 821 errors)) { 822 return 0; 823 } 824 if (base64->pos == 1 && !stacked_write(writer, "==", 2, 825 errors)) { 826 return 0; 827 } 828 if (base64->pos == 2 && !stacked_write(writer, "=", 1, 829 errors)) { 830 return 0; 831 } 832 } 833 /* Ready for the checksum */ 834 if (!stacked_write(writer, "\r\n=", 3, errors)) { 835 return 0; 836 } 837 base64->pos = 0; /* get ready to write the checksum */ 838 c[0] = base64->checksum >> 16; 839 c[1] = base64->checksum >> 8; 840 c[2] = base64->checksum; 841 /* push the checksum through our own writer */ 842 if (!base64_writer(c, 3, errors, writer)) { 843 return 0; 844 } 845 return stacked_write(writer, tail, tailsize, errors); 846} 847 848static unsigned 849armored_pubkey_fini(__ops_error_t **errors, __ops_writer_t *writer) 850{ 851 return armoured_finaliser(OPS_PGP_PUBLIC_KEY_BLOCK, errors, writer); 852} 853 854static unsigned 855armored_privkey_fini(__ops_error_t **errors, __ops_writer_t *writer) 856{ 857 return armoured_finaliser(OPS_PGP_PRIVATE_KEY_BLOCK, errors, writer); 858} 859 860/* \todo use this for other armoured types */ 861/** 862 \ingroup Core_WritersNext 863 \brief Push Armoured Writer on stack (generic) 864*/ 865void 866__ops_writer_push_armoured(__ops_output_t *output, __ops_armor_type_t type) 867{ 868 static char hdr_pubkey[] = 869 "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: " 870 NETPGP_VERSION_STRING 871 "\r\n\r\n"; 872 static char hdr_private_key[] = 873 "-----BEGIN PGP PRIVATE KEY BLOCK-----\r\nVersion: " 874 NETPGP_VERSION_STRING 875 "\r\n\r\n"; 876 unsigned hdrsize = 0; 877 unsigned (*finaliser) (__ops_error_t **, __ops_writer_t *); 878 base64_t *base64; 879 linebreak_t *linebreak; 880 char *header = NULL; 881 882 finaliser = NULL; 883 switch (type) { 884 case OPS_PGP_PUBLIC_KEY_BLOCK: 885 header = hdr_pubkey; 886 hdrsize = sizeof(hdr_pubkey) - 1; 887 finaliser = armored_pubkey_fini; 888 break; 889 890 case OPS_PGP_PRIVATE_KEY_BLOCK: 891 header = hdr_private_key; 892 hdrsize = sizeof(hdr_private_key) - 1; 893 finaliser = armored_privkey_fini; 894 break; 895 896 default: 897 (void) fprintf(stderr, 898 "__ops_writer_push_armoured: unusual type\n"); 899 return; 900 } 901 if ((linebreak = calloc(1, sizeof(*linebreak))) == NULL) { 902 (void) fprintf(stderr, 903 "__ops_writer_push_armoured: bad alloc\n"); 904 return; 905 } 906 __ops_write(output, header, hdrsize); 907 __ops_writer_push(output, linebreak_writer, NULL, 908 generic_destroyer, 909 linebreak); 910 if ((base64 = calloc(1, sizeof(*base64))) == NULL) { 911 (void) fprintf(stderr, 912 "__ops_writer_push_armoured: bad alloc\n"); 913 return; 914 } 915 base64->checksum = CRC24_INIT; 916 __ops_writer_push(output, base64_writer, finaliser, 917 generic_destroyer, base64); 918} 919 920/**************************************************************************/ 921 922typedef struct { 923 __ops_crypt_t *crypt; 924 int free_crypt; 925} crypt_t; 926 927/* 928 * This writer simply takes plaintext as input, 929 * encrypts it with the given key 930 * and outputs the resulting encrypted text 931 */ 932static unsigned 933encrypt_writer(const uint8_t *src, 934 unsigned len, 935 __ops_error_t **errors, 936 __ops_writer_t *writer) 937{ 938#define BUFSZ 1024 /* arbitrary number */ 939 uint8_t encbuf[BUFSZ]; 940 unsigned remaining; 941 unsigned done = 0; 942 crypt_t *pgp_encrypt; 943 944 remaining = len; 945 pgp_encrypt = (crypt_t *) __ops_writer_get_arg(writer); 946 if (!__ops_is_sa_supported(pgp_encrypt->crypt->alg)) { 947 (void) fprintf(stderr, "encrypt_writer: not supported\n"); 948 return 0; 949 } 950 while (remaining > 0) { 951 unsigned size = (remaining < BUFSZ) ? remaining : BUFSZ; 952 953 /* memcpy(buf,src,size); // \todo copy needed here? */ 954 pgp_encrypt->crypt->cfb_encrypt(pgp_encrypt->crypt, encbuf, 955 src + done, size); 956 957 if (__ops_get_debug_level(__FILE__)) { 958 hexdump(stderr, "unencrypted", &src[done], 16); 959 hexdump(stderr, "encrypted", encbuf, 16); 960 } 961 if (!stacked_write(writer, encbuf, size, errors)) { 962 if (__ops_get_debug_level(__FILE__)) { 963 fprintf(stderr, 964 "encrypted_writer: stacked write\n"); 965 } 966 return 0; 967 } 968 remaining -= size; 969 done += size; 970 } 971 972 return 1; 973} 974 975static void 976encrypt_destroyer(__ops_writer_t *writer) 977{ 978 crypt_t *pgp_encrypt; 979 980 pgp_encrypt = (crypt_t *) __ops_writer_get_arg(writer); 981 if (pgp_encrypt->free_crypt) { 982 free(pgp_encrypt->crypt); 983 } 984 free(pgp_encrypt); 985} 986 987/** 988\ingroup Core_WritersNext 989\brief Push Encrypted Writer onto stack (create SE packets) 990*/ 991void 992__ops_push_enc_crypt(__ops_output_t *output, __ops_crypt_t *pgp_crypt) 993{ 994 /* Create encrypt to be used with this writer */ 995 /* Remember to free this in the destroyer */ 996 crypt_t *pgp_encrypt; 997 998 if ((pgp_encrypt = calloc(1, sizeof(*pgp_encrypt))) == NULL) { 999 (void) fprintf(stderr, "__ops_push_enc_crypt: bad alloc\n"); 1000 } else { 1001 /* Setup the encrypt */ 1002 pgp_encrypt->crypt = pgp_crypt; 1003 pgp_encrypt->free_crypt = 0; 1004 /* And push writer on stack */ 1005 __ops_writer_push(output, encrypt_writer, NULL, 1006 encrypt_destroyer, pgp_encrypt); 1007 } 1008} 1009 1010/**************************************************************************/ 1011 1012typedef struct { 1013 __ops_crypt_t *crypt; 1014} encrypt_se_ip_t; 1015 1016static unsigned encrypt_se_ip_writer(const uint8_t *, 1017 unsigned, 1018 __ops_error_t **, 1019 __ops_writer_t *); 1020static void encrypt_se_ip_destroyer(__ops_writer_t *); 1021 1022/* */ 1023 1024/** 1025\ingroup Core_WritersNext 1026\brief Push Encrypted SE IP Writer onto stack 1027*/ 1028int 1029__ops_push_enc_se_ip(__ops_output_t *output, const __ops_key_t *pubkey) 1030{ 1031 __ops_pk_sesskey_t *encrypted_pk_sesskey; 1032 encrypt_se_ip_t *se_ip; 1033 __ops_crypt_t *encrypted; 1034 uint8_t *iv; 1035 1036 if ((se_ip = calloc(1, sizeof(*se_ip))) == NULL) { 1037 (void) fprintf(stderr, "__ops_push_enc_se_ip: bad alloc\n"); 1038 return 0; 1039 } 1040 1041 /* Create and write encrypted PK session key */ 1042 if ((encrypted_pk_sesskey = __ops_create_pk_sesskey(pubkey)) == NULL) { 1043 (void) fprintf(stderr, "__ops_push_enc_se_ip: null pk sesskey\n"); 1044 return 0; 1045 } 1046 __ops_write_pk_sesskey(output, encrypted_pk_sesskey); 1047 1048 /* Setup the se_ip */ 1049 if ((encrypted = calloc(1, sizeof(*encrypted))) == NULL) { 1050 free(se_ip); 1051 (void) fprintf(stderr, "__ops_push_enc_se_ip: bad alloc\n"); 1052 return 0; 1053 } 1054 __ops_crypt_any(encrypted, encrypted_pk_sesskey->symm_alg); 1055 if ((iv = calloc(1, encrypted->blocksize)) == NULL) { 1056 free(se_ip); 1057 free(encrypted); 1058 (void) fprintf(stderr, "__ops_push_enc_se_ip: bad alloc\n"); 1059 return 0; 1060 } 1061 encrypted->set_iv(encrypted, iv); 1062 encrypted->set_crypt_key(encrypted, &encrypted_pk_sesskey->key[0]); 1063 __ops_encrypt_init(encrypted); 1064 1065 se_ip->crypt = encrypted; 1066 1067 /* And push writer on stack */ 1068 __ops_writer_push(output, encrypt_se_ip_writer, NULL, 1069 encrypt_se_ip_destroyer, se_ip); 1070 /* tidy up */ 1071 free(encrypted_pk_sesskey); 1072 free(iv); 1073 return 1; 1074} 1075 1076static unsigned 1077encrypt_se_ip_writer(const uint8_t *src, 1078 unsigned len, 1079 __ops_error_t **errors, 1080 __ops_writer_t *writer) 1081{ 1082 const unsigned bufsz = 128; 1083 encrypt_se_ip_t *se_ip = __ops_writer_get_arg(writer); 1084 __ops_output_t *litoutput; 1085 __ops_output_t *zoutput; 1086 __ops_output_t *output; 1087 __ops_memory_t *litmem; 1088 __ops_memory_t *zmem; 1089 __ops_memory_t *localmem; 1090 unsigned ret = 1; 1091 1092 __ops_setup_memory_write(&litoutput, &litmem, bufsz); 1093 __ops_setup_memory_write(&zoutput, &zmem, bufsz); 1094 __ops_setup_memory_write(&output, &localmem, bufsz); 1095 1096 /* create literal data packet from source data */ 1097 __ops_write_litdata(litoutput, src, (const int)len, OPS_LDT_BINARY); 1098 if (__ops_mem_len(litmem) <= len) { 1099 (void) fprintf(stderr, "encrypt_se_ip_writer: bad len\n"); 1100 return 0; 1101 } 1102 1103 /* create compressed packet from literal data packet */ 1104 __ops_writez(zoutput, __ops_mem_data(litmem), (unsigned)__ops_mem_len(litmem)); 1105 1106 /* create SE IP packet set from this compressed literal data */ 1107 __ops_write_se_ip_pktset(output, __ops_mem_data(zmem), 1108 (unsigned)__ops_mem_len(zmem), 1109 se_ip->crypt); 1110 if (__ops_mem_len(localmem) <= __ops_mem_len(zmem)) { 1111 (void) fprintf(stderr, 1112 "encrypt_se_ip_writer: bad comp len\n"); 1113 return 0; 1114 } 1115 1116 /* now write memory to next writer */ 1117 ret = stacked_write(writer, __ops_mem_data(localmem), 1118 (unsigned)__ops_mem_len(localmem), errors); 1119 1120 __ops_memory_free(localmem); 1121 __ops_memory_free(zmem); 1122 __ops_memory_free(litmem); 1123 1124 return ret; 1125} 1126 1127static void 1128encrypt_se_ip_destroyer(__ops_writer_t *writer) 1129{ 1130 encrypt_se_ip_t *se_ip; 1131 1132 se_ip = __ops_writer_get_arg(writer); 1133 free(se_ip->crypt); 1134 free(se_ip); 1135} 1136 1137unsigned 1138__ops_write_se_ip_pktset(__ops_output_t *output, 1139 const uint8_t *data, 1140 const unsigned len, 1141 __ops_crypt_t *crypted) 1142{ 1143 __ops_output_t *mdcoutput; 1144 __ops_memory_t *mdc; 1145 uint8_t hashed[OPS_SHA1_HASH_SIZE]; 1146 uint8_t *preamble; 1147 const size_t mdcsize = 1 + 1 + OPS_SHA1_HASH_SIZE; 1148 size_t preamblesize; 1149 size_t bufsize; 1150 1151 preamblesize = crypted->blocksize + 2; 1152 if ((preamble = calloc(1, preamblesize)) == NULL) { 1153 (void) fprintf(stderr, "__ops_write_se_ip_pktset: bad alloc\n"); 1154 return 0; 1155 } 1156 bufsize = preamblesize + len + mdcsize; 1157 1158 if (!__ops_write_ptag(output, OPS_PTAG_CT_SE_IP_DATA) || 1159 !__ops_write_length(output, (unsigned)(1 + bufsize)) || 1160 !__ops_write_scalar(output, OPS_SE_IP_DATA_VERSION, 1)) { 1161 free(preamble); 1162 return 0; 1163 } 1164 __ops_random(preamble, crypted->blocksize); 1165 preamble[crypted->blocksize] = preamble[crypted->blocksize - 2]; 1166 preamble[crypted->blocksize + 1] = preamble[crypted->blocksize - 1]; 1167 1168 if (__ops_get_debug_level(__FILE__)) { 1169 hexdump(stderr, "preamble", preamble, preamblesize); 1170 } 1171 1172 /* now construct MDC packet and add to the end of the buffer */ 1173 __ops_setup_memory_write(&mdcoutput, &mdc, mdcsize); 1174 __ops_calc_mdc_hash(preamble, preamblesize, data, len, &hashed[0]); 1175 __ops_write_mdc(mdcoutput, hashed); 1176 1177 if (__ops_get_debug_level(__FILE__)) { 1178 hexdump(stderr, "plaintext", data, len); 1179 hexdump(stderr, "mdc", __ops_mem_data(mdc), OPS_SHA1_HASH_SIZE + 1 + 1); 1180 } 1181 1182 /* and write it out */ 1183 __ops_push_enc_crypt(output, crypted); 1184 if (__ops_get_debug_level(__FILE__)) { 1185 (void) fprintf(stderr, 1186 "writing %" PRIsize "u + %u + %" PRIsize "u\n", 1187 preamblesize, len, __ops_mem_len(mdc)); 1188 } 1189 if (!__ops_write(output, preamble, (unsigned)preamblesize) || 1190 !__ops_write(output, data, len) || 1191 !__ops_write(output, __ops_mem_data(mdc), (unsigned)__ops_mem_len(mdc))) { 1192 /* \todo fix cleanup here and in old code functions */ 1193 return 0; 1194 } 1195 1196 __ops_writer_pop(output); 1197 1198 /* cleanup */ 1199 __ops_teardown_memory_write(mdcoutput, mdc); 1200 free(preamble); 1201 1202 return 1; 1203} 1204 1205typedef struct { 1206 int fd; 1207} writer_fd_t; 1208 1209static unsigned 1210fd_writer(const uint8_t *src, unsigned len, 1211 __ops_error_t **errors, 1212 __ops_writer_t *writer) 1213{ 1214 writer_fd_t *writerfd; 1215 int n; 1216 1217 writerfd = __ops_writer_get_arg(writer); 1218 n = (int)write(writerfd->fd, src, len); 1219 if (n == -1) { 1220 OPS_SYSTEM_ERROR_1(errors, OPS_E_W_WRITE_FAILED, "write", 1221 "file descriptor %d", writerfd->fd); 1222 return 0; 1223 } 1224 if ((unsigned) n != len) { 1225 OPS_ERROR_1(errors, OPS_E_W_WRITE_TOO_SHORT, 1226 "file descriptor %d", writerfd->fd); 1227 return 0; 1228 } 1229 return 1; 1230} 1231 1232static void 1233writer_fd_destroyer(__ops_writer_t *writer) 1234{ 1235 free(__ops_writer_get_arg(writer)); 1236} 1237 1238/** 1239 * \ingroup Core_WritersFirst 1240 * \brief Write to a File 1241 * 1242 * Set the writer in output to be a stock writer that writes to a file 1243 * descriptor. If another writer has already been set, then that is 1244 * first destroyed. 1245 * 1246 * \param output The output structure 1247 * \param fd The file descriptor 1248 * 1249 */ 1250 1251void 1252__ops_writer_set_fd(__ops_output_t *output, int fd) 1253{ 1254 writer_fd_t *writer; 1255 1256 if ((writer = calloc(1, sizeof(*writer))) == NULL) { 1257 (void) fprintf(stderr, "__ops_writer_set_fd: bad alloc\n"); 1258 } else { 1259 writer->fd = fd; 1260 __ops_writer_set(output, fd_writer, NULL, writer_fd_destroyer, writer); 1261 } 1262} 1263 1264static unsigned 1265memory_writer(const uint8_t *src, 1266 unsigned len, 1267 __ops_error_t **errors, 1268 __ops_writer_t *writer) 1269{ 1270 __ops_memory_t *mem; 1271 1272 __OPS_USED(errors); 1273 mem = __ops_writer_get_arg(writer); 1274 __ops_memory_add(mem, src, len); 1275 return 1; 1276} 1277 1278/** 1279 * \ingroup Core_WritersFirst 1280 * \brief Write to memory 1281 * 1282 * Set a memory writer. 1283 * 1284 * \param output The output structure 1285 * \param mem The memory structure 1286 * \note It is the caller's responsiblity to call __ops_memory_free(mem) 1287 * \sa __ops_memory_free() 1288 */ 1289 1290void 1291__ops_writer_set_memory(__ops_output_t *output, __ops_memory_t *mem) 1292{ 1293 __ops_writer_set(output, memory_writer, NULL, NULL, mem); 1294} 1295 1296/**************************************************************************/ 1297 1298typedef struct { 1299 __ops_hash_alg_t hash_alg; 1300 __ops_hash_t hash; 1301 uint8_t *hashed; 1302} skey_checksum_t; 1303 1304static unsigned 1305skey_checksum_writer(const uint8_t *src, 1306 const unsigned len, 1307 __ops_error_t **errors, 1308 __ops_writer_t *writer) 1309{ 1310 skey_checksum_t *sum; 1311 unsigned ret = 1; 1312 1313 sum = __ops_writer_get_arg(writer); 1314 /* add contents to hash */ 1315 sum->hash.add(&sum->hash, src, len); 1316 /* write to next stacked writer */ 1317 ret = stacked_write(writer, src, len, errors); 1318 /* tidy up and return */ 1319 return ret; 1320} 1321 1322static unsigned 1323skey_checksum_finaliser(__ops_error_t **errors, __ops_writer_t *writer) 1324{ 1325 skey_checksum_t *sum; 1326 1327 sum = __ops_writer_get_arg(writer); 1328 if (errors && *errors) { 1329 printf("errors in skey_checksum_finaliser\n"); 1330 } 1331 (*sum->hash.finish)(&sum->hash, sum->hashed); 1332 return 1; 1333} 1334 1335static void 1336skey_checksum_destroyer(__ops_writer_t *writer) 1337{ 1338 skey_checksum_t *sum; 1339 1340 sum = __ops_writer_get_arg(writer); 1341 free(sum); 1342} 1343 1344/** 1345\ingroup Core_WritersNext 1346\param output 1347\param seckey 1348*/ 1349void 1350__ops_push_checksum_writer(__ops_output_t *output, __ops_seckey_t *seckey) 1351{ 1352 /* XXX: push a SHA-1 checksum writer (and change s2k to 254). */ 1353 skey_checksum_t *sum; 1354 1355 if ((sum = calloc(1, sizeof(*sum))) == NULL) { 1356 (void) fprintf(stderr, 1357 "__ops_push_checksum_writer: bad alloc\n"); 1358 } else { 1359 /* configure the arg */ 1360 sum->hash_alg = seckey->hash_alg; 1361 if ((sum->hashed = seckey->checkhash) == NULL) { 1362 sum->hashed = seckey->checkhash = calloc(1, OPS_CHECKHASH_SIZE); 1363 } 1364 /* init the hash */ 1365 __ops_hash_any(&sum->hash, sum->hash_alg); 1366 if (!sum->hash.init(&sum->hash)) { 1367 (void) fprintf(stderr, 1368 "__ops_push_checksum_writer: bad hash init\n"); 1369 /* just continue and die */ 1370 /* XXX - agc - no way to return failure */ 1371 } 1372 __ops_writer_push(output, skey_checksum_writer, 1373 skey_checksum_finaliser, skey_checksum_destroyer, sum); 1374 } 1375} 1376 1377/**************************************************************************/ 1378 1379#define MAX_PARTIAL_DATA_LENGTH 1073741824 1380 1381typedef struct { 1382 __ops_crypt_t *crypt; 1383 __ops_memory_t *mem_data; 1384 __ops_memory_t *litmem; 1385 __ops_output_t *litoutput; 1386 __ops_memory_t *se_ip_mem; 1387 __ops_output_t *se_ip_out; 1388 __ops_hash_t hash; 1389} str_enc_se_ip_t; 1390 1391 1392static unsigned 1393str_enc_se_ip_writer(const uint8_t *src, 1394 unsigned len, 1395 __ops_error_t **errors, 1396 __ops_writer_t *writer); 1397 1398static unsigned 1399str_enc_se_ip_finaliser(__ops_error_t **errors, 1400 __ops_writer_t * writer); 1401 1402static void str_enc_se_ip_destroyer(__ops_writer_t *writer); 1403 1404/* */ 1405 1406/** 1407\ingroup Core_WritersNext 1408\param output 1409\param pubkey 1410*/ 1411void 1412__ops_push_stream_enc_se_ip(__ops_output_t *output, const __ops_key_t *pubkey) 1413{ 1414 __ops_pk_sesskey_t *encrypted_pk_sesskey; 1415 str_enc_se_ip_t *se_ip; 1416 const unsigned bufsz = 1024; 1417 __ops_crypt_t *encrypted; 1418 uint8_t *iv; 1419 1420 if ((se_ip = calloc(1, sizeof(*se_ip))) == NULL) { 1421 (void) fprintf(stderr, 1422 "__ops_push_stream_enc_se_ip: bad alloc\n"); 1423 return; 1424 } 1425 encrypted_pk_sesskey = __ops_create_pk_sesskey(pubkey); 1426 __ops_write_pk_sesskey(output, encrypted_pk_sesskey); 1427 1428 /* Setup the se_ip */ 1429 if ((encrypted = calloc(1, sizeof(*encrypted))) == NULL) { 1430 free(se_ip); 1431 (void) fprintf(stderr, 1432 "__ops_push_stream_enc_se_ip: bad alloc\n"); 1433 return; 1434 } 1435 __ops_crypt_any(encrypted, encrypted_pk_sesskey->symm_alg); 1436 if ((iv = calloc(1, encrypted->blocksize)) == NULL) { 1437 free(encrypted); 1438 free(se_ip); 1439 (void) fprintf(stderr, 1440 "__ops_push_stream_enc_se_ip: bad alloc\n"); 1441 return; 1442 } 1443 encrypted->set_iv(encrypted, iv); 1444 encrypted->set_crypt_key(encrypted, &encrypted_pk_sesskey->key[0]); 1445 __ops_encrypt_init(encrypted); 1446 1447 se_ip->crypt = encrypted; 1448 1449 se_ip->mem_data = __ops_memory_new(); 1450 __ops_memory_init(se_ip->mem_data, bufsz); 1451 1452 se_ip->litmem = NULL; 1453 se_ip->litoutput = NULL; 1454 1455 __ops_setup_memory_write(&se_ip->se_ip_out, &se_ip->se_ip_mem, bufsz); 1456 1457 /* And push writer on stack */ 1458 __ops_writer_push(output, 1459 str_enc_se_ip_writer, 1460 str_enc_se_ip_finaliser, 1461 str_enc_se_ip_destroyer, se_ip); 1462 /* tidy up */ 1463 free(encrypted_pk_sesskey); 1464 free(iv); 1465} 1466 1467 1468/* calculate the partial data length */ 1469static unsigned 1470__ops_partial_data_len(unsigned len) 1471{ 1472 unsigned mask; 1473 int i; 1474 1475 if (len == 0) { 1476 (void) fprintf(stderr, "__ops_partial_data_len: 0 len\n"); 1477 return 0; 1478 } 1479 if (len > MAX_PARTIAL_DATA_LENGTH) { 1480 return MAX_PARTIAL_DATA_LENGTH; 1481 } 1482 mask = MAX_PARTIAL_DATA_LENGTH; 1483 for (i = 0; i <= 30; i++) { 1484 if (mask & len) { 1485 break; 1486 } 1487 mask >>= 1; 1488 } 1489 return mask; 1490} 1491 1492static unsigned 1493write_partial_len(__ops_output_t *output, unsigned len) 1494{ 1495 /* len must be a power of 2 from 0 to 30 */ 1496 uint8_t c; 1497 int i; 1498 1499 for (i = 0; i <= 30; i++) { 1500 if ((len >> i) & 1) { 1501 break; 1502 } 1503 } 1504 c = 224 + i; 1505 return __ops_write(output, &c, 1); 1506} 1507 1508static unsigned 1509stream_write_litdata(__ops_output_t *output, 1510 const uint8_t *data, 1511 unsigned len) 1512{ 1513 size_t pdlen; 1514 1515 while (len > 0) { 1516 pdlen = __ops_partial_data_len(len); 1517 write_partial_len(output, (unsigned)pdlen); 1518 __ops_write(output, data, (unsigned)pdlen); 1519 data += pdlen; 1520 len -= (unsigned)pdlen; 1521 } 1522 return 1; 1523} 1524 1525static unsigned 1526stream_write_litdata_first(__ops_output_t *output, 1527 const uint8_t *data, 1528 unsigned len, 1529 const __ops_litdata_enum type) 1530{ 1531 /* \todo add filename */ 1532 /* \todo add date */ 1533 /* \todo do we need to check text data for <cr><lf> line endings ? */ 1534 1535 unsigned sz_towrite; 1536 size_t sz_pd; 1537 1538 sz_towrite = 1 + 1 + 4 + len; 1539 sz_pd = (size_t)__ops_partial_data_len(sz_towrite); 1540 if (sz_pd < 512) { 1541 (void) fprintf(stderr, 1542 "stream_write_litdata_first: bad sz_pd\n"); 1543 return 0; 1544 } 1545 __ops_write_ptag(output, OPS_PTAG_CT_LITDATA); 1546 write_partial_len(output, (unsigned)sz_pd); 1547 __ops_write_scalar(output, (unsigned)type, 1); 1548 __ops_write_scalar(output, 0, 1); 1549 __ops_write_scalar(output, 0, 4); 1550 __ops_write(output, data, (unsigned)(sz_pd - 6)); 1551 1552 data += (sz_pd - 6); 1553 sz_towrite -= sz_pd; 1554 1555 return stream_write_litdata(output, data, (unsigned)sz_towrite); 1556} 1557 1558static unsigned 1559stream_write_litdata_last(__ops_output_t *output, 1560 const uint8_t *data, 1561 unsigned len) 1562{ 1563 __ops_write_length(output, len); 1564 return __ops_write(output, data, len); 1565} 1566 1567static unsigned 1568stream_write_se_ip(__ops_output_t *output, 1569 const uint8_t *data, 1570 unsigned len, 1571 str_enc_se_ip_t *se_ip) 1572{ 1573 size_t pdlen; 1574 1575 while (len > 0) { 1576 pdlen = __ops_partial_data_len(len); 1577 write_partial_len(output, (unsigned)pdlen); 1578 1579 __ops_push_enc_crypt(output, se_ip->crypt); 1580 __ops_write(output, data, (unsigned)pdlen); 1581 __ops_writer_pop(output); 1582 1583 se_ip->hash.add(&se_ip->hash, data, (unsigned)pdlen); 1584 1585 data += pdlen; 1586 len -= pdlen; 1587 } 1588 return 1; 1589} 1590 1591static unsigned 1592stream_write_se_ip_first(__ops_output_t *output, 1593 const uint8_t *data, 1594 unsigned len, 1595 str_enc_se_ip_t *se_ip) 1596{ 1597 uint8_t *preamble; 1598 size_t blocksize; 1599 size_t preamblesize; 1600 size_t sz_towrite; 1601 size_t sz_pd; 1602 1603 blocksize = se_ip->crypt->blocksize; 1604 preamblesize = blocksize + 2; 1605 sz_towrite = preamblesize + 1 + len; 1606 if ((preamble = calloc(1, preamblesize)) == NULL) { 1607 (void) fprintf(stderr, 1608 "stream_write_se_ip_first: bad alloc\n"); 1609 return 0; 1610 } 1611 sz_pd = (size_t)__ops_partial_data_len((unsigned)sz_towrite); 1612 if (sz_pd < 512) { 1613 free(preamble); 1614 (void) fprintf(stderr, 1615 "stream_write_se_ip_first: bad sz_pd\n"); 1616 return 0; 1617 } 1618 __ops_write_ptag(output, OPS_PTAG_CT_SE_IP_DATA); 1619 write_partial_len(output, (unsigned)sz_pd); 1620 __ops_write_scalar(output, OPS_SE_IP_DATA_VERSION, 1); 1621 __ops_push_enc_crypt(output, se_ip->crypt); 1622 1623 __ops_random(preamble, blocksize); 1624 preamble[blocksize] = preamble[blocksize - 2]; 1625 preamble[blocksize + 1] = preamble[blocksize - 1]; 1626 __ops_hash_any(&se_ip->hash, OPS_HASH_SHA1); 1627 if (!se_ip->hash.init(&se_ip->hash)) { 1628 free(preamble); 1629 (void) fprintf(stderr, 1630 "stream_write_se_ip_first: bad hash init\n"); 1631 return 0; 1632 } 1633 __ops_write(output, preamble, (unsigned)preamblesize); 1634 se_ip->hash.add(&se_ip->hash, preamble, (unsigned)preamblesize); 1635 __ops_write(output, data, (unsigned)(sz_pd - preamblesize - 1)); 1636 se_ip->hash.add(&se_ip->hash, data, (unsigned)(sz_pd - preamblesize - 1)); 1637 data += (sz_pd - preamblesize - 1); 1638 sz_towrite -= sz_pd; 1639 __ops_writer_pop(output); 1640 stream_write_se_ip(output, data, (unsigned)sz_towrite, se_ip); 1641 free(preamble); 1642 return 1; 1643} 1644 1645static unsigned 1646stream_write_se_ip_last(__ops_output_t *output, 1647 const uint8_t *data, 1648 unsigned len, 1649 str_enc_se_ip_t *se_ip) 1650{ 1651 __ops_output_t *mdcoutput; 1652 __ops_memory_t *mdcmem; 1653 const size_t mdcsize = 1 + 1 + OPS_SHA1_HASH_SIZE; 1654 uint8_t c; 1655 uint8_t hashed[OPS_SHA1_HASH_SIZE]; 1656 size_t bufsize = len + mdcsize; 1657 1658 se_ip->hash.add(&se_ip->hash, data, len); 1659 1660 /* MDC packet tag */ 1661 c = MDC_PKT_TAG; 1662 se_ip->hash.add(&se_ip->hash, &c, 1); 1663 1664 /* MDC packet len */ 1665 c = OPS_SHA1_HASH_SIZE; 1666 se_ip->hash.add(&se_ip->hash, &c, 1); 1667 1668 /* finish */ 1669 se_ip->hash.finish(&se_ip->hash, hashed); 1670 1671 __ops_setup_memory_write(&mdcoutput, &mdcmem, mdcsize); 1672 __ops_write_mdc(mdcoutput, hashed); 1673 1674 /* write length of last se_ip chunk */ 1675 __ops_write_length(output, (unsigned)bufsize); 1676 1677 /* encode everting */ 1678 __ops_push_enc_crypt(output, se_ip->crypt); 1679 1680 __ops_write(output, data, len); 1681 __ops_write(output, __ops_mem_data(mdcmem), (unsigned)__ops_mem_len(mdcmem)); 1682 1683 __ops_writer_pop(output); 1684 1685 __ops_teardown_memory_write(mdcoutput, mdcmem); 1686 1687 return 1; 1688} 1689 1690static unsigned 1691str_enc_se_ip_writer(const uint8_t *src, 1692 unsigned len, 1693 __ops_error_t **errors, 1694 __ops_writer_t *writer) 1695{ 1696 str_enc_se_ip_t *se_ip; 1697 unsigned ret; 1698 size_t datalength; 1699 1700 se_ip = __ops_writer_get_arg(writer); 1701 ret = 1; 1702 if (se_ip->litoutput == NULL) { 1703 /* first literal data chunk is not yet written */ 1704 1705 __ops_memory_add(se_ip->mem_data, src, len); 1706 datalength = __ops_mem_len(se_ip->mem_data); 1707 1708 /* 4.2.2.4. Partial Body Lengths */ 1709 /* The first partial length MUST be at least 512 octets long. */ 1710 if (datalength < 512) { 1711 return 1; /* will wait for more data or 1712 * end of stream */ 1713 } 1714 __ops_setup_memory_write(&se_ip->litoutput, 1715 &se_ip->litmem, datalength + 32); 1716 stream_write_litdata_first(se_ip->litoutput, 1717 __ops_mem_data(se_ip->mem_data), 1718 (unsigned)datalength, 1719 OPS_LDT_BINARY); 1720 1721 stream_write_se_ip_first(se_ip->se_ip_out, 1722 __ops_mem_data(se_ip->litmem), 1723 (unsigned)__ops_mem_len(se_ip->litmem), se_ip); 1724 } else { 1725 stream_write_litdata(se_ip->litoutput, src, len); 1726 stream_write_se_ip(se_ip->se_ip_out, 1727 __ops_mem_data(se_ip->litmem), 1728 (unsigned)__ops_mem_len(se_ip->litmem), se_ip); 1729 } 1730 1731 /* now write memory to next writer */ 1732 ret = stacked_write(writer, __ops_mem_data(se_ip->se_ip_mem), 1733 (unsigned)__ops_mem_len(se_ip->se_ip_mem), errors); 1734 1735 __ops_memory_clear(se_ip->litmem); 1736 __ops_memory_clear(se_ip->se_ip_mem); 1737 1738 return ret; 1739} 1740 1741/* write last chunk of data */ 1742static unsigned 1743str_enc_se_ip_finaliser(__ops_error_t **errors, __ops_writer_t *writer) 1744{ 1745 str_enc_se_ip_t *se_ip; 1746 1747 se_ip = __ops_writer_get_arg(writer); 1748 if (se_ip->litoutput == NULL) { 1749 /* first literal data chunk was not written */ 1750 /* so we know the total length of data, write a simple packet */ 1751 1752 /* create literal data packet from buffered data */ 1753 __ops_setup_memory_write(&se_ip->litoutput, &se_ip->litmem, 1754 __ops_mem_len(se_ip->mem_data) + 32); 1755 1756 __ops_write_litdata(se_ip->litoutput, 1757 __ops_mem_data(se_ip->mem_data), 1758 (const int)__ops_mem_len(se_ip->mem_data), 1759 OPS_LDT_BINARY); 1760 1761 /* create SE IP packet set from this literal data */ 1762 __ops_write_se_ip_pktset(se_ip->se_ip_out, 1763 __ops_mem_data(se_ip->litmem), 1764 (unsigned)__ops_mem_len(se_ip->litmem), 1765 se_ip->crypt); 1766 1767 } else { 1768 /* finish writing */ 1769 stream_write_litdata_last(se_ip->litoutput, NULL, 0); 1770 stream_write_se_ip_last(se_ip->se_ip_out, 1771 __ops_mem_data(se_ip->litmem), 1772 (unsigned)__ops_mem_len(se_ip->litmem), se_ip); 1773 } 1774 1775 /* now write memory to next writer */ 1776 return stacked_write(writer, __ops_mem_data(se_ip->se_ip_mem), 1777 (unsigned)__ops_mem_len(se_ip->se_ip_mem), errors); 1778} 1779 1780static void 1781str_enc_se_ip_destroyer(__ops_writer_t *writer) 1782{ 1783 str_enc_se_ip_t *se_ip; 1784 1785 se_ip = __ops_writer_get_arg(writer); 1786 __ops_memory_free(se_ip->mem_data); 1787 __ops_teardown_memory_write(se_ip->litoutput, se_ip->litmem); 1788 __ops_teardown_memory_write(se_ip->se_ip_out, se_ip->se_ip_mem); 1789 1790 se_ip->crypt->decrypt_finish(se_ip->crypt); 1791 1792 free(se_ip->crypt); 1793 free(se_ip); 1794} 1795