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