1 /* $OpenBSD: signify.c,v 1.131 2019/03/23 07:10:06 tedu Exp $ */ 2 /* 3 * Copyright (c) 2013 Ted Unangst <tedu@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 #include <sys/stat.h> 18 19 #include <netinet/in.h> 20 #include <resolv.h> 21 22 #include <limits.h> 23 #include <stdint.h> 24 #include <fcntl.h> 25 #include <string.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <stddef.h> 29 #include <ohash.h> 30 #include <err.h> 31 #include <unistd.h> 32 #include <readpassphrase.h> 33 #include <util.h> 34 #include <sha2.h> 35 36 #include "crypto_api.h" 37 #include "signify.h" 38 39 #define SIGBYTES crypto_sign_ed25519_BYTES 40 #define SECRETBYTES crypto_sign_ed25519_SECRETKEYBYTES 41 #define PUBLICBYTES crypto_sign_ed25519_PUBLICKEYBYTES 42 43 #define PKALG "Ed" 44 #define KDFALG "BK" 45 #define KEYNUMLEN 8 46 47 #define COMMENTHDR "untrusted comment: " 48 #define COMMENTHDRLEN 19 49 #define COMMENTMAXLEN 1024 50 #define VERIFYWITH "verify with " 51 52 struct enckey { 53 uint8_t pkalg[2]; 54 uint8_t kdfalg[2]; 55 uint32_t kdfrounds; 56 uint8_t salt[16]; 57 uint8_t checksum[8]; 58 uint8_t keynum[KEYNUMLEN]; 59 uint8_t seckey[SECRETBYTES]; 60 }; 61 62 struct pubkey { 63 uint8_t pkalg[2]; 64 uint8_t keynum[KEYNUMLEN]; 65 uint8_t pubkey[PUBLICBYTES]; 66 }; 67 68 struct sig { 69 uint8_t pkalg[2]; 70 uint8_t keynum[KEYNUMLEN]; 71 uint8_t sig[SIGBYTES]; 72 }; 73 74 static void __dead 75 usage(const char *error) 76 { 77 if (error) 78 fprintf(stderr, "%s\n", error); 79 fprintf(stderr, "usage:" 80 #ifndef VERIFYONLY 81 "\t%1$s -C [-q] -p pubkey -x sigfile [file ...]\n" 82 "\t%1$s -G [-n] [-c comment] -p pubkey -s seckey\n" 83 "\t%1$s -S [-enz] [-x sigfile] -s seckey -m message\n" 84 #endif 85 "\t%1$s -V [-eqz] [-p pubkey] [-t keytype] [-x sigfile] -m message\n", 86 getprogname()); 87 exit(1); 88 } 89 90 int 91 xopen(const char *fname, int oflags, mode_t mode) 92 { 93 struct stat sb; 94 int fd; 95 96 if (strcmp(fname, "-") == 0) { 97 if ((oflags & O_WRONLY)) 98 fd = dup(STDOUT_FILENO); 99 else 100 fd = dup(STDIN_FILENO); 101 if (fd == -1) 102 err(1, "dup failed"); 103 } else { 104 fd = open(fname, oflags, mode); 105 if (fd == -1) 106 err(1, "can't open %s for %s", fname, 107 (oflags & O_WRONLY) ? "writing" : "reading"); 108 } 109 if (fstat(fd, &sb) == -1 || S_ISDIR(sb.st_mode)) 110 errx(1, "not a valid file: %s", fname); 111 return fd; 112 } 113 114 void * 115 xmalloc(size_t len) 116 { 117 void *p; 118 119 if (!(p = malloc(len))) 120 err(1, "malloc %zu", len); 121 return p; 122 } 123 124 static size_t 125 parseb64file(const char *filename, char *b64, void *buf, size_t buflen, 126 char *comment) 127 { 128 char *commentend, *b64end; 129 130 commentend = strchr(b64, '\n'); 131 if (!commentend || commentend - b64 <= COMMENTHDRLEN || 132 memcmp(b64, COMMENTHDR, COMMENTHDRLEN) != 0) 133 errx(1, "invalid comment in %s; must start with '%s'", 134 filename, COMMENTHDR); 135 *commentend = '\0'; 136 if (comment) { 137 if (strlcpy(comment, b64 + COMMENTHDRLEN, 138 COMMENTMAXLEN) >= COMMENTMAXLEN) 139 errx(1, "comment too long"); 140 } 141 if (!(b64end = strchr(commentend + 1, '\n'))) 142 errx(1, "missing new line after base64 in %s", filename); 143 *b64end = '\0'; 144 if (b64_pton(commentend + 1, buf, buflen) != buflen) 145 errx(1, "unable to parse %s", filename); 146 if (memcmp(buf, PKALG, 2) != 0) 147 errx(1, "unsupported file %s", filename); 148 return b64end - b64 + 1; 149 } 150 151 static void 152 readb64file(const char *filename, void *buf, size_t buflen, char *comment) 153 { 154 char b64[2048]; 155 int rv, fd; 156 157 fd = xopen(filename, O_RDONLY | O_NOFOLLOW, 0); 158 if ((rv = read(fd, b64, sizeof(b64) - 1)) == -1) 159 err(1, "read from %s", filename); 160 b64[rv] = '\0'; 161 parseb64file(filename, b64, buf, buflen, comment); 162 explicit_bzero(b64, sizeof(b64)); 163 close(fd); 164 } 165 166 static uint8_t * 167 readmsg(const char *filename, unsigned long long *msglenp) 168 { 169 unsigned long long msglen = 0; 170 uint8_t *msg = NULL; 171 struct stat sb; 172 ssize_t x, space; 173 int fd; 174 const unsigned long long maxmsgsize = 1UL << 30; 175 176 fd = xopen(filename, O_RDONLY | O_NOFOLLOW, 0); 177 if (fstat(fd, &sb) == 0 && S_ISREG(sb.st_mode)) { 178 if (sb.st_size > maxmsgsize) 179 errx(1, "msg too large in %s", filename); 180 space = sb.st_size + 1; 181 } else { 182 space = 64 * 1024 - 1; 183 } 184 185 msg = xmalloc(space + 1); 186 while (1) { 187 if (space == 0) { 188 if (msglen * 2 > maxmsgsize) 189 errx(1, "msg too large in %s", filename); 190 space = msglen; 191 if (!(msg = realloc(msg, msglen + space + 1))) 192 err(1, "realloc"); 193 } 194 if ((x = read(fd, msg + msglen, space)) == -1) 195 err(1, "read from %s", filename); 196 if (x == 0) 197 break; 198 space -= x; 199 msglen += x; 200 } 201 202 msg[msglen] = '\0'; 203 close(fd); 204 205 *msglenp = msglen; 206 return msg; 207 } 208 209 void 210 writeall(int fd, const void *buf, size_t buflen, const char *filename) 211 { 212 ssize_t x; 213 214 while (buflen != 0) { 215 if ((x = write(fd, buf, buflen)) == -1) 216 err(1, "write to %s", filename); 217 buflen -= x; 218 buf = (char *)buf + x; 219 } 220 } 221 222 #ifndef VERIFYONLY 223 static char * 224 createheader(const char *comment, const void *buf, size_t buflen) 225 { 226 char *header; 227 char b64[1024]; 228 229 if (b64_ntop(buf, buflen, b64, sizeof(b64)) == -1) 230 errx(1, "base64 encode failed"); 231 if (asprintf(&header, "%s%s\n%s\n", COMMENTHDR, comment, b64) == -1) 232 err(1, "asprintf failed"); 233 explicit_bzero(b64, sizeof(b64)); 234 return header; 235 } 236 237 static void 238 writekeyfile(const char *filename, const char *comment, const void *buf, 239 size_t buflen, int oflags, mode_t mode) 240 { 241 char *header; 242 int fd; 243 244 fd = xopen(filename, O_CREAT|oflags|O_NOFOLLOW|O_WRONLY, mode); 245 header = createheader(comment, buf, buflen); 246 writeall(fd, header, strlen(header), filename); 247 freezero(header, strlen(header)); 248 close(fd); 249 } 250 251 static void 252 kdf(uint8_t *salt, size_t saltlen, int rounds, int allowstdin, int confirm, 253 uint8_t *key, size_t keylen) 254 { 255 char pass[1024]; 256 int rppflags = RPP_ECHO_OFF; 257 const char *errstr = NULL; 258 259 if (rounds == 0) { 260 memset(key, 0, keylen); 261 return; 262 } 263 264 if (allowstdin && !isatty(STDIN_FILENO)) 265 rppflags |= RPP_STDIN; 266 if (!readpassphrase("passphrase: ", pass, sizeof(pass), rppflags)) 267 errx(1, "unable to read passphrase"); 268 if (strlen(pass) == 0) 269 errx(1, "please provide a password"); 270 if (confirm && !(rppflags & RPP_STDIN)) { 271 char pass2[1024]; 272 if (!readpassphrase("confirm passphrase: ", pass2, 273 sizeof(pass2), rppflags)) 274 errstr = "unable to read passphrase"; 275 if (!errstr && strcmp(pass, pass2) != 0) 276 errstr = "passwords don't match"; 277 explicit_bzero(pass2, sizeof(pass2)); 278 } 279 if (!errstr && bcrypt_pbkdf(pass, strlen(pass), salt, saltlen, key, 280 keylen, rounds) == -1) 281 errstr = "bcrypt pbkdf"; 282 explicit_bzero(pass, sizeof(pass)); 283 if (errstr) 284 errx(1, "%s", errstr); 285 } 286 287 static void 288 signmsg(uint8_t *seckey, uint8_t *msg, unsigned long long msglen, 289 uint8_t *sig) 290 { 291 unsigned long long siglen; 292 uint8_t *sigbuf; 293 294 sigbuf = xmalloc(msglen + SIGBYTES); 295 crypto_sign_ed25519(sigbuf, &siglen, msg, msglen, seckey); 296 memcpy(sig, sigbuf, SIGBYTES); 297 free(sigbuf); 298 } 299 300 static void 301 generate(const char *pubkeyfile, const char *seckeyfile, int rounds, 302 const char *comment) 303 { 304 uint8_t digest[SHA512_DIGEST_LENGTH]; 305 struct pubkey pubkey; 306 struct enckey enckey; 307 uint8_t xorkey[sizeof(enckey.seckey)]; 308 uint8_t keynum[KEYNUMLEN]; 309 char commentbuf[COMMENTMAXLEN]; 310 SHA2_CTX ctx; 311 int i, nr; 312 313 crypto_sign_ed25519_keypair(pubkey.pubkey, enckey.seckey); 314 arc4random_buf(keynum, sizeof(keynum)); 315 316 SHA512Init(&ctx); 317 SHA512Update(&ctx, enckey.seckey, sizeof(enckey.seckey)); 318 SHA512Final(digest, &ctx); 319 320 memcpy(enckey.pkalg, PKALG, 2); 321 memcpy(enckey.kdfalg, KDFALG, 2); 322 enckey.kdfrounds = htonl(rounds); 323 memcpy(enckey.keynum, keynum, KEYNUMLEN); 324 arc4random_buf(enckey.salt, sizeof(enckey.salt)); 325 kdf(enckey.salt, sizeof(enckey.salt), rounds, 1, 1, xorkey, sizeof(xorkey)); 326 memcpy(enckey.checksum, digest, sizeof(enckey.checksum)); 327 for (i = 0; i < sizeof(enckey.seckey); i++) 328 enckey.seckey[i] ^= xorkey[i]; 329 explicit_bzero(digest, sizeof(digest)); 330 explicit_bzero(xorkey, sizeof(xorkey)); 331 332 nr = snprintf(commentbuf, sizeof(commentbuf), "%s secret key", comment); 333 if (nr == -1 || nr >= sizeof(commentbuf)) 334 errx(1, "comment too long"); 335 writekeyfile(seckeyfile, commentbuf, &enckey, 336 sizeof(enckey), O_EXCL, 0600); 337 explicit_bzero(&enckey, sizeof(enckey)); 338 339 memcpy(pubkey.pkalg, PKALG, 2); 340 memcpy(pubkey.keynum, keynum, KEYNUMLEN); 341 nr = snprintf(commentbuf, sizeof(commentbuf), "%s public key", comment); 342 if (nr == -1 || nr >= sizeof(commentbuf)) 343 errx(1, "comment too long"); 344 writekeyfile(pubkeyfile, commentbuf, &pubkey, 345 sizeof(pubkey), O_EXCL, 0666); 346 } 347 348 static const char * 349 check_keyname_compliance(const char *pubkeyfile, const char *seckeyfile) 350 { 351 const char *pos; 352 size_t len; 353 354 /* basename may or may not modify input */ 355 pos = strrchr(seckeyfile, '/'); 356 if (pos != NULL) 357 seckeyfile = pos + 1; 358 359 len = strlen(seckeyfile); 360 if (len < 5) /* ?.key */ 361 goto bad; 362 if (strcmp(seckeyfile + len - 4, ".sec") != 0) 363 goto bad; 364 if (pubkeyfile != NULL) { 365 pos = strrchr(pubkeyfile, '/'); 366 if (pos != NULL) 367 pubkeyfile = pos + 1; 368 369 if (strlen(pubkeyfile) != len) 370 goto bad; 371 if (strcmp(pubkeyfile + len - 4, ".pub") != 0) 372 goto bad; 373 if (strncmp(pubkeyfile, seckeyfile, len - 4) != 0) 374 goto bad; 375 } 376 377 return seckeyfile; 378 bad: 379 errx(1, "please use naming scheme of keyname.pub and keyname.sec"); 380 } 381 382 uint8_t * 383 createsig(const char *seckeyfile, const char *msgfile, uint8_t *msg, 384 unsigned long long msglen) 385 { 386 struct enckey enckey; 387 uint8_t xorkey[sizeof(enckey.seckey)]; 388 struct sig sig; 389 char *sighdr; 390 uint8_t digest[SHA512_DIGEST_LENGTH]; 391 int i, nr, rounds; 392 SHA2_CTX ctx; 393 char comment[COMMENTMAXLEN], sigcomment[COMMENTMAXLEN]; 394 395 readb64file(seckeyfile, &enckey, sizeof(enckey), comment); 396 397 if (strcmp(seckeyfile, "-") == 0) { 398 nr = snprintf(sigcomment, sizeof(sigcomment), 399 "signature from %s", comment); 400 } else { 401 const char *keyname = check_keyname_compliance(NULL, 402 seckeyfile); 403 nr = snprintf(sigcomment, sizeof(sigcomment), 404 VERIFYWITH "%.*s.pub", (int)strlen(keyname) - 4, keyname); 405 } 406 if (nr == -1 || nr >= sizeof(sigcomment)) 407 errx(1, "comment too long"); 408 409 if (memcmp(enckey.kdfalg, KDFALG, 2) != 0) 410 errx(1, "unsupported KDF"); 411 rounds = ntohl(enckey.kdfrounds); 412 kdf(enckey.salt, sizeof(enckey.salt), rounds, strcmp(msgfile, "-") != 0, 413 0, xorkey, sizeof(xorkey)); 414 for (i = 0; i < sizeof(enckey.seckey); i++) 415 enckey.seckey[i] ^= xorkey[i]; 416 explicit_bzero(xorkey, sizeof(xorkey)); 417 SHA512Init(&ctx); 418 SHA512Update(&ctx, enckey.seckey, sizeof(enckey.seckey)); 419 SHA512Final(digest, &ctx); 420 if (memcmp(enckey.checksum, digest, sizeof(enckey.checksum)) != 0) 421 errx(1, "incorrect passphrase"); 422 explicit_bzero(digest, sizeof(digest)); 423 424 signmsg(enckey.seckey, msg, msglen, sig.sig); 425 memcpy(sig.keynum, enckey.keynum, KEYNUMLEN); 426 explicit_bzero(&enckey, sizeof(enckey)); 427 428 memcpy(sig.pkalg, PKALG, 2); 429 430 sighdr = createheader(sigcomment, &sig, sizeof(sig)); 431 return sighdr; 432 } 433 434 static void 435 sign(const char *seckeyfile, const char *msgfile, const char *sigfile, 436 int embedded) 437 { 438 uint8_t *msg; 439 char *sighdr; 440 int fd; 441 unsigned long long msglen; 442 443 msg = readmsg(msgfile, &msglen); 444 445 sighdr = createsig(seckeyfile, msgfile, msg, msglen); 446 447 fd = xopen(sigfile, O_CREAT|O_TRUNC|O_NOFOLLOW|O_WRONLY, 0666); 448 writeall(fd, sighdr, strlen(sighdr), sigfile); 449 free(sighdr); 450 if (embedded) 451 writeall(fd, msg, msglen, sigfile); 452 close(fd); 453 454 free(msg); 455 } 456 #endif 457 458 static void 459 verifymsg(struct pubkey *pubkey, uint8_t *msg, unsigned long long msglen, 460 struct sig *sig, int quiet) 461 { 462 uint8_t *sigbuf, *dummybuf; 463 unsigned long long siglen, dummylen; 464 465 if (memcmp(pubkey->keynum, sig->keynum, KEYNUMLEN) != 0) 466 errx(1, "verification failed: checked against wrong key"); 467 468 siglen = SIGBYTES + msglen; 469 sigbuf = xmalloc(siglen); 470 dummybuf = xmalloc(siglen); 471 memcpy(sigbuf, sig->sig, SIGBYTES); 472 memcpy(sigbuf + SIGBYTES, msg, msglen); 473 if (crypto_sign_ed25519_open(dummybuf, &dummylen, sigbuf, siglen, 474 pubkey->pubkey) == -1) 475 errx(1, "signature verification failed"); 476 if (!quiet) 477 printf("Signature Verified\n"); 478 free(sigbuf); 479 free(dummybuf); 480 } 481 482 static void 483 check_keytype(const char *pubkeyfile, const char *keytype) 484 { 485 const char *p; 486 size_t typelen; 487 488 if (!(p = strrchr(pubkeyfile, '-'))) 489 goto bad; 490 p++; 491 typelen = strlen(keytype); 492 if (strncmp(p, keytype, typelen) != 0) 493 goto bad; 494 if (strcmp(p + typelen, ".pub") != 0) 495 goto bad; 496 return; 497 498 bad: 499 errx(1, "incorrect keytype: %s is not %s", pubkeyfile, keytype); 500 } 501 502 static void 503 readpubkey(const char *pubkeyfile, struct pubkey *pubkey, 504 const char *sigcomment, const char *keytype) 505 { 506 const char *safepath = "/etc/signify"; 507 char keypath[1024]; 508 509 if (!pubkeyfile) { 510 pubkeyfile = strstr(sigcomment, VERIFYWITH); 511 if (pubkeyfile && strchr(pubkeyfile, '/') == NULL) { 512 pubkeyfile += strlen(VERIFYWITH); 513 if (keytype) 514 check_keytype(pubkeyfile, keytype); 515 if (snprintf(keypath, sizeof(keypath), "%s/%s", 516 safepath, pubkeyfile) >= sizeof(keypath)) 517 errx(1, "name too long %s", pubkeyfile); 518 pubkeyfile = keypath; 519 } else 520 usage("must specify pubkey"); 521 } 522 readb64file(pubkeyfile, pubkey, sizeof(*pubkey), NULL); 523 } 524 525 static void 526 verifysimple(const char *pubkeyfile, const char *msgfile, const char *sigfile, 527 int quiet, const char *keytype) 528 { 529 char sigcomment[COMMENTMAXLEN]; 530 struct sig sig; 531 struct pubkey pubkey; 532 unsigned long long msglen; 533 uint8_t *msg; 534 535 msg = readmsg(msgfile, &msglen); 536 537 readb64file(sigfile, &sig, sizeof(sig), sigcomment); 538 readpubkey(pubkeyfile, &pubkey, sigcomment, keytype); 539 540 verifymsg(&pubkey, msg, msglen, &sig, quiet); 541 542 free(msg); 543 } 544 545 static uint8_t * 546 verifyembedded(const char *pubkeyfile, const char *sigfile, 547 int quiet, unsigned long long *msglenp, const char *keytype) 548 { 549 char sigcomment[COMMENTMAXLEN]; 550 struct sig sig; 551 struct pubkey pubkey; 552 unsigned long long msglen, siglen; 553 uint8_t *msg; 554 555 msg = readmsg(sigfile, &msglen); 556 557 siglen = parseb64file(sigfile, msg, &sig, sizeof(sig), sigcomment); 558 readpubkey(pubkeyfile, &pubkey, sigcomment, keytype); 559 560 msglen -= siglen; 561 memmove(msg, msg + siglen, msglen); 562 msg[msglen] = 0; 563 564 verifymsg(&pubkey, msg, msglen, &sig, quiet); 565 566 *msglenp = msglen; 567 return msg; 568 } 569 570 static void 571 verify(const char *pubkeyfile, const char *msgfile, const char *sigfile, 572 int embedded, int quiet, const char *keytype) 573 { 574 unsigned long long msglen; 575 uint8_t *msg; 576 int fd; 577 578 if (embedded) { 579 msg = verifyembedded(pubkeyfile, sigfile, quiet, &msglen, 580 keytype); 581 fd = xopen(msgfile, O_CREAT|O_TRUNC|O_NOFOLLOW|O_WRONLY, 0666); 582 writeall(fd, msg, msglen, msgfile); 583 free(msg); 584 close(fd); 585 } else { 586 verifysimple(pubkeyfile, msgfile, sigfile, quiet, keytype); 587 } 588 } 589 590 #ifndef VERIFYONLY 591 #define HASHBUFSIZE 224 592 struct checksum { 593 char file[PATH_MAX]; 594 char hash[HASHBUFSIZE]; 595 char algo[32]; 596 }; 597 598 static void * 599 ecalloc(size_t s1, size_t s2, void *data) 600 { 601 void *p; 602 603 if (!(p = calloc(s1, s2))) 604 err(1, "calloc"); 605 return p; 606 } 607 608 static void 609 efree(void *p, void *data) 610 { 611 free(p); 612 } 613 614 static void 615 recodehash(char *hash, size_t len) 616 { 617 uint8_t data[HASHBUFSIZE / 2]; 618 int i, rv; 619 620 if (strlen(hash) == len) 621 return; 622 if ((rv = b64_pton(hash, data, sizeof(data))) == -1) 623 errx(1, "invalid base64 encoding"); 624 for (i = 0; i < rv; i++) 625 snprintf(hash + i * 2, HASHBUFSIZE - i * 2, "%2.2x", data[i]); 626 } 627 628 static int 629 verifychecksum(struct checksum *c, int quiet) 630 { 631 char buf[HASHBUFSIZE]; 632 633 if (strcmp(c->algo, "SHA256") == 0) { 634 recodehash(c->hash, SHA256_DIGEST_STRING_LENGTH-1); 635 if (!SHA256File(c->file, buf)) 636 return 0; 637 } else if (strcmp(c->algo, "SHA512") == 0) { 638 recodehash(c->hash, SHA512_DIGEST_STRING_LENGTH-1); 639 if (!SHA512File(c->file, buf)) 640 return 0; 641 } else { 642 errx(1, "can't handle algorithm %s", c->algo); 643 } 644 if (strcmp(c->hash, buf) != 0) 645 return 0; 646 if (!quiet) 647 printf("%s: OK\n", c->file); 648 return 1; 649 } 650 651 static void 652 verifychecksums(char *msg, int argc, char **argv, int quiet) 653 { 654 struct ohash_info info = { 0, NULL, ecalloc, efree, NULL }; 655 struct ohash myh; 656 struct checksum c; 657 char *e, *line, *endline; 658 int hasfailed = 0; 659 int i, rv; 660 unsigned int slot; 661 662 ohash_init(&myh, 6, &info); 663 if (argc) { 664 for (i = 0; i < argc; i++) { 665 slot = ohash_qlookup(&myh, argv[i]); 666 e = ohash_find(&myh, slot); 667 if (e == NULL) 668 ohash_insert(&myh, slot, argv[i]); 669 } 670 } 671 672 line = msg; 673 while (line && *line) { 674 if ((endline = strchr(line, '\n'))) 675 *endline++ = '\0'; 676 #if PATH_MAX < 1024 || HASHBUFSIZE < 224 677 #error sizes are wrong 678 #endif 679 rv = sscanf(line, "%31s (%1023[^)]) = %223s", 680 c.algo, c.file, c.hash); 681 if (rv != 3) 682 errx(1, "unable to parse checksum line %s", line); 683 line = endline; 684 if (argc) { 685 slot = ohash_qlookup(&myh, c.file); 686 e = ohash_find(&myh, slot); 687 if (e != NULL) { 688 if (verifychecksum(&c, quiet) != 0) 689 ohash_remove(&myh, slot); 690 } 691 } else { 692 if (verifychecksum(&c, quiet) == 0) { 693 slot = ohash_qlookup(&myh, c.file); 694 e = ohash_find(&myh, slot); 695 if (e == NULL) { 696 if (!(e = strdup(c.file))) 697 err(1, "strdup"); 698 ohash_insert(&myh, slot, e); 699 } 700 } 701 } 702 } 703 704 for (e = ohash_first(&myh, &slot); e != NULL; e = ohash_next(&myh, &slot)) { 705 fprintf(stderr, "%s: FAIL\n", e); 706 hasfailed = 1; 707 if (argc == 0) 708 free(e); 709 } 710 ohash_delete(&myh); 711 if (hasfailed) 712 exit(1); 713 } 714 715 static void 716 check(const char *pubkeyfile, const char *sigfile, int quiet, int argc, 717 char **argv) 718 { 719 unsigned long long msglen; 720 uint8_t *msg; 721 722 msg = verifyembedded(pubkeyfile, sigfile, quiet, &msglen, NULL); 723 verifychecksums((char *)msg, argc, argv, quiet); 724 725 free(msg); 726 } 727 728 void * 729 verifyzdata(uint8_t *zdata, unsigned long long zdatalen, 730 const char *filename, const char *pubkeyfile, const char *keytype) 731 { 732 struct sig sig; 733 char sigcomment[COMMENTMAXLEN]; 734 unsigned long long siglen; 735 struct pubkey pubkey; 736 737 if (zdatalen < sizeof(sig)) 738 errx(1, "signature too short in %s", filename); 739 siglen = parseb64file(filename, zdata, &sig, sizeof(sig), 740 sigcomment); 741 readpubkey(pubkeyfile, &pubkey, sigcomment, keytype); 742 zdata += siglen; 743 zdatalen -= siglen; 744 verifymsg(&pubkey, zdata, zdatalen, &sig, 1); 745 return zdata; 746 } 747 #endif 748 749 int 750 main(int argc, char **argv) 751 { 752 const char *pubkeyfile = NULL, *seckeyfile = NULL, *msgfile = NULL, 753 *sigfile = NULL; 754 char sigfilebuf[PATH_MAX]; 755 const char *comment = "signify"; 756 char *keytype = NULL; 757 int ch; 758 int none = 0; 759 int embedded = 0; 760 int quiet = 0; 761 int gzip = 0; 762 enum { 763 NONE, 764 CHECK, 765 GENERATE, 766 SIGN, 767 VERIFY 768 } verb = NONE; 769 770 if (pledge("stdio rpath wpath cpath tty", NULL) == -1) 771 err(1, "pledge"); 772 773 while ((ch = getopt(argc, argv, "CGSVzc:em:np:qs:t:x:")) != -1) { 774 switch (ch) { 775 #ifndef VERIFYONLY 776 case 'C': 777 if (verb) 778 usage(NULL); 779 verb = CHECK; 780 break; 781 case 'G': 782 if (verb) 783 usage(NULL); 784 verb = GENERATE; 785 break; 786 case 'S': 787 if (verb) 788 usage(NULL); 789 verb = SIGN; 790 break; 791 case 'z': 792 gzip = 1; 793 break; 794 #endif 795 case 'V': 796 if (verb) 797 usage(NULL); 798 verb = VERIFY; 799 break; 800 case 'c': 801 comment = optarg; 802 break; 803 case 'e': 804 embedded = 1; 805 break; 806 case 'm': 807 msgfile = optarg; 808 break; 809 case 'n': 810 none = 1; 811 break; 812 case 'p': 813 pubkeyfile = optarg; 814 break; 815 case 'q': 816 quiet = 1; 817 break; 818 case 's': 819 seckeyfile = optarg; 820 break; 821 case 't': 822 keytype = optarg; 823 break; 824 case 'x': 825 sigfile = optarg; 826 break; 827 default: 828 usage(NULL); 829 break; 830 } 831 } 832 argc -= optind; 833 argv += optind; 834 835 if (embedded && gzip) 836 errx(1, "can't combine -e and -z options"); 837 838 if (setvbuf(stdout, NULL, _IOLBF, 0) != 0) 839 err(1, "setvbuf"); 840 841 #ifndef VERIFYONLY 842 if (verb == CHECK) { 843 if (pledge("stdio rpath", NULL) == -1) 844 err(1, "pledge"); 845 if (!sigfile) 846 usage("must specify sigfile"); 847 check(pubkeyfile, sigfile, quiet, argc, argv); 848 return 0; 849 } 850 #endif 851 852 if (argc != 0) 853 usage(NULL); 854 855 if (!sigfile && msgfile) { 856 int nr; 857 if (strcmp(msgfile, "-") == 0) 858 usage("must specify sigfile with - message"); 859 nr = snprintf(sigfilebuf, sizeof(sigfilebuf), 860 "%s.sig", msgfile); 861 if (nr == -1 || nr >= sizeof(sigfilebuf)) 862 errx(1, "path too long"); 863 sigfile = sigfilebuf; 864 } 865 866 switch (verb) { 867 #ifndef VERIFYONLY 868 case GENERATE: 869 /* no pledge */ 870 if (!pubkeyfile || !seckeyfile) 871 usage("must specify pubkey and seckey"); 872 check_keyname_compliance(pubkeyfile, seckeyfile); 873 generate(pubkeyfile, seckeyfile, none ? 0 : 42, comment); 874 break; 875 case SIGN: 876 /* no pledge */ 877 if (gzip) { 878 if (!msgfile || !seckeyfile || !sigfile) 879 usage("must specify message sigfile seckey"); 880 zsign(seckeyfile, msgfile, sigfile, none); 881 } else { 882 if (!msgfile || !seckeyfile) 883 usage("must specify message and seckey"); 884 sign(seckeyfile, msgfile, sigfile, embedded); 885 } 886 break; 887 #endif 888 case VERIFY: 889 if ((embedded || gzip) && 890 (msgfile && strcmp(msgfile, "-") != 0)) { 891 /* will need to create output file */ 892 if (pledge("stdio rpath wpath cpath", NULL) == -1) 893 err(1, "pledge"); 894 } else { 895 if (pledge("stdio rpath", NULL) == -1) 896 err(1, "pledge"); 897 } 898 if (gzip) { 899 zverify(pubkeyfile, msgfile, sigfile, keytype); 900 } else { 901 if (!msgfile) 902 usage("must specify message"); 903 verify(pubkeyfile, msgfile, sigfile, embedded, 904 quiet, keytype); 905 } 906 break; 907 default: 908 if (pledge("stdio", NULL) == -1) 909 err(1, "pledge"); 910 usage(NULL); 911 break; 912 } 913 914 return 0; 915 } 916