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