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