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.28 2010/02/08 17:19:12 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 unsigned char *data, 179 const unsigned len, 180 const __ops_sig_t *sig, 181 const __ops_pubkey_t *signer) 182 { 183 unsigned char hashout[OPS_MAX_HASH_SIZE]; 184 unsigned char trailer[6]; 185 unsigned int hashedlen; 186 __ops_hash_t hash; 187 unsigned n; 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] = (unsigned char)(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 unsigned char *)content->trust.data, 10, " "); 413 //hexdump(stdout, (const unsigned char *)&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 unsigned char *)(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 (void) snprintf(buf, size, "%" PRId64 " years", n / (365 * 24 * 60 * 60)); 599 return buf; 600 } 601 if (n > 30 * 24 * 60 * 60) { 602 (void) snprintf(buf, size, "%" PRId64 " months", n / (30 * 24 * 60 * 60)); 603 return buf; 604 } 605 if (n > 24 * 60 * 60) { 606 (void) snprintf(buf, size, "%" PRId64 " days", n / (24 * 60 * 60)); 607 return buf; 608 } 609 if (n > 60 * 60) { 610 (void) snprintf(buf, size, "%" PRId64 " hours", n / (60 * 60)); 611 return buf; 612 } 613 if (n > 60) { 614 (void) snprintf(buf, size, "%" PRId64 " minutes", n / 60); 615 return buf; 616 } 617 (void) snprintf(buf, size, "%" PRId64 " seconds", n); 618 return buf; 619 } 620 621 /** 622 * \ingroup HighLevel_Verify 623 * \brief Indicicates whether any errors were found 624 * \param result Validation result to check 625 * \return 0 if any invalid signatures or unknown signers 626 or no valid signatures; else 1 627 */ 628 static unsigned 629 validate_result_status(FILE *errs, const char *f, __ops_validation_t *val) 630 { 631 time_t now; 632 time_t t; 633 char buf[128]; 634 635 now = time(NULL); 636 if (now < val->birthtime) { 637 /* signature is not valid yet! */ 638 if (f) { 639 (void) fprintf(errs, "\"%s\": ", f); 640 } else { 641 (void) fprintf(errs, "memory "); 642 } 643 (void) fprintf(errs, 644 "signature not valid until %.24s (%s)\n", 645 ctime(&val->birthtime), 646 fmtsecs((int64_t)(val->birthtime - now), buf, sizeof(buf))); 647 return 0; 648 } 649 if (val->duration != 0 && now > val->birthtime + val->duration) { 650 /* signature has expired */ 651 t = val->duration + val->birthtime; 652 if (f) { 653 (void) fprintf(errs, "\"%s\": ", f); 654 } else { 655 (void) fprintf(errs, "memory "); 656 } 657 (void) fprintf(errs, 658 "signature not valid after %.24s (%s ago)\n", 659 ctime(&t), 660 fmtsecs((int64_t)(now - t), buf, sizeof(buf))); 661 return 0; 662 } 663 return val->validc && !val->invalidc && !val->unknownc; 664 } 665 666 /** 667 * \ingroup HighLevel_Verify 668 * \brief Validate all signatures on a single key against the given keyring 669 * \param result Where to put the result 670 * \param key Key to validate 671 * \param keyring Keyring to use for validation 672 * \param cb_get_passphrase Callback to use to get passphrase 673 * \return 1 if all signatures OK; else 0 674 * \note It is the caller's responsiblity to free result after use. 675 * \sa __ops_validate_result_free() 676 */ 677 unsigned 678 __ops_validate_key_sigs(__ops_validation_t *result, 679 const __ops_key_t *key, 680 const __ops_keyring_t *keyring, 681 __ops_cb_ret_t cb_get_passphrase(const __ops_packet_t *, 682 __ops_cbdata_t *)) 683 { 684 __ops_stream_t *stream; 685 validate_key_cb_t keysigs; 686 const int printerrors = 1; 687 688 (void) memset(&keysigs, 0x0, sizeof(keysigs)); 689 keysigs.result = result; 690 keysigs.getpassphrase = cb_get_passphrase; 691 692 stream = __ops_new(sizeof(*stream)); 693 /* __ops_parse_options(&opt,OPS_PTAG_CT_SIGNATURE,OPS_PARSE_PARSED); */ 694 695 keysigs.keyring = keyring; 696 697 __ops_set_callback(stream, __ops_validate_key_cb, &keysigs); 698 stream->readinfo.accumulate = 1; 699 __ops_keydata_reader_set(stream, key); 700 701 /* Note: Coverity incorrectly reports an error that keysigs.reader */ 702 /* is never used. */ 703 keysigs.reader = stream->readinfo.arg; 704 705 __ops_parse(stream, !printerrors); 706 707 __ops_pubkey_free(&keysigs.pubkey); 708 if (keysigs.subkey.version) { 709 __ops_pubkey_free(&keysigs.subkey); 710 } 711 __ops_userid_free(&keysigs.userid); 712 __ops_userattr_free(&keysigs.userattr); 713 714 __ops_stream_delete(stream); 715 716 return (!result->invalidc && !result->unknownc && result->validc); 717 } 718 719 /** 720 \ingroup HighLevel_Verify 721 \param result Where to put the result 722 \param ring Keyring to use 723 \param cb_get_passphrase Callback to use to get passphrase 724 \note It is the caller's responsibility to free result after use. 725 \sa __ops_validate_result_free() 726 */ 727 unsigned 728 __ops_validate_all_sigs(__ops_validation_t *result, 729 const __ops_keyring_t *ring, 730 __ops_cb_ret_t cb_get_passphrase(const __ops_packet_t *, 731 __ops_cbdata_t *)) 732 { 733 unsigned n; 734 735 (void) memset(result, 0x0, sizeof(*result)); 736 for (n = 0; n < ring->keyc; ++n) { 737 __ops_validate_key_sigs(result, &ring->keys[n], ring, 738 cb_get_passphrase); 739 } 740 return validate_result_status(stderr, "keyring", result); 741 } 742 743 /** 744 \ingroup HighLevel_Verify 745 \brief Frees validation result and associated memory 746 \param result Struct to be freed 747 \note Must be called after validation functions 748 */ 749 void 750 __ops_validate_result_free(__ops_validation_t *result) 751 { 752 if (result != NULL) { 753 if (result->valid_sigs) { 754 free_sig_info(result->valid_sigs); 755 } 756 if (result->invalid_sigs) { 757 free_sig_info(result->invalid_sigs); 758 } 759 if (result->unknown_sigs) { 760 free_sig_info(result->unknown_sigs); 761 } 762 free(result); 763 /* result = NULL; - XXX unnecessary */ 764 } 765 } 766 767 /** 768 \ingroup HighLevel_Verify 769 \brief Verifies the signatures in a signed file 770 \param result Where to put the result 771 \param filename Name of file to be validated 772 \param armoured Treat file as armoured, if set 773 \param keyring Keyring to use 774 \return 1 if signatures validate successfully; 775 0 if signatures fail or there are no signatures 776 \note After verification, result holds the details of all keys which 777 have passed, failed and not been recognised. 778 \note It is the caller's responsiblity to call 779 __ops_validate_result_free(result) after use. 780 */ 781 unsigned 782 __ops_validate_file(__ops_io_t *io, 783 __ops_validation_t *result, 784 const char *infile, 785 const char *outfile, 786 const int armoured, 787 const __ops_keyring_t *keyring) 788 { 789 validate_data_cb_t validation; 790 __ops_stream_t *parse = NULL; 791 struct stat st; 792 const int printerrors = 1; 793 unsigned ret; 794 int64_t sigsize; 795 char origfile[MAXPATHLEN]; 796 char *detachname; 797 int realarmour; 798 int outfd = 0; 799 int infd; 800 int cc; 801 802 #define SIG_OVERHEAD 284 /* XXX - depends on sig size? */ 803 804 realarmour = armoured; 805 if (stat(infile, &st) < 0) { 806 (void) fprintf(io->errs, "can't validate \"%s\"\n", infile); 807 return 0; 808 } 809 sigsize = st.st_size; 810 detachname = NULL; 811 cc = snprintf(origfile, sizeof(origfile), "%s", infile); 812 if (strcmp(&origfile[cc - 4], ".sig") == 0) { 813 origfile[cc - 4] = 0x0; 814 if (stat(origfile, &st) == 0 && 815 st.st_size > sigsize - SIG_OVERHEAD) { 816 detachname = strdup(origfile); 817 } 818 } 819 if (strcmp(&origfile[cc - 4], ".asc") == 0) { 820 realarmour = 1; 821 } 822 823 (void) memset(&validation, 0x0, sizeof(validation)); 824 825 infd = __ops_setup_file_read(io, &parse, infile, &validation, 826 validate_data_cb, 1); 827 if (infd < 0) { 828 return 0; 829 } 830 831 validation.detachname = detachname; 832 833 /* Set verification reader and handling options */ 834 validation.result = result; 835 validation.keyring = keyring; 836 validation.mem = __ops_memory_new(); 837 __ops_memory_init(validation.mem, 128); 838 /* Note: Coverity incorrectly reports an error that validation.reader */ 839 /* is never used. */ 840 validation.reader = parse->readinfo.arg; 841 842 if (realarmour) { 843 __ops_reader_push_dearmour(parse); 844 } 845 846 /* Do the verification */ 847 __ops_parse(parse, !printerrors); 848 849 /* Tidy up */ 850 if (realarmour) { 851 __ops_reader_pop_dearmour(parse); 852 } 853 __ops_teardown_file_read(parse, infd); 854 855 ret = validate_result_status(io->errs, infile, result); 856 857 /* this is triggered only for --cat output */ 858 if (outfile) { 859 /* need to send validated output somewhere */ 860 if (strcmp(outfile, "-") == 0) { 861 outfd = STDOUT_FILENO; 862 } else { 863 outfd = open(outfile, O_WRONLY | O_CREAT, 0666); 864 } 865 if (outfd < 0) { 866 /* even if the signature was good, we can't 867 * write the file, so send back a bad return 868 * code */ 869 ret = 0; 870 } else if (validate_result_status(io->errs, infile, result)) { 871 unsigned len; 872 char *cp; 873 int i; 874 875 len = __ops_mem_len(validation.mem); 876 cp = __ops_mem_data(validation.mem); 877 for (i = 0 ; i < (int)len ; i += cc) { 878 cc = write(outfd, &cp[i], len - i); 879 if (cc < 0) { 880 (void) fprintf(io->errs, 881 "netpgp: short write\n"); 882 ret = 0; 883 break; 884 } 885 } 886 if (strcmp(outfile, "-") != 0) { 887 (void) close(outfd); 888 } 889 } 890 } 891 __ops_memory_free(validation.mem); 892 return ret; 893 } 894 895 /** 896 \ingroup HighLevel_Verify 897 \brief Verifies the signatures in a __ops_memory_t struct 898 \param result Where to put the result 899 \param mem Memory to be validated 900 \param armoured Treat data as armoured, if set 901 \param keyring Keyring to use 902 \return 1 if signature validates successfully; 0 if not 903 \note After verification, result holds the details of all keys which 904 have passed, failed and not been recognised. 905 \note It is the caller's responsiblity to call 906 __ops_validate_result_free(result) after use. 907 */ 908 909 unsigned 910 __ops_validate_mem(__ops_io_t *io, 911 __ops_validation_t *result, 912 __ops_memory_t *mem, 913 __ops_memory_t **cat, 914 const int armoured, 915 const __ops_keyring_t *keyring) 916 { 917 validate_data_cb_t validation; 918 __ops_stream_t *stream = NULL; 919 const int printerrors = 1; 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 (armoured) { 933 __ops_reader_push_dearmour(stream); 934 } 935 936 /* Do the verification */ 937 __ops_parse(stream, !printerrors); 938 939 /* Tidy up */ 940 if (armoured) { 941 __ops_reader_pop_dearmour(stream); 942 } 943 __ops_teardown_memory_read(stream, mem); 944 945 /* this is triggered only for --cat output */ 946 if (*cat) { 947 /* need to send validated output somewhere */ 948 *cat = validation.mem; 949 } else { 950 __ops_memory_free(validation.mem); 951 } 952 953 return validate_result_status(io->errs, NULL, result); 954 } 955