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