Annotation of src/usr.bin/signify/signify.c, Revision 1.49
1.49 ! tedu 1: /* $OpenBSD: signify.c,v 1.48 2014/03/06 20:04:45 tedu Exp $ */
1.1 tedu 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 <stdint.h>
23: #include <fcntl.h>
24: #include <string.h>
25: #include <stdio.h>
1.34 tedu 26: #include <stdlib.h>
1.1 tedu 27: #include <err.h>
28: #include <unistd.h>
29: #include <readpassphrase.h>
30: #include <util.h>
31: #include <sha2.h>
32:
33: #include "crypto_api.h"
34:
35: #define SIGBYTES crypto_sign_ed25519_BYTES
36: #define SECRETBYTES crypto_sign_ed25519_SECRETKEYBYTES
37: #define PUBLICBYTES crypto_sign_ed25519_PUBLICKEYBYTES
38:
39: #define PKALG "Ed"
40: #define KDFALG "BK"
1.13 tedu 41: #define FPLEN 8
42:
1.18 tedu 43: #define COMMENTHDR "untrusted comment: "
44: #define COMMENTHDRLEN 19
45: #define COMMENTMAXLEN 1024
1.1 tedu 46:
47: struct enckey {
48: uint8_t pkalg[2];
49: uint8_t kdfalg[2];
50: uint32_t kdfrounds;
51: uint8_t salt[16];
52: uint8_t checksum[8];
1.13 tedu 53: uint8_t fingerprint[FPLEN];
1.1 tedu 54: uint8_t seckey[SECRETBYTES];
55: };
56:
57: struct pubkey {
58: uint8_t pkalg[2];
1.13 tedu 59: uint8_t fingerprint[FPLEN];
1.1 tedu 60: uint8_t pubkey[PUBLICBYTES];
61: };
62:
63: struct sig {
64: uint8_t pkalg[2];
1.13 tedu 65: uint8_t fingerprint[FPLEN];
1.1 tedu 66: uint8_t sig[SIGBYTES];
67: };
68:
69: extern char *__progname;
70:
71: static void
1.31 tedu 72: usage(const char *error)
1.1 tedu 73: {
1.31 tedu 74: if (error)
75: fprintf(stderr, "%s\n", error);
1.9 espie 76: fprintf(stderr, "usage:"
1.15 espie 77: #ifndef VERIFYONLY
1.47 naddy 78: "\t%1$s -C [-q] -p pubkey -x sigfile [file ...]\n"
1.31 tedu 79: "\t%1$s -G [-n] [-c comment] -p pubkey -s seckey\n"
80: "\t%1$s -I [-p pubkey] [-s seckey] [-x sigfile]\n"
81: "\t%1$s -S [-e] [-x sigfile] -s seckey -m message\n"
1.15 espie 82: #endif
1.42 tedu 83: "\t%1$s -V [-eq] [-x sigfile] -p pubkey -m message\n",
1.15 espie 84: __progname);
1.1 tedu 85: exit(1);
86: }
87:
88: static int
89: xopen(const char *fname, int flags, mode_t mode)
90: {
91: int fd;
92:
1.31 tedu 93: if (strcmp(fname, "-") == 0) {
94: if ((flags & O_WRONLY))
95: fd = dup(STDOUT_FILENO);
96: else
97: fd = dup(STDIN_FILENO);
98: if (fd == -1)
99: err(1, "dup failed");
100: } else {
101: fd = open(fname, flags, mode);
102: if (fd == -1)
103: err(1, "can't open %s for %s", fname,
104: (flags & O_WRONLY) ? "writing" : "reading");
105: }
1.1 tedu 106: return fd;
107: }
108:
109: static void *
110: xmalloc(size_t len)
111: {
112: void *p;
113:
114: p = malloc(len);
115: if (!p)
116: err(1, "malloc %zu", len);
117: return p;
118: }
119:
1.16 tedu 120: static size_t
1.46 tedu 121: parseb64file(const char *filename, char *b64, void *buf, size_t buflen,
1.18 tedu 122: char *comment)
1.16 tedu 123: {
124: int rv;
125: char *commentend, *b64end;
126:
127: commentend = strchr(b64, '\n');
128: if (!commentend || commentend - b64 <= COMMENTHDRLEN ||
129: memcmp(b64, COMMENTHDR, COMMENTHDRLEN))
130: errx(1, "invalid comment in %s; must start with '%s'",
131: filename, COMMENTHDR);
1.18 tedu 132: *commentend = 0;
1.40 deraadt 133: if (comment) {
134: if (strlcpy(comment, b64 + COMMENTHDRLEN,
135: COMMENTMAXLEN) >= COMMENTMAXLEN)
136: err(1, "comment too long");
137: }
1.16 tedu 138: b64end = strchr(commentend + 1, '\n');
139: if (!b64end)
140: errx(1, "missing new line after b64 in %s", filename);
141: *b64end = 0;
1.46 tedu 142: rv = b64_pton(commentend + 1, buf, buflen);
143: if (rv != buflen)
1.16 tedu 144: errx(1, "invalid b64 encoding in %s", filename);
145: if (memcmp(buf, PKALG, 2))
146: errx(1, "unsupported file %s", filename);
147: return b64end - b64 + 1;
148: }
149:
1.1 tedu 150: static void
1.46 tedu 151: readb64file(const char *filename, void *buf, size_t buflen, char *comment)
1.1 tedu 152: {
153: char b64[2048];
1.10 tedu 154: int rv, fd;
1.1 tedu 155:
156: fd = xopen(filename, O_RDONLY | O_NOFOLLOW, 0);
157: memset(b64, 0, sizeof(b64));
158: rv = read(fd, b64, sizeof(b64) - 1);
159: if (rv == -1)
1.7 espie 160: err(1, "read from %s", filename);
1.46 tedu 161: parseb64file(filename, b64, buf, buflen, comment);
1.41 tedu 162: explicit_bzero(b64, sizeof(b64));
1.1 tedu 163: close(fd);
164: }
165:
1.35 tedu 166: static uint8_t *
1.1 tedu 167: readmsg(const char *filename, unsigned long long *msglenp)
168: {
1.49 ! tedu 169: unsigned long long msglen = 0;
! 170: uint8_t *msg = NULL;
1.1 tedu 171: struct stat sb;
1.49 ! tedu 172: ssize_t x, space;
1.1 tedu 173: int fd;
1.49 ! tedu 174: const size_t chunklen = 64 * 1024;
1.1 tedu 175:
176: fd = xopen(filename, O_RDONLY | O_NOFOLLOW, 0);
1.49 ! tedu 177: if (fstat(fd, &sb) == 0 && S_ISREG(sb.st_mode)) {
! 178: if (sb.st_size > (1UL << 30))
! 179: errx(1, "msg too large in %s", filename);
! 180: space = sb.st_size + 1;
! 181: msg = xmalloc(space + 1);
! 182: } else {
! 183: space = 0;
! 184: }
! 185:
! 186: while (1) {
! 187: if (space == 0) {
! 188: space = chunklen;
! 189: if (!(msg = realloc(msg, msglen + space + 1)))
! 190: errx(1, "realloc");
! 191: }
! 192: if ((x = read(fd, msg + msglen, space)) == -1)
! 193: err(1, "read from %s", filename);
! 194: if (x == 0)
! 195: break;
! 196: space -= x;
! 197: msglen += x;
! 198: if (msglen > (1UL << 30))
! 199: errx(1, "msg too large in %s", filename);
! 200: }
! 201:
1.45 tedu 202: msg[msglen] = 0;
1.1 tedu 203: close(fd);
204:
205: *msglenp = msglen;
206: return msg;
207: }
208:
209: static void
1.46 tedu 210: writeall(int fd, const void *buf, size_t buflen, const char *filename)
1.1 tedu 211: {
1.11 tedu 212: ssize_t x;
1.38 espie 213:
1.46 tedu 214: while (buflen != 0) {
215: x = write(fd, buf, buflen);
1.38 espie 216: if (x == -1)
217: err(1, "write to %s", filename);
1.46 tedu 218: buflen -= x;
1.44 tedu 219: buf = (char*)buf + x;
1.7 espie 220: }
1.1 tedu 221: }
222:
1.17 deraadt 223: #ifndef VERIFYONLY
1.1 tedu 224: static void
1.46 tedu 225: appendall(const char *filename, const void *buf, size_t buflen)
1.16 tedu 226: {
227: int fd;
228:
1.30 tedu 229: fd = xopen(filename, O_NOFOLLOW | O_WRONLY | O_APPEND, 0);
1.46 tedu 230: writeall(fd, buf, buflen, filename);
1.16 tedu 231: close(fd);
232: }
233:
234: static void
1.1 tedu 235: writeb64file(const char *filename, const char *comment, const void *buf,
1.46 tedu 236: size_t buflen, int flags, mode_t mode)
1.1 tedu 237: {
238: char header[1024];
239: char b64[1024];
240: int fd, rv;
241:
1.30 tedu 242: fd = xopen(filename, O_CREAT|flags|O_NOFOLLOW|O_WRONLY, mode);
1.40 deraadt 243: if (snprintf(header, sizeof(header), "%s%s\n",
244: COMMENTHDR, comment) >= sizeof(header))
245: err(1, "comment too long");
1.7 espie 246: writeall(fd, header, strlen(header), filename);
1.46 tedu 247: if ((rv = b64_ntop(buf, buflen, b64, sizeof(b64)-1)) == -1)
1.1 tedu 248: errx(1, "b64 encode failed");
1.8 espie 249: b64[rv++] = '\n';
1.7 espie 250: writeall(fd, b64, rv, filename);
1.41 tedu 251: explicit_bzero(b64, sizeof(b64));
1.1 tedu 252: close(fd);
253: }
254:
255: static void
256: kdf(uint8_t *salt, size_t saltlen, int rounds, uint8_t *key, size_t keylen)
257: {
258: char pass[1024];
1.48 tedu 259: int rppflags = RPP_ECHO_OFF;
1.1 tedu 260:
261: if (rounds == 0) {
262: memset(key, 0, keylen);
263: return;
264: }
265:
1.48 tedu 266: if (!isatty(STDIN_FILENO))
267: rppflags |= RPP_STDIN;
268: if (!readpassphrase("passphrase: ", pass, sizeof(pass), rppflags))
1.39 tedu 269: errx(1, "unable to read passphrase");
1.37 tedu 270: if (strlen(pass) == 0)
271: errx(1, "please provide a password");
1.1 tedu 272: if (bcrypt_pbkdf(pass, strlen(pass), salt, saltlen, key,
273: keylen, rounds) == -1)
274: errx(1, "bcrypt pbkdf");
1.41 tedu 275: explicit_bzero(pass, sizeof(pass));
1.1 tedu 276: }
277:
278: static void
279: signmsg(uint8_t *seckey, uint8_t *msg, unsigned long long msglen,
280: uint8_t *sig)
281: {
282: unsigned long long siglen;
283: uint8_t *sigbuf;
284:
285: sigbuf = xmalloc(msglen + SIGBYTES);
286: crypto_sign_ed25519(sigbuf, &siglen, msg, msglen, seckey);
287: memcpy(sig, sigbuf, SIGBYTES);
288: free(sigbuf);
289: }
290:
291: static void
1.27 tedu 292: generate(const char *pubkeyfile, const char *seckeyfile, int rounds,
293: const char *comment)
1.1 tedu 294: {
295: uint8_t digest[SHA512_DIGEST_LENGTH];
296: struct pubkey pubkey;
297: struct enckey enckey;
298: uint8_t xorkey[sizeof(enckey.seckey)];
1.13 tedu 299: uint8_t fingerprint[FPLEN];
1.27 tedu 300: char commentbuf[COMMENTMAXLEN];
1.1 tedu 301: SHA2_CTX ctx;
302: int i;
303:
304: crypto_sign_ed25519_keypair(pubkey.pubkey, enckey.seckey);
1.13 tedu 305: arc4random_buf(fingerprint, sizeof(fingerprint));
1.1 tedu 306:
307: SHA512Init(&ctx);
308: SHA512Update(&ctx, enckey.seckey, sizeof(enckey.seckey));
309: SHA512Final(digest, &ctx);
310:
311: memcpy(enckey.pkalg, PKALG, 2);
312: memcpy(enckey.kdfalg, KDFALG, 2);
313: enckey.kdfrounds = htonl(rounds);
1.13 tedu 314: memcpy(enckey.fingerprint, fingerprint, FPLEN);
1.1 tedu 315: arc4random_buf(enckey.salt, sizeof(enckey.salt));
316: kdf(enckey.salt, sizeof(enckey.salt), rounds, xorkey, sizeof(xorkey));
317: memcpy(enckey.checksum, digest, sizeof(enckey.checksum));
318: for (i = 0; i < sizeof(enckey.seckey); i++)
319: enckey.seckey[i] ^= xorkey[i];
1.41 tedu 320: explicit_bzero(digest, sizeof(digest));
321: explicit_bzero(xorkey, sizeof(xorkey));
1.1 tedu 322:
1.40 deraadt 323: if (snprintf(commentbuf, sizeof(commentbuf), "%s secret key",
324: comment) >= sizeof(commentbuf))
325: err(1, "comment too long");
1.27 tedu 326: writeb64file(seckeyfile, commentbuf, &enckey,
1.20 espie 327: sizeof(enckey), O_EXCL, 0600);
1.41 tedu 328: explicit_bzero(&enckey, sizeof(enckey));
1.1 tedu 329:
330: memcpy(pubkey.pkalg, PKALG, 2);
1.13 tedu 331: memcpy(pubkey.fingerprint, fingerprint, FPLEN);
1.40 deraadt 332: if (snprintf(commentbuf, sizeof(commentbuf), "%s public key",
333: comment) >= sizeof(commentbuf))
334: err(1, "comment too long");
1.27 tedu 335: writeb64file(pubkeyfile, commentbuf, &pubkey,
1.20 espie 336: sizeof(pubkey), O_EXCL, 0666);
1.1 tedu 337: }
338:
339: static void
1.16 tedu 340: sign(const char *seckeyfile, const char *msgfile, const char *sigfile,
341: int embedded)
1.1 tedu 342: {
343: struct sig sig;
344: uint8_t digest[SHA512_DIGEST_LENGTH];
345: struct enckey enckey;
346: uint8_t xorkey[sizeof(enckey.seckey)];
347: uint8_t *msg;
1.18 tedu 348: char comment[COMMENTMAXLEN], sigcomment[1024];
1.1 tedu 349: unsigned long long msglen;
350: int i, rounds;
351: SHA2_CTX ctx;
352:
1.18 tedu 353: readb64file(seckeyfile, &enckey, sizeof(enckey), comment);
1.1 tedu 354:
355: if (memcmp(enckey.kdfalg, KDFALG, 2))
356: errx(1, "unsupported KDF");
357: rounds = ntohl(enckey.kdfrounds);
358: kdf(enckey.salt, sizeof(enckey.salt), rounds, xorkey, sizeof(xorkey));
359: for (i = 0; i < sizeof(enckey.seckey); i++)
360: enckey.seckey[i] ^= xorkey[i];
1.41 tedu 361: explicit_bzero(xorkey, sizeof(xorkey));
1.1 tedu 362: SHA512Init(&ctx);
363: SHA512Update(&ctx, enckey.seckey, sizeof(enckey.seckey));
364: SHA512Final(digest, &ctx);
365: if (memcmp(enckey.checksum, digest, sizeof(enckey.checksum)))
366: errx(1, "incorrect passphrase");
1.41 tedu 367: explicit_bzero(digest, sizeof(digest));
1.1 tedu 368:
1.16 tedu 369: msg = readmsg(msgfile, &msglen);
1.1 tedu 370:
371: signmsg(enckey.seckey, msg, msglen, sig.sig);
1.13 tedu 372: memcpy(sig.fingerprint, enckey.fingerprint, FPLEN);
1.41 tedu 373: explicit_bzero(&enckey, sizeof(enckey));
1.1 tedu 374:
375: memcpy(sig.pkalg, PKALG, 2);
1.40 deraadt 376: if (snprintf(sigcomment, sizeof(sigcomment), "signature from %s",
377: comment) >= sizeof(sigcomment))
378: err(1, "comment too long");
1.20 espie 379: writeb64file(sigfile, sigcomment, &sig, sizeof(sig), O_TRUNC, 0666);
1.16 tedu 380: if (embedded)
381: appendall(sigfile, msg, msglen);
1.1 tedu 382:
383: free(msg);
384: }
1.22 tedu 385:
386: static void
387: inspect(const char *seckeyfile, const char *pubkeyfile, const char *sigfile)
388: {
389: struct sig sig;
390: struct enckey enckey;
391: struct pubkey pubkey;
392: char fp[(FPLEN + 2) / 3 * 4 + 1];
393:
394: if (seckeyfile) {
395: readb64file(seckeyfile, &enckey, sizeof(enckey), NULL);
396: b64_ntop(enckey.fingerprint, FPLEN, fp, sizeof(fp));
397: printf("sec fp: %s\n", fp);
398: }
399: if (pubkeyfile) {
400: readb64file(pubkeyfile, &pubkey, sizeof(pubkey), NULL);
401: b64_ntop(pubkey.fingerprint, FPLEN, fp, sizeof(fp));
402: printf("pub fp: %s\n", fp);
403: }
404: if (sigfile) {
405: readb64file(sigfile, &sig, sizeof(sig), NULL);
406: b64_ntop(sig.fingerprint, FPLEN, fp, sizeof(fp));
407: printf("sig fp: %s\n", fp);
408: }
409: }
1.14 tedu 410: #endif
1.1 tedu 411:
412: static void
1.13 tedu 413: verifymsg(uint8_t *pubkey, uint8_t *msg, unsigned long long msglen,
1.42 tedu 414: uint8_t *sig, int quiet)
1.13 tedu 415: {
416: uint8_t *sigbuf, *dummybuf;
417: unsigned long long siglen, dummylen;
418:
419: siglen = SIGBYTES + msglen;
420: sigbuf = xmalloc(siglen);
421: dummybuf = xmalloc(siglen);
422: memcpy(sigbuf, sig, SIGBYTES);
423: memcpy(sigbuf + SIGBYTES, msg, msglen);
424: if (crypto_sign_ed25519_open(dummybuf, &dummylen, sigbuf, siglen,
425: pubkey) == -1)
426: errx(1, "signature verification failed");
1.42 tedu 427: if (!quiet)
428: printf("Signature Verified\n");
1.13 tedu 429: free(sigbuf);
430: free(dummybuf);
431: }
432:
433:
434: static void
1.16 tedu 435: verify(const char *pubkeyfile, const char *msgfile, const char *sigfile,
1.42 tedu 436: int embedded, int quiet)
1.1 tedu 437: {
438: struct sig sig;
439: struct pubkey pubkey;
1.16 tedu 440: unsigned long long msglen, siglen = 0;
1.1 tedu 441: uint8_t *msg;
1.16 tedu 442: int fd;
443:
444: msg = readmsg(embedded ? sigfile : msgfile, &msglen);
1.1 tedu 445:
1.18 tedu 446: readb64file(pubkeyfile, &pubkey, sizeof(pubkey), NULL);
1.16 tedu 447: if (embedded) {
1.18 tedu 448: siglen = parseb64file(sigfile, msg, &sig, sizeof(sig), NULL);
1.16 tedu 449: msg += siglen;
450: msglen -= siglen;
451: } else {
1.18 tedu 452: readb64file(sigfile, &sig, sizeof(sig), NULL);
1.16 tedu 453: }
1.13 tedu 454:
1.22 tedu 455: if (memcmp(pubkey.fingerprint, sig.fingerprint, FPLEN)) {
456: #ifndef VERIFYONLY
457: inspect(NULL, pubkeyfile, sigfile);
458: #endif
1.13 tedu 459: errx(1, "verification failed: checked against wrong key");
1.22 tedu 460: }
1.1 tedu 461:
1.42 tedu 462: verifymsg(pubkey.pubkey, msg, msglen, sig.sig, quiet);
1.16 tedu 463: if (embedded) {
1.30 tedu 464: fd = xopen(msgfile, O_CREAT|O_TRUNC|O_NOFOLLOW|O_WRONLY, 0666);
1.16 tedu 465: writeall(fd, msg, msglen, msgfile);
466: close(fd);
467: }
1.1 tedu 468:
1.16 tedu 469: free(msg - siglen);
1.1 tedu 470: }
471:
1.42 tedu 472: #ifndef VERIFYONLY
473: struct checksum {
474: char file[1024];
475: char hash[1024];
476: char algo[256];
477: };
478:
479: static void
1.45 tedu 480: verifychecksums(char *msg, int argc, char **argv, int quiet)
1.42 tedu 481: {
482: char buf[1024];
1.45 tedu 483: char *line, *endline;
1.42 tedu 484: struct checksum *checksums = NULL, *c = NULL;
485: int nchecksums = 0;
1.43 tedu 486: int i, j, uselist, count, hasfailed;
1.42 tedu 487: int *failures;
488:
1.45 tedu 489: line = msg;
1.42 tedu 490: while (line && *line) {
491: if (!(checksums = realloc(checksums,
492: sizeof(*c) * (nchecksums + 1))))
493: err(1, "realloc");
494: c = &checksums[nchecksums++];
495: if ((endline = strchr(line, '\n')))
496: *endline++ = 0;
497: if (sscanf(line, "%255s %1023s = %1023s",
498: c->algo, buf, c->hash) != 3 ||
499: buf[0] != '(' || buf[strlen(buf) - 1] != ')')
500: errx(1, "unable to parse checksum line %s", line);
501: buf[strlen(buf) - 1] = 0;
502: strlcpy(c->file, buf + 1, sizeof(c->file));
503: line = endline;
504: }
505:
506: if (argc) {
507: uselist = 0;
508: count = argc;
509: } else {
510: uselist = 1;
511: count = nchecksums;
512: }
1.43 tedu 513: if (!(failures = calloc(count, sizeof(int))))
514: err(1, "calloc");
1.42 tedu 515: for (i = 0; i < count; i++) {
516: if (uselist) {
517: c = &checksums[i];
518: } else {
519: for (j = 0; j < nchecksums; j++) {
520: c = &checksums[j];
521: if (strcmp(c->file, argv[i]) == 0)
522: break;
523: }
524: if (j == nchecksums) {
525: failures[i] = 1;
526: continue;
527: }
528: }
529:
530: if (strcmp(c->algo, "SHA256") == 0) {
531: if (!SHA256File(c->file, buf)) {
532: failures[i] = 1;
533: continue;
534: }
535: } else if (strcmp(c->algo, "SHA512") == 0) {
536: if (!SHA512File(c->file, buf)) {
537: failures[i] = 1;
538: continue;
539: }
540: } else {
541: errx(1, "can't handle algorithm %s", c->algo);
542: }
543: if (strcmp(c->hash, buf) != 0) {
544: failures[i] = 1;
545: continue;
546: }
547: if (!quiet)
548: printf("%s: OK\n", c->file);
549: }
1.43 tedu 550: hasfailed = 0;
1.42 tedu 551: for (i = 0; i < count; i++) {
552: if (failures[i]) {
553: fprintf(stderr, "%s: FAIL\n",
554: uselist ? checksums[i].file : argv[i]);
1.43 tedu 555: hasfailed = 1;
1.42 tedu 556: }
557: }
1.43 tedu 558: if (hasfailed)
1.42 tedu 559: exit(1);
560: free(checksums);
1.43 tedu 561: free(failures);
1.42 tedu 562: }
563:
564: static void
565: check(const char *pubkeyfile, const char *sigfile, int quiet, int argc,
566: char **argv)
567: {
568: struct sig sig;
569: struct pubkey pubkey;
570: unsigned long long msglen, siglen;
571: uint8_t *msg;
572:
573: msg = readmsg(sigfile, &msglen);
574:
575: readb64file(pubkeyfile, &pubkey, sizeof(pubkey), NULL);
576: siglen = parseb64file(sigfile, msg, &sig, sizeof(sig), NULL);
577: msg += siglen;
578: msglen -= siglen;
579:
580: if (memcmp(pubkey.fingerprint, sig.fingerprint, FPLEN)) {
581: #ifndef VERIFYONLY
582: inspect(NULL, pubkeyfile, sigfile);
583: #endif
584: errx(1, "verification failed: checked against wrong key");
585: }
586:
587: verifymsg(pubkey.pubkey, msg, msglen, sig.sig, quiet);
1.45 tedu 588: verifychecksums((char *)msg, argc, argv, quiet);
1.42 tedu 589:
590: free(msg - siglen);
591: }
592: #endif
593:
1.1 tedu 594: int
595: main(int argc, char **argv)
596: {
1.16 tedu 597: const char *pubkeyfile = NULL, *seckeyfile = NULL, *msgfile = NULL,
1.1 tedu 598: *sigfile = NULL;
599: char sigfilebuf[1024];
1.27 tedu 600: const char *comment = "signify";
1.1 tedu 601: int ch, rounds;
1.16 tedu 602: int embedded = 0;
1.42 tedu 603: int quiet = 0;
1.6 tedu 604: enum {
605: NONE,
1.42 tedu 606: CHECK,
1.6 tedu 607: GENERATE,
1.22 tedu 608: INSPECT,
1.6 tedu 609: SIGN,
610: VERIFY
611: } verb = NONE;
612:
1.1 tedu 613:
614: rounds = 42;
615:
1.42 tedu 616: while ((ch = getopt(argc, argv, "CGISVc:em:np:qs:x:")) != -1) {
1.1 tedu 617: switch (ch) {
1.14 tedu 618: #ifndef VERIFYONLY
1.42 tedu 619: case 'C':
620: if (verb)
621: usage(NULL);
622: verb = CHECK;
623: break;
1.6 tedu 624: case 'G':
625: if (verb)
1.31 tedu 626: usage(NULL);
1.6 tedu 627: verb = GENERATE;
628: break;
1.22 tedu 629: case 'I':
630: if (verb)
1.31 tedu 631: usage(NULL);
1.22 tedu 632: verb = INSPECT;
633: break;
1.6 tedu 634: case 'S':
635: if (verb)
1.31 tedu 636: usage(NULL);
1.6 tedu 637: verb = SIGN;
638: break;
1.14 tedu 639: #endif
1.6 tedu 640: case 'V':
641: if (verb)
1.31 tedu 642: usage(NULL);
1.6 tedu 643: verb = VERIFY;
644: break;
1.27 tedu 645: case 'c':
646: comment = optarg;
647: break;
1.16 tedu 648: case 'e':
649: embedded = 1;
650: break;
1.31 tedu 651: case 'm':
652: msgfile = optarg;
653: break;
1.6 tedu 654: case 'n':
1.1 tedu 655: rounds = 0;
656: break;
1.6 tedu 657: case 'p':
1.1 tedu 658: pubkeyfile = optarg;
659: break;
1.42 tedu 660: case 'q':
661: quiet = 1;
662: break;
1.6 tedu 663: case 's':
1.1 tedu 664: seckeyfile = optarg;
665: break;
1.31 tedu 666: case 'x':
667: sigfile = optarg;
668: break;
1.1 tedu 669: default:
1.31 tedu 670: usage(NULL);
1.1 tedu 671: break;
672: }
673: }
1.2 tedu 674: argc -= optind;
1.9 espie 675: argv += optind;
676:
1.42 tedu 677: #ifndef VERIFYONLY
678: if (verb == CHECK) {
679: if (!pubkeyfile || !sigfile)
680: usage("need pubkey and sigfile");
681: check(pubkeyfile, sigfile, quiet, argc, argv);
682: return 0;
683: }
684: #endif
685:
686: quiet = 1; /* retain quiet default for 5.5 release */
687:
1.31 tedu 688: if (argc != 0)
689: usage(NULL);
690:
1.36 tedu 691: if (!sigfile && msgfile) {
692: if (strcmp(msgfile, "-") == 0)
693: errx(1, "must specify sigfile with - message");
694: if (snprintf(sigfilebuf, sizeof(sigfilebuf), "%s.sig",
695: msgfile) >= sizeof(sigfilebuf))
696: errx(1, "path too long");
697: sigfile = sigfilebuf;
698: }
1.1 tedu 699:
1.36 tedu 700: switch (verb) {
1.14 tedu 701: #ifndef VERIFYONLY
1.36 tedu 702: case GENERATE:
1.31 tedu 703: if (!pubkeyfile || !seckeyfile)
704: usage("need pubkey and seckey");
1.27 tedu 705: generate(pubkeyfile, seckeyfile, rounds, comment);
1.36 tedu 706: break;
707: case INSPECT:
1.22 tedu 708: inspect(seckeyfile, pubkeyfile, sigfile);
1.36 tedu 709: break;
710: case SIGN:
711: if (!msgfile || !seckeyfile)
712: usage("need message and seckey");
713: sign(seckeyfile, msgfile, sigfile, embedded);
714: break;
1.14 tedu 715: #endif
1.36 tedu 716: case VERIFY:
717: if (!msgfile || !pubkeyfile)
718: usage("need message and pubkey");
1.42 tedu 719: verify(pubkeyfile, msgfile, sigfile, embedded, quiet);
1.36 tedu 720: break;
721: default:
722: usage(NULL);
723: break;
1.1 tedu 724: }
1.9 espie 725:
1.1 tedu 726: return 0;
727: }