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