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.24 2009/12/07 16:17:17 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 break; 335 336 case OPS_SIG_DIRECT: 337 valid = __ops_check_direct_sig(&key->pubkey, 338 &content->sig, 339 __ops_get_pubkey(signer), 340 key->reader->key->packets[ 341 key->reader->packet].raw); 342 break; 343 344 case OPS_SIG_STANDALONE: 345 case OPS_SIG_PRIMARY: 346 case OPS_SIG_REV_KEY: 347 case OPS_SIG_REV_SUBKEY: 348 case OPS_SIG_TIMESTAMP: 349 case OPS_SIG_3RD_PARTY: 350 OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED, 351 "Sig Verification type 0x%02x not done yet\n", 352 content->sig.info.type); 353 break; 354 355 default: 356 OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED, 357 "Unexpected signature type 0x%02x\n", 358 content->sig.info.type); 359 } 360 361 if (valid) { 362 if (!add_sig_to_list(&content->sig.info, 363 &key->result->valid_sigs, 364 &key->result->validc)) { 365 OPS_ERROR(errors, OPS_E_UNIMPLEMENTED, 366 "Can't add good sig to list\n"); 367 } 368 } else { 369 OPS_ERROR(errors, OPS_E_V_BAD_SIGNATURE, "Bad Sig"); 370 if (!add_sig_to_list(&content->sig.info, 371 &key->result->invalid_sigs, 372 &key->result->invalidc)) { 373 OPS_ERROR(errors, OPS_E_UNIMPLEMENTED, 374 "Can't add good sig to list\n"); 375 } 376 } 377 break; 378 379 /* ignore these */ 380 case OPS_PARSER_PTAG: 381 case OPS_PTAG_CT_SIGNATURE_HEADER: 382 case OPS_PARSER_PACKET_END: 383 break; 384 385 case OPS_GET_PASSPHRASE: 386 if (key->getpassphrase) { 387 return key->getpassphrase(pkt, cbinfo); 388 } 389 break; 390 391 default: 392 (void) fprintf(stderr, "unexpected tag=0x%x\n", pkt->tag); 393 return OPS_FINISHED; 394 } 395 return OPS_RELEASE_MEMORY; 396 } 397 398 __ops_cb_ret_t 399 validate_data_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo) 400 { 401 const __ops_contents_t *content = &pkt->u; 402 const __ops_key_t *signer; 403 validate_data_cb_t *data; 404 __ops_error_t **errors; 405 __ops_io_t *io; 406 unsigned from; 407 unsigned valid = 0; 408 409 io = cbinfo->io; 410 if (__ops_get_debug_level(__FILE__)) { 411 (void) fprintf(io->errs, "validate_data_cb: %s\n", 412 __ops_show_packet_tag(pkt->tag)); 413 } 414 data = __ops_callback_arg(cbinfo); 415 errors = __ops_callback_errors(cbinfo); 416 switch (pkt->tag) { 417 case OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER: 418 /* 419 * ignore - this gives us the "Armor Header" line "Hash: 420 * SHA1" or similar 421 */ 422 break; 423 424 case OPS_PTAG_CT_LITDATA_HEADER: 425 /* ignore */ 426 break; 427 428 case OPS_PTAG_CT_LITDATA_BODY: 429 data->data.litdata_body = content->litdata_body; 430 data->type = LITDATA; 431 __ops_memory_add(data->mem, data->data.litdata_body.data, 432 data->data.litdata_body.length); 433 return OPS_KEEP_MEMORY; 434 435 case OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY: 436 data->data.cleartext_body = content->cleartext_body; 437 data->type = SIGNED_CLEARTEXT; 438 __ops_memory_add(data->mem, data->data.litdata_body.data, 439 data->data.litdata_body.length); 440 return OPS_KEEP_MEMORY; 441 442 case OPS_PTAG_CT_SIGNED_CLEARTEXT_TRAILER: 443 /* this gives us an __ops_hash_t struct */ 444 break; 445 446 case OPS_PTAG_CT_SIGNATURE: /* V3 sigs */ 447 case OPS_PTAG_CT_SIGNATURE_FOOTER: /* V4 sigs */ 448 if (__ops_get_debug_level(__FILE__)) { 449 (void) fprintf(io->outs, "\n*** hashed data:\n"); 450 hexdump(io->outs, content->sig.info.v4_hashed, 451 content->sig.info.v4_hashlen, " "); 452 (void) fprintf(io->outs, "\n"); 453 (void) fprintf(io->outs, "type=%02x signer_id=", 454 content->sig.info.type); 455 hexdump(io->outs, content->sig.info.signer_id, 456 sizeof(content->sig.info.signer_id), ""); 457 (void) fprintf(io->outs, "\n"); 458 } 459 from = 0; 460 signer = __ops_getkeybyid(io, data->keyring, 461 content->sig.info.signer_id, &from); 462 if (!signer) { 463 OPS_ERROR(errors, OPS_E_V_UNKNOWN_SIGNER, 464 "Unknown Signer"); 465 if (!add_sig_to_list(&content->sig.info, 466 &data->result->unknown_sigs, 467 &data->result->unknownc)) { 468 OPS_ERROR(errors, OPS_E_V_UNKNOWN_SIGNER, 469 "Can't add unknown sig to list"); 470 } 471 break; 472 } 473 switch (content->sig.info.type) { 474 case OPS_SIG_BINARY: 475 case OPS_SIG_TEXT: 476 if (__ops_mem_len(data->mem) == 0 && 477 data->detachname) { 478 /* check we have seen some data */ 479 /* if not, need to read from detached name */ 480 (void) fprintf(io->outs, 481 "netpgp: assuming signed data in \"%s\"\n", 482 data->detachname); 483 data->mem = __ops_memory_new(); 484 __ops_mem_readfile(data->mem, data->detachname); 485 } 486 valid = check_binary_sig(__ops_mem_data(data->mem), 487 __ops_mem_len(data->mem), 488 &content->sig, 489 __ops_get_pubkey(signer)); 490 break; 491 492 default: 493 OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED, 494 "No Sig Verification type 0x%02x yet\n", 495 content->sig.info.type); 496 break; 497 498 } 499 500 if (valid) { 501 if (!add_sig_to_list(&content->sig.info, 502 &data->result->valid_sigs, 503 &data->result->validc)) { 504 OPS_ERROR(errors, OPS_E_V_BAD_SIGNATURE, 505 "Can't add good sig to list"); 506 } 507 } else { 508 OPS_ERROR(errors, OPS_E_V_BAD_SIGNATURE, 509 "Bad Signature"); 510 if (!add_sig_to_list(&content->sig.info, 511 &data->result->invalid_sigs, 512 &data->result->invalidc)) { 513 OPS_ERROR(errors, OPS_E_V_BAD_SIGNATURE, 514 "Can't add good sig to list"); 515 } 516 } 517 break; 518 519 /* ignore these */ 520 case OPS_PARSER_PTAG: 521 case OPS_PTAG_CT_SIGNATURE_HEADER: 522 case OPS_PTAG_CT_ARMOUR_HEADER: 523 case OPS_PTAG_CT_ARMOUR_TRAILER: 524 case OPS_PTAG_CT_1_PASS_SIG: 525 break; 526 527 case OPS_PARSER_PACKET_END: 528 break; 529 530 default: 531 OPS_ERROR(errors, OPS_E_V_NO_SIGNATURE, "No signature"); 532 break; 533 } 534 return OPS_RELEASE_MEMORY; 535 } 536 537 static void 538 keydata_destroyer(__ops_reader_t *readinfo) 539 { 540 free(__ops_reader_get_arg(readinfo)); 541 } 542 543 void 544 __ops_keydata_reader_set(__ops_stream_t *stream, const __ops_key_t *key) 545 { 546 validate_reader_t *data; 547 548 if ((data = calloc(1, sizeof(*data))) == NULL) { 549 (void) fprintf(stderr, "__ops_keydata_reader_set: bad alloc\n"); 550 } else { 551 data->key = key; 552 data->packet = 0; 553 data->offset = 0; 554 __ops_reader_set(stream, keydata_reader, keydata_destroyer, data); 555 } 556 } 557 558 /** 559 * \ingroup HighLevel_Verify 560 * \brief Indicicates whether any errors were found 561 * \param result Validation result to check 562 * \return 0 if any invalid signatures or unknown signers 563 or no valid signatures; else 1 564 */ 565 static unsigned 566 validate_result_status(__ops_validation_t *val) 567 { 568 return val->validc && !val->invalidc && !val->unknownc; 569 } 570 571 /** 572 * \ingroup HighLevel_Verify 573 * \brief Validate all signatures on a single key against the given keyring 574 * \param result Where to put the result 575 * \param key Key to validate 576 * \param keyring Keyring to use for validation 577 * \param cb_get_passphrase Callback to use to get passphrase 578 * \return 1 if all signatures OK; else 0 579 * \note It is the caller's responsiblity to free result after use. 580 * \sa __ops_validate_result_free() 581 */ 582 unsigned 583 __ops_validate_key_sigs(__ops_validation_t *result, 584 const __ops_key_t *key, 585 const __ops_keyring_t *keyring, 586 __ops_cb_ret_t cb_get_passphrase(const __ops_packet_t *, 587 __ops_cbdata_t *)) 588 { 589 __ops_stream_t *stream; 590 validate_key_cb_t keysigs; 591 const int printerrors = 1; 592 593 (void) memset(&keysigs, 0x0, sizeof(keysigs)); 594 keysigs.result = result; 595 keysigs.getpassphrase = cb_get_passphrase; 596 597 stream = __ops_new(sizeof(*stream)); 598 /* __ops_parse_options(&opt,OPS_PTAG_CT_SIGNATURE,OPS_PARSE_PARSED); */ 599 600 keysigs.keyring = keyring; 601 602 __ops_set_callback(stream, __ops_validate_key_cb, &keysigs); 603 stream->readinfo.accumulate = 1; 604 __ops_keydata_reader_set(stream, key); 605 606 /* Note: Coverity incorrectly reports an error that keysigs.reader */ 607 /* is never used. */ 608 keysigs.reader = stream->readinfo.arg; 609 610 __ops_parse(stream, !printerrors); 611 612 __ops_pubkey_free(&keysigs.pubkey); 613 if (keysigs.subkey.version) { 614 __ops_pubkey_free(&keysigs.subkey); 615 } 616 __ops_userid_free(&keysigs.userid); 617 __ops_userattr_free(&keysigs.userattr); 618 619 __ops_stream_delete(stream); 620 621 return (!result->invalidc && !result->unknownc && result->validc); 622 } 623 624 /** 625 \ingroup HighLevel_Verify 626 \param result Where to put the result 627 \param ring Keyring to use 628 \param cb_get_passphrase Callback to use to get passphrase 629 \note It is the caller's responsibility to free result after use. 630 \sa __ops_validate_result_free() 631 */ 632 unsigned 633 __ops_validate_all_sigs(__ops_validation_t *result, 634 const __ops_keyring_t *ring, 635 __ops_cb_ret_t cb_get_passphrase(const __ops_packet_t *, 636 __ops_cbdata_t *)) 637 { 638 unsigned n; 639 640 (void) memset(result, 0x0, sizeof(*result)); 641 for (n = 0; n < ring->keyc; ++n) { 642 __ops_validate_key_sigs(result, &ring->keys[n], ring, 643 cb_get_passphrase); 644 } 645 return validate_result_status(result); 646 } 647 648 /** 649 \ingroup HighLevel_Verify 650 \brief Frees validation result and associated memory 651 \param result Struct to be freed 652 \note Must be called after validation functions 653 */ 654 void 655 __ops_validate_result_free(__ops_validation_t *result) 656 { 657 if (result != NULL) { 658 if (result->valid_sigs) { 659 free_sig_info(result->valid_sigs); 660 } 661 if (result->invalid_sigs) { 662 free_sig_info(result->invalid_sigs); 663 } 664 if (result->unknown_sigs) { 665 free_sig_info(result->unknown_sigs); 666 } 667 free(result); 668 /* result = NULL; - XXX unnecessary */ 669 } 670 } 671 672 /** 673 \ingroup HighLevel_Verify 674 \brief Verifies the signatures in a signed file 675 \param result Where to put the result 676 \param filename Name of file to be validated 677 \param armoured Treat file as armoured, if set 678 \param keyring Keyring to use 679 \return 1 if signatures validate successfully; 680 0 if signatures fail or there are no signatures 681 \note After verification, result holds the details of all keys which 682 have passed, failed and not been recognised. 683 \note It is the caller's responsiblity to call 684 __ops_validate_result_free(result) after use. 685 */ 686 unsigned 687 __ops_validate_file(__ops_io_t *io, 688 __ops_validation_t *result, 689 const char *infile, 690 const char *outfile, 691 const int armoured, 692 const __ops_keyring_t *keyring) 693 { 694 validate_data_cb_t validation; 695 __ops_stream_t *parse = NULL; 696 struct stat st; 697 const int printerrors = 1; 698 unsigned ret; 699 int64_t sigsize; 700 char origfile[MAXPATHLEN]; 701 char *detachname; 702 int realarmour; 703 int outfd = 0; 704 int infd; 705 int cc; 706 707 #define SIG_OVERHEAD 284 /* XXX - depends on sig size? */ 708 709 realarmour = armoured; 710 if (stat(infile, &st) < 0) { 711 (void) fprintf(io->errs, "can't validate \"%s\"\n", infile); 712 return 0; 713 } 714 sigsize = st.st_size; 715 detachname = NULL; 716 cc = snprintf(origfile, sizeof(origfile), "%s", infile); 717 if (strcmp(&origfile[cc - 4], ".sig") == 0) { 718 origfile[cc - 4] = 0x0; 719 if (stat(origfile, &st) == 0 && 720 st.st_size > sigsize - SIG_OVERHEAD) { 721 detachname = strdup(origfile); 722 } 723 } 724 if (strcmp(&origfile[cc - 4], ".asc") == 0) { 725 realarmour = 1; 726 } 727 728 (void) memset(&validation, 0x0, sizeof(validation)); 729 730 infd = __ops_setup_file_read(io, &parse, infile, &validation, 731 validate_data_cb, 1); 732 if (infd < 0) { 733 return 0; 734 } 735 736 validation.detachname = detachname; 737 738 /* Set verification reader and handling options */ 739 validation.result = result; 740 validation.keyring = keyring; 741 validation.mem = __ops_memory_new(); 742 __ops_memory_init(validation.mem, 128); 743 /* Note: Coverity incorrectly reports an error that validation.reader */ 744 /* is never used. */ 745 validation.reader = parse->readinfo.arg; 746 747 if (realarmour) { 748 __ops_reader_push_dearmour(parse); 749 } 750 751 /* Do the verification */ 752 __ops_parse(parse, !printerrors); 753 754 /* Tidy up */ 755 if (realarmour) { 756 __ops_reader_pop_dearmour(parse); 757 } 758 __ops_teardown_file_read(parse, infd); 759 760 ret = validate_result_status(result); 761 762 /* this is triggered only for --cat output */ 763 if (outfile) { 764 /* need to send validated output somewhere */ 765 if (strcmp(outfile, "-") == 0) { 766 outfd = STDOUT_FILENO; 767 } else { 768 outfd = open(outfile, O_WRONLY | O_CREAT, 0666); 769 } 770 if (outfd < 0) { 771 /* even if the signature was good, we can't 772 * write the file, so send back a bad return 773 * code */ 774 ret = 0; 775 } else if (validate_result_status(result)) { 776 unsigned len; 777 char *cp; 778 int i; 779 780 len = __ops_mem_len(validation.mem); 781 cp = __ops_mem_data(validation.mem); 782 for (i = 0 ; i < (int)len ; i += cc) { 783 cc = write(outfd, &cp[i], len - i); 784 if (cc < 0) { 785 (void) fprintf(io->errs, 786 "netpgp: short write\n"); 787 ret = 0; 788 break; 789 } 790 } 791 if (strcmp(outfile, "-") != 0) { 792 (void) close(outfd); 793 } 794 } 795 } 796 __ops_memory_free(validation.mem); 797 return ret; 798 } 799 800 /** 801 \ingroup HighLevel_Verify 802 \brief Verifies the signatures in a __ops_memory_t struct 803 \param result Where to put the result 804 \param mem Memory to be validated 805 \param armoured Treat data as armoured, if set 806 \param keyring Keyring to use 807 \return 1 if signature validates successfully; 0 if not 808 \note After verification, result holds the details of all keys which 809 have passed, failed and not been recognised. 810 \note It is the caller's responsiblity to call 811 __ops_validate_result_free(result) after use. 812 */ 813 814 unsigned 815 __ops_validate_mem(__ops_io_t *io, 816 __ops_validation_t *result, 817 __ops_memory_t *mem, 818 const int armoured, 819 const __ops_keyring_t *keyring) 820 { 821 validate_data_cb_t validation; 822 __ops_stream_t *stream = NULL; 823 const int printerrors = 1; 824 825 __ops_setup_memory_read(io, &stream, mem, &validation, validate_data_cb, 1); 826 /* Set verification reader and handling options */ 827 (void) memset(&validation, 0x0, sizeof(validation)); 828 validation.result = result; 829 validation.keyring = keyring; 830 validation.mem = __ops_memory_new(); 831 __ops_memory_init(validation.mem, 128); 832 /* Note: Coverity incorrectly reports an error that validation.reader */ 833 /* is never used. */ 834 validation.reader = stream->readinfo.arg; 835 836 if (armoured) { 837 __ops_reader_push_dearmour(stream); 838 } 839 840 /* Do the verification */ 841 __ops_parse(stream, !printerrors); 842 843 /* Tidy up */ 844 if (armoured) { 845 __ops_reader_pop_dearmour(stream); 846 } 847 __ops_teardown_memory_read(stream, mem); 848 __ops_memory_free(validation.mem); 849 850 return validate_result_status(result); 851 } 852