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