1 /* $OpenBSD: signify.c,v 1.118 2016/09/10 12:23:16 deraadt 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 [-ez] [-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, "invalid base64 encoding in %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 explicit_bzero(header, strlen(header)); 248 free(header); 249 close(fd); 250 } 251 252 static void 253 kdf(uint8_t *salt, size_t saltlen, int rounds, int allowstdin, int confirm, 254 uint8_t *key, size_t keylen) 255 { 256 char pass[1024]; 257 int rppflags = RPP_ECHO_OFF; 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 errx(1, "unable to read passphrase"); 275 if (strcmp(pass, pass2) != 0) 276 errx(1, "passwords don't match"); 277 explicit_bzero(pass2, sizeof(pass2)); 278 } 279 if (bcrypt_pbkdf(pass, strlen(pass), salt, saltlen, key, 280 keylen, rounds) == -1) 281 errx(1, "bcrypt pbkdf"); 282 explicit_bzero(pass, sizeof(pass)); 283 } 284 285 static void 286 signmsg(uint8_t *seckey, uint8_t *msg, unsigned long long msglen, 287 uint8_t *sig) 288 { 289 unsigned long long siglen; 290 uint8_t *sigbuf; 291 292 sigbuf = xmalloc(msglen + SIGBYTES); 293 crypto_sign_ed25519(sigbuf, &siglen, msg, msglen, seckey); 294 memcpy(sig, sigbuf, SIGBYTES); 295 free(sigbuf); 296 } 297 298 static void 299 generate(const char *pubkeyfile, const char *seckeyfile, int rounds, 300 const char *comment) 301 { 302 uint8_t digest[SHA512_DIGEST_LENGTH]; 303 struct pubkey pubkey; 304 struct enckey enckey; 305 uint8_t xorkey[sizeof(enckey.seckey)]; 306 uint8_t keynum[KEYNUMLEN]; 307 char commentbuf[COMMENTMAXLEN]; 308 SHA2_CTX ctx; 309 int i, nr; 310 311 crypto_sign_ed25519_keypair(pubkey.pubkey, enckey.seckey); 312 arc4random_buf(keynum, sizeof(keynum)); 313 314 SHA512Init(&ctx); 315 SHA512Update(&ctx, enckey.seckey, sizeof(enckey.seckey)); 316 SHA512Final(digest, &ctx); 317 318 memcpy(enckey.pkalg, PKALG, 2); 319 memcpy(enckey.kdfalg, KDFALG, 2); 320 enckey.kdfrounds = htonl(rounds); 321 memcpy(enckey.keynum, keynum, KEYNUMLEN); 322 arc4random_buf(enckey.salt, sizeof(enckey.salt)); 323 kdf(enckey.salt, sizeof(enckey.salt), rounds, 1, 1, xorkey, sizeof(xorkey)); 324 memcpy(enckey.checksum, digest, sizeof(enckey.checksum)); 325 for (i = 0; i < sizeof(enckey.seckey); i++) 326 enckey.seckey[i] ^= xorkey[i]; 327 explicit_bzero(digest, sizeof(digest)); 328 explicit_bzero(xorkey, sizeof(xorkey)); 329 330 if ((nr = snprintf(commentbuf, sizeof(commentbuf), "%s secret key", 331 comment)) == -1 || nr >= sizeof(commentbuf)) 332 errx(1, "comment too long"); 333 writekeyfile(seckeyfile, commentbuf, &enckey, 334 sizeof(enckey), O_EXCL, 0600); 335 explicit_bzero(&enckey, sizeof(enckey)); 336 337 memcpy(pubkey.pkalg, PKALG, 2); 338 memcpy(pubkey.keynum, keynum, KEYNUMLEN); 339 if ((nr = snprintf(commentbuf, sizeof(commentbuf), "%s public key", 340 comment)) == -1 || nr >= sizeof(commentbuf)) 341 errx(1, "comment too long"); 342 writekeyfile(pubkeyfile, commentbuf, &pubkey, 343 sizeof(pubkey), O_EXCL, 0666); 344 } 345 346 uint8_t * 347 createsig(const char *seckeyfile, const char *msgfile, uint8_t *msg, 348 unsigned long long msglen) 349 { 350 struct enckey enckey; 351 uint8_t xorkey[sizeof(enckey.seckey)]; 352 struct sig sig; 353 char *sighdr; 354 char *secname; 355 uint8_t digest[SHA512_DIGEST_LENGTH]; 356 int i, nr, rounds; 357 SHA2_CTX ctx; 358 char comment[COMMENTMAXLEN], sigcomment[COMMENTMAXLEN]; 359 360 readb64file(seckeyfile, &enckey, sizeof(enckey), comment); 361 362 secname = strstr(seckeyfile, ".sec"); 363 if (secname && strlen(secname) == 4) { 364 if ((nr = snprintf(sigcomment, sizeof(sigcomment), VERIFYWITH "%.*s.pub", 365 (int)strlen(seckeyfile) - 4, seckeyfile)) == -1 || nr >= sizeof(sigcomment)) 366 errx(1, "comment too long"); 367 } else { 368 if ((nr = snprintf(sigcomment, sizeof(sigcomment), "signature from %s", 369 comment)) == -1 || nr >= sizeof(sigcomment)) 370 errx(1, "comment too long"); 371 } 372 373 if (memcmp(enckey.kdfalg, KDFALG, 2) != 0) 374 errx(1, "unsupported KDF"); 375 rounds = ntohl(enckey.kdfrounds); 376 kdf(enckey.salt, sizeof(enckey.salt), rounds, strcmp(msgfile, "-") != 0, 377 0, xorkey, sizeof(xorkey)); 378 for (i = 0; i < sizeof(enckey.seckey); i++) 379 enckey.seckey[i] ^= xorkey[i]; 380 explicit_bzero(xorkey, sizeof(xorkey)); 381 SHA512Init(&ctx); 382 SHA512Update(&ctx, enckey.seckey, sizeof(enckey.seckey)); 383 SHA512Final(digest, &ctx); 384 if (memcmp(enckey.checksum, digest, sizeof(enckey.checksum)) != 0) 385 errx(1, "incorrect passphrase"); 386 explicit_bzero(digest, sizeof(digest)); 387 388 signmsg(enckey.seckey, msg, msglen, sig.sig); 389 memcpy(sig.keynum, enckey.keynum, KEYNUMLEN); 390 explicit_bzero(&enckey, sizeof(enckey)); 391 392 memcpy(sig.pkalg, PKALG, 2); 393 394 sighdr = createheader(sigcomment, &sig, sizeof(sig)); 395 return sighdr; 396 } 397 398 static void 399 sign(const char *seckeyfile, const char *msgfile, const char *sigfile, 400 int embedded) 401 { 402 uint8_t *msg; 403 char *sighdr; 404 int fd; 405 unsigned long long msglen; 406 407 msg = readmsg(msgfile, &msglen); 408 409 sighdr = createsig(seckeyfile, msgfile, msg, msglen); 410 411 fd = xopen(sigfile, O_CREAT|O_TRUNC|O_NOFOLLOW|O_WRONLY, 0666); 412 writeall(fd, sighdr, strlen(sighdr), sigfile); 413 free(sighdr); 414 if (embedded) 415 writeall(fd, msg, msglen, sigfile); 416 close(fd); 417 418 free(msg); 419 } 420 #endif 421 422 static void 423 verifymsg(struct pubkey *pubkey, uint8_t *msg, unsigned long long msglen, 424 struct sig *sig, int quiet) 425 { 426 uint8_t *sigbuf, *dummybuf; 427 unsigned long long siglen, dummylen; 428 429 if (memcmp(pubkey->keynum, sig->keynum, KEYNUMLEN) != 0) 430 errx(1, "verification failed: checked against wrong key"); 431 432 siglen = SIGBYTES + msglen; 433 sigbuf = xmalloc(siglen); 434 dummybuf = xmalloc(siglen); 435 memcpy(sigbuf, sig->sig, SIGBYTES); 436 memcpy(sigbuf + SIGBYTES, msg, msglen); 437 if (crypto_sign_ed25519_open(dummybuf, &dummylen, sigbuf, siglen, 438 pubkey->pubkey) == -1) 439 errx(1, "signature verification failed"); 440 if (!quiet) 441 printf("Signature Verified\n"); 442 free(sigbuf); 443 free(dummybuf); 444 } 445 446 #ifndef VERIFYONLY 447 static void 448 check_keytype(const char *pubkeyfile, const char *keytype) 449 { 450 size_t len; 451 char *cmp; 452 int slen; 453 454 len = strlen(pubkeyfile); 455 slen = asprintf(&cmp, "-%s.pub", keytype); 456 if (slen < 0) 457 err(1, "asprintf error"); 458 if (len < slen) 459 errx(1, "too short"); 460 461 if (strcmp(pubkeyfile + len - slen, cmp) != 0) 462 errx(1, "wrong keytype"); 463 free(cmp); 464 } 465 #endif 466 467 static void 468 readpubkey(const char *pubkeyfile, struct pubkey *pubkey, 469 const char *sigcomment, const char *keytype) 470 { 471 const char *safepath = "/etc/signify/"; 472 473 if (!pubkeyfile) { 474 pubkeyfile = strstr(sigcomment, VERIFYWITH); 475 if (pubkeyfile) { 476 pubkeyfile += strlen(VERIFYWITH); 477 if (strncmp(pubkeyfile, safepath, strlen(safepath)) != 0 || 478 strstr(pubkeyfile, "/../") != NULL) 479 errx(1, "untrusted path %s", pubkeyfile); 480 #ifndef VERIFYONLY 481 if (keytype) 482 check_keytype(pubkeyfile, keytype); 483 #endif 484 } else 485 usage("must specify pubkey"); 486 } 487 readb64file(pubkeyfile, pubkey, sizeof(*pubkey), NULL); 488 } 489 490 static void 491 verifysimple(const char *pubkeyfile, const char *msgfile, const char *sigfile, 492 int quiet, const char *keytype) 493 { 494 char sigcomment[COMMENTMAXLEN]; 495 struct sig sig; 496 struct pubkey pubkey; 497 unsigned long long msglen; 498 uint8_t *msg; 499 500 msg = readmsg(msgfile, &msglen); 501 502 readb64file(sigfile, &sig, sizeof(sig), sigcomment); 503 readpubkey(pubkeyfile, &pubkey, sigcomment, keytype); 504 505 verifymsg(&pubkey, msg, msglen, &sig, quiet); 506 507 free(msg); 508 } 509 510 static uint8_t * 511 verifyembedded(const char *pubkeyfile, const char *sigfile, 512 int quiet, unsigned long long *msglenp, const char *keytype) 513 { 514 char sigcomment[COMMENTMAXLEN]; 515 struct sig sig; 516 struct pubkey pubkey; 517 unsigned long long msglen, siglen; 518 uint8_t *msg; 519 520 msg = readmsg(sigfile, &msglen); 521 522 siglen = parseb64file(sigfile, msg, &sig, sizeof(sig), sigcomment); 523 readpubkey(pubkeyfile, &pubkey, sigcomment, keytype); 524 525 msglen -= siglen; 526 memmove(msg, msg + siglen, msglen); 527 msg[msglen] = 0; 528 529 verifymsg(&pubkey, msg, msglen, &sig, quiet); 530 531 *msglenp = msglen; 532 return msg; 533 } 534 535 static void 536 verify(const char *pubkeyfile, const char *msgfile, const char *sigfile, 537 int embedded, int quiet, const char *keytype) 538 { 539 unsigned long long msglen; 540 uint8_t *msg; 541 int fd; 542 543 if (embedded) { 544 msg = verifyembedded(pubkeyfile, sigfile, quiet, &msglen, 545 keytype); 546 fd = xopen(msgfile, O_CREAT|O_TRUNC|O_NOFOLLOW|O_WRONLY, 0666); 547 writeall(fd, msg, msglen, msgfile); 548 free(msg); 549 close(fd); 550 } else { 551 verifysimple(pubkeyfile, msgfile, sigfile, quiet, keytype); 552 } 553 } 554 555 #ifndef VERIFYONLY 556 #define HASHBUFSIZE 224 557 struct checksum { 558 char file[PATH_MAX]; 559 char hash[HASHBUFSIZE]; 560 char algo[32]; 561 }; 562 563 static void * 564 ecalloc(size_t s1, size_t s2, void *data) 565 { 566 void *p; 567 568 if (!(p = calloc(s1, s2))) 569 err(1, "calloc"); 570 return p; 571 } 572 573 static void 574 efree(void *p, void *data) 575 { 576 free(p); 577 } 578 579 static void 580 recodehash(char *hash, size_t len) 581 { 582 uint8_t data[HASHBUFSIZE / 2]; 583 int i, rv; 584 585 if (strlen(hash) == len) 586 return; 587 if ((rv = b64_pton(hash, data, sizeof(data))) == -1) 588 errx(1, "invalid base64 encoding"); 589 for (i = 0; i < rv; i++) 590 snprintf(hash + i * 2, HASHBUFSIZE - i * 2, "%2.2x", data[i]); 591 } 592 593 static int 594 verifychecksum(struct checksum *c, int quiet) 595 { 596 char buf[HASHBUFSIZE]; 597 598 if (strcmp(c->algo, "SHA256") == 0) { 599 recodehash(c->hash, SHA256_DIGEST_STRING_LENGTH-1); 600 if (!SHA256File(c->file, buf)) 601 return 0; 602 } else if (strcmp(c->algo, "SHA512") == 0) { 603 recodehash(c->hash, SHA512_DIGEST_STRING_LENGTH-1); 604 if (!SHA512File(c->file, buf)) 605 return 0; 606 } else { 607 errx(1, "can't handle algorithm %s", c->algo); 608 } 609 if (strcmp(c->hash, buf) != 0) 610 return 0; 611 if (!quiet) 612 printf("%s: OK\n", c->file); 613 return 1; 614 } 615 616 static void 617 verifychecksums(char *msg, int argc, char **argv, int quiet) 618 { 619 struct ohash_info info = { 0, NULL, ecalloc, efree, NULL }; 620 struct ohash myh; 621 struct checksum c; 622 char *e, *line, *endline; 623 int hasfailed = 0; 624 int i, rv; 625 unsigned int slot; 626 627 ohash_init(&myh, 6, &info); 628 if (argc) { 629 for (i = 0; i < argc; i++) { 630 slot = ohash_qlookup(&myh, argv[i]); 631 e = ohash_find(&myh, slot); 632 if (e == NULL) 633 ohash_insert(&myh, slot, argv[i]); 634 } 635 } 636 637 line = msg; 638 while (line && *line) { 639 if ((endline = strchr(line, '\n'))) 640 *endline++ = '\0'; 641 #if PATH_MAX < 1024 || HASHBUFSIZE < 224 642 #error sizes are wrong 643 #endif 644 rv = sscanf(line, "%31s (%1023[^)]) = %223s", 645 c.algo, c.file, c.hash); 646 if (rv != 3) 647 errx(1, "unable to parse checksum line %s", line); 648 line = endline; 649 if (argc) { 650 slot = ohash_qlookup(&myh, c.file); 651 e = ohash_find(&myh, slot); 652 if (e != NULL) { 653 if (verifychecksum(&c, quiet) != 0) 654 ohash_remove(&myh, slot); 655 } 656 } else { 657 if (verifychecksum(&c, quiet) == 0) { 658 slot = ohash_qlookup(&myh, c.file); 659 e = ohash_find(&myh, slot); 660 if (e == NULL) { 661 if (!(e = strdup(c.file))) 662 err(1, "strdup"); 663 ohash_insert(&myh, slot, e); 664 } 665 } 666 } 667 } 668 669 for (e = ohash_first(&myh, &slot); e != NULL; e = ohash_next(&myh, &slot)) { 670 fprintf(stderr, "%s: FAIL\n", e); 671 hasfailed = 1; 672 if (argc == 0) 673 free(e); 674 } 675 ohash_delete(&myh); 676 if (hasfailed) 677 exit(1); 678 } 679 680 static void 681 check(const char *pubkeyfile, const char *sigfile, int quiet, int argc, 682 char **argv) 683 { 684 unsigned long long msglen; 685 uint8_t *msg; 686 687 msg = verifyembedded(pubkeyfile, sigfile, quiet, &msglen, NULL); 688 verifychecksums((char *)msg, argc, argv, quiet); 689 690 free(msg); 691 } 692 693 void * 694 verifyzdata(uint8_t *zdata, unsigned long long zdatalen, 695 const char *filename, const char *pubkeyfile, const char *keytype) 696 { 697 struct sig sig; 698 char sigcomment[COMMENTMAXLEN]; 699 unsigned long long siglen; 700 struct pubkey pubkey; 701 702 if (zdatalen < sizeof(sig)) 703 errx(1, "signature too short in %s", filename); 704 siglen = parseb64file(filename, zdata, &sig, sizeof(sig), 705 sigcomment); 706 readpubkey(pubkeyfile, &pubkey, sigcomment, keytype); 707 zdata += siglen; 708 zdatalen -= siglen; 709 verifymsg(&pubkey, zdata, zdatalen, &sig, 1); 710 return zdata; 711 } 712 #endif 713 714 int 715 main(int argc, char **argv) 716 { 717 const char *pubkeyfile = NULL, *seckeyfile = NULL, *msgfile = NULL, 718 *sigfile = NULL; 719 char sigfilebuf[PATH_MAX]; 720 const char *comment = "signify"; 721 char *keytype = NULL; 722 int ch, rounds; 723 int embedded = 0; 724 int quiet = 0; 725 int gzip = 0; 726 enum { 727 NONE, 728 CHECK, 729 GENERATE, 730 SIGN, 731 VERIFY 732 } verb = NONE; 733 734 if (pledge("stdio rpath wpath cpath tty", NULL) == -1) 735 err(1, "pledge"); 736 737 rounds = 42; 738 739 while ((ch = getopt(argc, argv, "CGSVzc:em:np:qs:t:x:")) != -1) { 740 switch (ch) { 741 #ifndef VERIFYONLY 742 case 'C': 743 if (verb) 744 usage(NULL); 745 verb = CHECK; 746 break; 747 case 'G': 748 if (verb) 749 usage(NULL); 750 verb = GENERATE; 751 break; 752 case 'S': 753 if (verb) 754 usage(NULL); 755 verb = SIGN; 756 break; 757 case 'z': 758 gzip = 1; 759 break; 760 #endif 761 case 'V': 762 if (verb) 763 usage(NULL); 764 verb = VERIFY; 765 break; 766 case 'c': 767 comment = optarg; 768 break; 769 case 'e': 770 embedded = 1; 771 break; 772 case 'm': 773 msgfile = optarg; 774 break; 775 case 'n': 776 rounds = 0; 777 break; 778 case 'p': 779 pubkeyfile = optarg; 780 break; 781 case 'q': 782 quiet = 1; 783 break; 784 case 's': 785 seckeyfile = optarg; 786 break; 787 case 't': 788 keytype = optarg; 789 break; 790 case 'x': 791 sigfile = optarg; 792 break; 793 default: 794 usage(NULL); 795 break; 796 } 797 } 798 argc -= optind; 799 argv += optind; 800 801 if (embedded && gzip) 802 errx(1, "can't combine -e and -z options"); 803 804 if (setvbuf(stdout, NULL, _IOLBF, 0) != 0) 805 err(1, "setvbuf"); 806 807 #ifndef VERIFYONLY 808 if (verb == CHECK) { 809 if (pledge("stdio rpath", NULL) == -1) 810 err(1, "pledge"); 811 if (!sigfile) 812 usage("must specify sigfile"); 813 check(pubkeyfile, sigfile, quiet, argc, argv); 814 return 0; 815 } 816 #endif 817 818 if (argc != 0) 819 usage(NULL); 820 821 if (!sigfile && msgfile) { 822 int nr; 823 if (strcmp(msgfile, "-") == 0) 824 usage("must specify sigfile with - message"); 825 if ((nr = snprintf(sigfilebuf, sizeof(sigfilebuf), "%s.sig", 826 msgfile)) == -1 || nr >= sizeof(sigfilebuf)) 827 errx(1, "path too long"); 828 sigfile = sigfilebuf; 829 } 830 831 switch (verb) { 832 #ifndef VERIFYONLY 833 case GENERATE: 834 /* no pledge */ 835 if (!pubkeyfile || !seckeyfile) 836 usage("must specify pubkey and seckey"); 837 generate(pubkeyfile, seckeyfile, rounds, comment); 838 break; 839 case SIGN: 840 /* no pledge */ 841 if (gzip) { 842 if (!msgfile || !seckeyfile || !sigfile) 843 usage("must specify message sigfile seckey"); 844 zsign(seckeyfile, msgfile, sigfile); 845 } else { 846 if (!msgfile || !seckeyfile) 847 usage("must specify message and seckey"); 848 sign(seckeyfile, msgfile, sigfile, embedded); 849 } 850 break; 851 #endif 852 case VERIFY: 853 if ((embedded || gzip) && 854 (msgfile && strcmp(msgfile, "-") != 0)) { 855 /* will need to create output file */ 856 if (pledge("stdio rpath wpath cpath", NULL) == -1) 857 err(1, "pledge"); 858 } else { 859 if (pledge("stdio rpath", NULL) == -1) 860 err(1, "pledge"); 861 } 862 if (gzip) { 863 zverify(pubkeyfile, msgfile, sigfile, keytype); 864 } else { 865 if (!msgfile) 866 usage("must specify message"); 867 verify(pubkeyfile, msgfile, sigfile, embedded, 868 quiet, keytype); 869 } 870 break; 871 default: 872 if (pledge("stdio", NULL) == -1) 873 err(1, "pledge"); 874 usage(NULL); 875 break; 876 } 877 878 return 0; 879 } 880