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