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 #include "config.h" 50 51 #ifdef HAVE_SYS_CDEFS_H 52 #include <sys/cdefs.h> 53 #endif 54 55 #if defined(__NetBSD__) 56 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved."); 57 __RCSID("$NetBSD: validate.c,v 1.19 2009/06/11 01:12:42 agc Exp $"); 58 #endif 59 60 #include <sys/types.h> 61 #include <sys/param.h> 62 #include <sys/stat.h> 63 64 #include <string.h> 65 #include <stdio.h> 66 67 #ifdef HAVE_UNISTD_H 68 #include <unistd.h> 69 #endif 70 71 #ifdef HAVE_FCNTL_H 72 #include <fcntl.h> 73 #endif 74 75 #include "packet-parse.h" 76 #include "packet-show.h" 77 #include "keyring.h" 78 #include "signature.h" 79 #include "netpgpsdk.h" 80 #include "readerwriter.h" 81 #include "netpgpdefs.h" 82 #include "memory.h" 83 #include "packet.h" 84 #include "crypto.h" 85 #include "validate.h" 86 87 #ifdef HAVE_FCNTL_H 88 #include <fcntl.h> 89 #endif 90 91 92 /* Does the signed hash match the given hash? */ 93 static unsigned 94 check_binary_sig(const unsigned len, 95 const unsigned char *data, 96 const __ops_sig_t *sig, 97 const __ops_pubkey_t *signer) 98 { 99 unsigned char hashout[OPS_MAX_HASH_SIZE]; 100 unsigned char trailer[6]; 101 unsigned int hashedlen; 102 __ops_hash_t hash; 103 unsigned n = 0; 104 105 __OPS_USED(signer); 106 __ops_hash_any(&hash, sig->info.hash_alg); 107 hash.init(&hash); 108 hash.add(&hash, data, len); 109 switch (sig->info.version) { 110 case OPS_V3: 111 trailer[0] = sig->info.type; 112 trailer[1] = (unsigned)(sig->info.birthtime) >> 24; 113 trailer[2] = (unsigned)(sig->info.birthtime) >> 16; 114 trailer[3] = (unsigned)(sig->info.birthtime) >> 8; 115 trailer[4] = (unsigned char)(sig->info.birthtime); 116 hash.add(&hash, &trailer[0], 5); 117 break; 118 119 case OPS_V4: 120 hash.add(&hash, sig->info.v4_hashed, sig->info.v4_hashlen); 121 trailer[0] = 0x04; /* version */ 122 trailer[1] = 0xFF; 123 hashedlen = sig->info.v4_hashlen; 124 trailer[2] = hashedlen >> 24; 125 trailer[3] = hashedlen >> 16; 126 trailer[4] = hashedlen >> 8; 127 trailer[5] = hashedlen; 128 hash.add(&hash, trailer, 6); 129 break; 130 131 default: 132 (void) fprintf(stderr, "Invalid signature version %d\n", 133 sig->info.version); 134 return 0; 135 } 136 137 n = hash.finish(&hash, hashout); 138 if (__ops_get_debug_level(__FILE__)) { 139 printf("check_binary_sig: hash length %" PRIsize "u\n", 140 hash.size); 141 } 142 return __ops_check_sig(hashout, n, sig, signer); 143 } 144 145 static int 146 keydata_reader(void *dest, size_t length, __ops_error_t **errors, 147 __ops_reader_t *readinfo, 148 __ops_cbdata_t *cbinfo) 149 { 150 validate_reader_t *reader = __ops_reader_get_arg(readinfo); 151 152 __OPS_USED(errors); 153 __OPS_USED(cbinfo); 154 if (reader->offset == reader->key->packets[reader->packet].length) { 155 reader->packet += 1; 156 reader->offset = 0; 157 } 158 if (reader->packet == reader->key->packetc) { 159 return 0; 160 } 161 162 /* 163 * we should never be asked to cross a packet boundary in a single 164 * read 165 */ 166 if (reader->key->packets[reader->packet].length < 167 reader->offset + length) { 168 (void) fprintf(stderr, "keydata_reader: weird length\n"); 169 return 0; 170 } 171 172 (void) memcpy(dest, 173 &reader->key->packets[reader->packet].raw[reader->offset], 174 length); 175 reader->offset += length; 176 177 return length; 178 } 179 180 static void 181 free_sig_info(__ops_sig_info_t *sig) 182 { 183 (void) free(sig->v4_hashed); 184 (void) free(sig); 185 } 186 187 static void 188 copy_sig_info(__ops_sig_info_t *dst, const __ops_sig_info_t *src) 189 { 190 (void) memcpy(dst, src, sizeof(*src)); 191 dst->v4_hashed = calloc(1, src->v4_hashlen); 192 (void) memcpy(dst->v4_hashed, src->v4_hashed, src->v4_hashlen); 193 } 194 195 static void 196 add_sig_to_list(const __ops_sig_info_t *sig, __ops_sig_info_t **sigs, 197 unsigned *count) 198 { 199 if (*count == 0) { 200 *sigs = calloc(*count + 1, sizeof(__ops_sig_info_t)); 201 } else { 202 *sigs = realloc(*sigs, 203 (*count + 1) * sizeof(__ops_sig_info_t)); 204 } 205 copy_sig_info(&(*sigs)[*count], sig); 206 *count += 1; 207 } 208 209 210 __ops_cb_ret_t 211 __ops_validate_key_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo) 212 { 213 const __ops_contents_t *content = &pkt->u; 214 const __ops_key_t *signer; 215 validate_key_cb_t *key; 216 __ops_error_t **errors; 217 __ops_io_t *io; 218 unsigned valid = 0; 219 220 io = cbinfo->io; 221 if (__ops_get_debug_level(__FILE__)) { 222 (void) fprintf(io->errs, "%s\n", 223 __ops_show_packet_tag(pkt->tag)); 224 } 225 key = __ops_callback_arg(cbinfo); 226 errors = __ops_callback_errors(cbinfo); 227 switch (pkt->tag) { 228 case OPS_PTAG_CT_PUBLIC_KEY: 229 if (key->pubkey.version != 0) { 230 (void) fprintf(io->errs, 231 "__ops_validate_key_cb: version bad\n"); 232 return OPS_FINISHED; 233 } 234 key->pubkey = content->pubkey; 235 return OPS_KEEP_MEMORY; 236 237 case OPS_PTAG_CT_PUBLIC_SUBKEY: 238 if (key->subkey.version) { 239 __ops_pubkey_free(&key->subkey); 240 } 241 key->subkey = content->pubkey; 242 return OPS_KEEP_MEMORY; 243 244 case OPS_PTAG_CT_SECRET_KEY: 245 key->seckey = content->seckey; 246 key->pubkey = key->seckey.pubkey; 247 return OPS_KEEP_MEMORY; 248 249 case OPS_PTAG_CT_USER_ID: 250 if (key->userid.userid) { 251 __ops_userid_free(&key->userid); 252 } 253 key->userid = content->userid; 254 key->last_seen = ID; 255 return OPS_KEEP_MEMORY; 256 257 case OPS_PTAG_CT_USER_ATTR: 258 if (content->userattr.data.len == 0) { 259 (void) fprintf(io->errs, 260 "__ops_validate_key_cb: user attribute length 0"); 261 return OPS_FINISHED; 262 } 263 (void) fprintf(io->outs, "user attribute, length=%d\n", 264 (int) content->userattr.data.len); 265 if (key->userattr.data.len) { 266 __ops_userattr_free(&key->userattr); 267 } 268 key->userattr = content->userattr; 269 key->last_seen = ATTRIBUTE; 270 return OPS_KEEP_MEMORY; 271 272 case OPS_PTAG_CT_SIGNATURE: /* V3 sigs */ 273 case OPS_PTAG_CT_SIGNATURE_FOOTER: /* V4 sigs */ 274 275 signer = __ops_getkeybyid(io, key->keyring, 276 content->sig.info.signer_id); 277 if (!signer) { 278 add_sig_to_list(&content->sig.info, 279 &key->result->unknown_sigs, 280 &key->result->unknownc); 281 break; 282 } 283 switch (content->sig.info.type) { 284 case OPS_CERT_GENERIC: 285 case OPS_CERT_PERSONA: 286 case OPS_CERT_CASUAL: 287 case OPS_CERT_POSITIVE: 288 case OPS_SIG_REV_CERT: 289 valid = (key->last_seen == ID) ? 290 __ops_check_useridcert_sig(&key->pubkey, 291 &key->userid, 292 &content->sig, 293 __ops_get_pubkey(signer), 294 key->reader->key->packets[ 295 key->reader->packet].raw) : 296 __ops_check_userattrcert_sig(&key->pubkey, 297 &key->userattr, 298 &content->sig, 299 __ops_get_pubkey(signer), 300 key->reader->key->packets[ 301 key->reader->packet].raw); 302 break; 303 304 case OPS_SIG_SUBKEY: 305 /* 306 * XXX: we should also check that the signer is the 307 * key we are validating, I think. 308 */ 309 valid = __ops_check_subkey_sig(&key->pubkey, 310 &key->subkey, 311 &content->sig, 312 __ops_get_pubkey(signer), 313 key->reader->key->packets[ 314 key->reader->packet].raw); 315 break; 316 317 case OPS_SIG_DIRECT: 318 valid = __ops_check_direct_sig(&key->pubkey, 319 &content->sig, 320 __ops_get_pubkey(signer), 321 key->reader->key->packets[ 322 key->reader->packet].raw); 323 break; 324 325 case OPS_SIG_STANDALONE: 326 case OPS_SIG_PRIMARY: 327 case OPS_SIG_REV_KEY: 328 case OPS_SIG_REV_SUBKEY: 329 case OPS_SIG_TIMESTAMP: 330 case OPS_SIG_3RD_PARTY: 331 OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED, 332 "Sig Verification type 0x%02x not done yet\n", 333 content->sig.info.type); 334 break; 335 336 default: 337 OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED, 338 "Unexpected signature type 0x%02x\n", 339 content->sig.info.type); 340 } 341 342 if (valid) { 343 add_sig_to_list(&content->sig.info, 344 &key->result->valid_sigs, 345 &key->result->validc); 346 } else { 347 OPS_ERROR(errors, OPS_E_V_BAD_SIGNATURE, "Bad Sig"); 348 add_sig_to_list(&content->sig.info, 349 &key->result->invalid_sigs, 350 &key->result->invalidc); 351 } 352 break; 353 354 /* ignore these */ 355 case OPS_PARSER_PTAG: 356 case OPS_PTAG_CT_SIGNATURE_HEADER: 357 case OPS_PARSER_PACKET_END: 358 break; 359 360 case OPS_GET_PASSPHRASE: 361 if (key->getpassphrase) { 362 return key->getpassphrase(pkt, cbinfo); 363 } 364 break; 365 366 default: 367 (void) fprintf(stderr, "unexpected tag=0x%x\n", pkt->tag); 368 return OPS_FINISHED; 369 } 370 return OPS_RELEASE_MEMORY; 371 } 372 373 __ops_cb_ret_t 374 validate_data_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo) 375 { 376 const __ops_contents_t *content = &pkt->u; 377 const __ops_key_t *signer; 378 validate_data_cb_t *data; 379 __ops_error_t **errors; 380 __ops_io_t *io; 381 unsigned valid = 0; 382 383 io = cbinfo->io; 384 if (__ops_get_debug_level(__FILE__)) { 385 (void) fprintf(io->errs, "validate_data_cb: %s\n", 386 __ops_show_packet_tag(pkt->tag)); 387 } 388 data = __ops_callback_arg(cbinfo); 389 errors = __ops_callback_errors(cbinfo); 390 switch (pkt->tag) { 391 case OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER: 392 /* 393 * ignore - this gives us the "Armor Header" line "Hash: 394 * SHA1" or similar 395 */ 396 break; 397 398 case OPS_PTAG_CT_LITDATA_HEADER: 399 /* ignore */ 400 break; 401 402 case OPS_PTAG_CT_LITDATA_BODY: 403 data->data.litdata_body = content->litdata_body; 404 data->type = LITDATA; 405 __ops_memory_add(data->mem, data->data.litdata_body.data, 406 data->data.litdata_body.length); 407 return OPS_KEEP_MEMORY; 408 409 case OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY: 410 data->data.cleartext_body = content->cleartext_body; 411 data->type = SIGNED_CLEARTEXT; 412 __ops_memory_add(data->mem, data->data.litdata_body.data, 413 data->data.litdata_body.length); 414 return OPS_KEEP_MEMORY; 415 416 case OPS_PTAG_CT_SIGNED_CLEARTEXT_TRAILER: 417 /* this gives us an __ops_hash_t struct */ 418 break; 419 420 case OPS_PTAG_CT_SIGNATURE: /* V3 sigs */ 421 case OPS_PTAG_CT_SIGNATURE_FOOTER: /* V4 sigs */ 422 if (__ops_get_debug_level(__FILE__)) { 423 (void) fprintf(io->outs, "\n*** hashed data:\n"); 424 hexdump(io->outs, content->sig.info.v4_hashed, 425 content->sig.info.v4_hashlen, " "); 426 (void) fprintf(io->outs, "\n"); 427 (void) fprintf(io->outs, "type=%02x signer_id=", 428 content->sig.info.type); 429 hexdump(io->outs, content->sig.info.signer_id, 430 sizeof(content->sig.info.signer_id), ""); 431 (void) fprintf(io->outs, "\n"); 432 } 433 signer = __ops_getkeybyid(io, data->keyring, 434 content->sig.info.signer_id); 435 if (!signer) { 436 OPS_ERROR(errors, OPS_E_V_UNKNOWN_SIGNER, 437 "Unknown Signer"); 438 add_sig_to_list(&content->sig.info, 439 &data->result->unknown_sigs, 440 &data->result->unknownc); 441 break; 442 } 443 switch (content->sig.info.type) { 444 case OPS_SIG_BINARY: 445 case OPS_SIG_TEXT: 446 if (__ops_mem_len(data->mem) == 0 && 447 data->detachname) { 448 /* check we have seen some data */ 449 /* if not, need to read from detached name */ 450 (void) fprintf(io->outs, 451 "netpgp: assuming signed data in \"%s\"\n", 452 data->detachname); 453 data->mem = __ops_memory_new(); 454 __ops_mem_readfile(data->mem, data->detachname); 455 } 456 valid = check_binary_sig(__ops_mem_len(data->mem), 457 __ops_mem_data(data->mem), 458 &content->sig, 459 __ops_get_pubkey(signer)); 460 break; 461 462 default: 463 OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED, 464 "No Sig Verification type 0x%02x yet\n", 465 content->sig.info.type); 466 break; 467 468 } 469 470 if (valid) { 471 add_sig_to_list(&content->sig.info, 472 &data->result->valid_sigs, 473 &data->result->validc); 474 } else { 475 OPS_ERROR(errors, OPS_E_V_BAD_SIGNATURE, 476 "Bad Signature"); 477 add_sig_to_list(&content->sig.info, 478 &data->result->invalid_sigs, 479 &data->result->invalidc); 480 } 481 break; 482 483 /* ignore these */ 484 case OPS_PARSER_PTAG: 485 case OPS_PTAG_CT_SIGNATURE_HEADER: 486 case OPS_PTAG_CT_ARMOUR_HEADER: 487 case OPS_PTAG_CT_ARMOUR_TRAILER: 488 case OPS_PTAG_CT_1_PASS_SIG: 489 break; 490 491 case OPS_PARSER_PACKET_END: 492 break; 493 494 default: 495 OPS_ERROR(errors, OPS_E_V_NO_SIGNATURE, "No signature"); 496 break; 497 } 498 return OPS_RELEASE_MEMORY; 499 } 500 501 static void 502 keydata_destroyer(__ops_reader_t *readinfo) 503 { 504 (void) free(__ops_reader_get_arg(readinfo)); 505 } 506 507 void 508 __ops_keydata_reader_set(__ops_stream_t *stream, const __ops_key_t *key) 509 { 510 validate_reader_t *data = calloc(1, sizeof(*data)); 511 512 data->key = key; 513 data->packet = 0; 514 data->offset = 0; 515 __ops_reader_set(stream, keydata_reader, keydata_destroyer, data); 516 } 517 518 /** 519 * \ingroup HighLevel_Verify 520 * \brief Indicicates whether any errors were found 521 * \param result Validation result to check 522 * \return 0 if any invalid signatures or unknown signers 523 or no valid signatures; else 1 524 */ 525 static unsigned 526 validate_result_status(__ops_validation_t *val) 527 { 528 return val->validc && !val->invalidc && !val->unknownc; 529 } 530 531 /** 532 * \ingroup HighLevel_Verify 533 * \brief Validate all signatures on a single key against the given keyring 534 * \param result Where to put the result 535 * \param key Key to validate 536 * \param keyring Keyring to use for validation 537 * \param cb_get_passphrase Callback to use to get passphrase 538 * \return 1 if all signatures OK; else 0 539 * \note It is the caller's responsiblity to free result after use. 540 * \sa __ops_validate_result_free() 541 */ 542 unsigned 543 __ops_validate_key_sigs(__ops_validation_t *result, 544 const __ops_key_t *key, 545 const __ops_keyring_t *keyring, 546 __ops_cb_ret_t cb_get_passphrase(const __ops_packet_t *, 547 __ops_cbdata_t *)) 548 { 549 __ops_stream_t *stream; 550 validate_key_cb_t keysigs; 551 const int printerrors = 1; 552 553 (void) memset(&keysigs, 0x0, sizeof(keysigs)); 554 keysigs.result = result; 555 keysigs.getpassphrase = cb_get_passphrase; 556 557 stream = __ops_new(sizeof(*stream)); 558 /* __ops_parse_options(&opt,OPS_PTAG_CT_SIGNATURE,OPS_PARSE_PARSED); */ 559 560 keysigs.keyring = keyring; 561 562 __ops_set_callback(stream, __ops_validate_key_cb, &keysigs); 563 stream->readinfo.accumulate = 1; 564 __ops_keydata_reader_set(stream, key); 565 566 /* Note: Coverity incorrectly reports an error that keysigs.reader */ 567 /* is never used. */ 568 keysigs.reader = stream->readinfo.arg; 569 570 __ops_parse(stream, !printerrors); 571 572 __ops_pubkey_free(&keysigs.pubkey); 573 if (keysigs.subkey.version) { 574 __ops_pubkey_free(&keysigs.subkey); 575 } 576 __ops_userid_free(&keysigs.userid); 577 __ops_userattr_free(&keysigs.userattr); 578 579 __ops_stream_delete(stream); 580 581 return (!result->invalidc && !result->unknownc && result->validc); 582 } 583 584 /** 585 \ingroup HighLevel_Verify 586 \param result Where to put the result 587 \param ring Keyring to use 588 \param cb_get_passphrase Callback to use to get passphrase 589 \note It is the caller's responsibility to free result after use. 590 \sa __ops_validate_result_free() 591 */ 592 unsigned 593 __ops_validate_all_sigs(__ops_validation_t *result, 594 const __ops_keyring_t *ring, 595 __ops_cb_ret_t cb_get_passphrase(const __ops_packet_t *, 596 __ops_cbdata_t *)) 597 { 598 unsigned n; 599 600 (void) memset(result, 0x0, sizeof(*result)); 601 for (n = 0; n < ring->keyc; ++n) { 602 __ops_validate_key_sigs(result, &ring->keys[n], ring, 603 cb_get_passphrase); 604 } 605 return validate_result_status(result); 606 } 607 608 /** 609 \ingroup HighLevel_Verify 610 \brief Frees validation result and associated memory 611 \param result Struct to be freed 612 \note Must be called after validation functions 613 */ 614 void 615 __ops_validate_result_free(__ops_validation_t *result) 616 { 617 if (result != NULL) { 618 if (result->valid_sigs) { 619 free_sig_info(result->valid_sigs); 620 } 621 if (result->invalid_sigs) { 622 free_sig_info(result->invalid_sigs); 623 } 624 if (result->unknown_sigs) { 625 free_sig_info(result->unknown_sigs); 626 } 627 (void) free(result); 628 result = NULL; 629 } 630 } 631 632 /** 633 \ingroup HighLevel_Verify 634 \brief Verifies the signatures in a signed file 635 \param result Where to put the result 636 \param filename Name of file to be validated 637 \param armoured Treat file as armoured, if set 638 \param keyring Keyring to use 639 \return 1 if signatures validate successfully; 640 0 if signatures fail or there are no signatures 641 \note After verification, result holds the details of all keys which 642 have passed, failed and not been recognised. 643 \note It is the caller's responsiblity to call 644 __ops_validate_result_free(result) after use. 645 */ 646 unsigned 647 __ops_validate_file(__ops_io_t *io, 648 __ops_validation_t *result, 649 const char *infile, 650 const char *outfile, 651 const int armoured, 652 const __ops_keyring_t *keyring) 653 { 654 validate_data_cb_t validation; 655 __ops_stream_t *parse = NULL; 656 struct stat st; 657 const int printerrors = 1; 658 unsigned ret; 659 int64_t sigsize; 660 char origfile[MAXPATHLEN]; 661 char *detachname; 662 int outfd = 0; 663 int infd; 664 int cc; 665 666 #define SIG_OVERHEAD 284 /* XXX - depends on sig size? */ 667 668 if (stat(infile, &st) < 0) { 669 (void) fprintf(io->errs, "can't validate \"%s\"\n", infile); 670 return 0; 671 } 672 sigsize = st.st_size; 673 detachname = NULL; 674 cc = snprintf(origfile, sizeof(origfile), "%s", infile); 675 if (strcmp(&origfile[cc - 4], ".sig") == 0) { 676 origfile[cc - 4] = 0x0; 677 if (stat(origfile, &st) == 0 && 678 st.st_size > sigsize - SIG_OVERHEAD) { 679 detachname = strdup(origfile); 680 } 681 } 682 683 (void) memset(&validation, 0x0, sizeof(validation)); 684 685 infd = __ops_setup_file_read(io, &parse, infile, &validation, 686 validate_data_cb, 1); 687 if (infd < 0) { 688 return 0; 689 } 690 691 validation.detachname = detachname; 692 693 /* Set verification reader and handling options */ 694 validation.result = result; 695 validation.keyring = keyring; 696 validation.mem = __ops_memory_new(); 697 __ops_memory_init(validation.mem, 128); 698 /* Note: Coverity incorrectly reports an error that validation.reader */ 699 /* is never used. */ 700 validation.reader = parse->readinfo.arg; 701 702 if (armoured) { 703 __ops_reader_push_dearmour(parse); 704 } 705 706 /* Do the verification */ 707 __ops_parse(parse, !printerrors); 708 709 /* Tidy up */ 710 if (armoured) { 711 __ops_reader_pop_dearmour(parse); 712 } 713 __ops_teardown_file_read(parse, infd); 714 715 ret = validate_result_status(result); 716 717 /* this is triggered only for --cat output */ 718 if (outfile) { 719 /* need to send validated output somewhere */ 720 if (strcmp(outfile, "-") == 0) { 721 outfd = STDOUT_FILENO; 722 } else { 723 outfd = open(outfile, O_WRONLY | O_CREAT, 0666); 724 } 725 if (outfd < 0) { 726 /* even if the signature was good, we can't 727 * write the file, so send back a bad return 728 * code */ 729 ret = 0; 730 } else if (validate_result_status(result)) { 731 unsigned len; 732 char *cp; 733 int i; 734 735 len = __ops_mem_len(validation.mem); 736 cp = __ops_mem_data(validation.mem); 737 for (i = 0 ; i < (int)len ; i += cc) { 738 cc = write(outfd, &cp[i], len - i); 739 if (cc < 0) { 740 (void) fprintf(io->errs, 741 "netpgp: short write\n"); 742 ret = 0; 743 break; 744 } 745 } 746 if (strcmp(outfile, "-") != 0) { 747 (void) close(outfd); 748 } 749 } 750 } 751 __ops_memory_free(validation.mem); 752 return ret; 753 } 754 755 /** 756 \ingroup HighLevel_Verify 757 \brief Verifies the signatures in a __ops_memory_t struct 758 \param result Where to put the result 759 \param mem Memory to be validated 760 \param armoured Treat data as armoured, if set 761 \param keyring Keyring to use 762 \return 1 if signature validates successfully; 0 if not 763 \note After verification, result holds the details of all keys which 764 have passed, failed and not been recognised. 765 \note It is the caller's responsiblity to call 766 __ops_validate_result_free(result) after use. 767 */ 768 769 unsigned 770 __ops_validate_mem(__ops_io_t *io, 771 __ops_validation_t *result, 772 __ops_memory_t *mem, 773 const int armoured, 774 const __ops_keyring_t *keyring) 775 { 776 validate_data_cb_t validation; 777 __ops_stream_t *stream = NULL; 778 const int printerrors = 1; 779 780 __ops_setup_memory_read(io, &stream, mem, &validation, validate_data_cb, 1); 781 /* Set verification reader and handling options */ 782 (void) memset(&validation, 0x0, sizeof(validation)); 783 validation.result = result; 784 validation.keyring = keyring; 785 validation.mem = __ops_memory_new(); 786 __ops_memory_init(validation.mem, 128); 787 /* Note: Coverity incorrectly reports an error that validation.reader */ 788 /* is never used. */ 789 validation.reader = stream->readinfo.arg; 790 791 if (armoured) { 792 __ops_reader_push_dearmour(stream); 793 } 794 795 /* Do the verification */ 796 __ops_parse(stream, !printerrors); 797 798 /* Tidy up */ 799 if (armoured) { 800 __ops_reader_pop_dearmour(stream); 801 } 802 __ops_teardown_memory_read(stream, mem); 803 __ops_memory_free(validation.mem); 804 805 return validate_result_status(result); 806 } 807