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