version 1.41, 2014/01/22 21:11:03 |
version 1.42, 2014/03/04 16:44:07 |
|
|
fprintf(stderr, "%s\n", error); |
fprintf(stderr, "%s\n", error); |
fprintf(stderr, "usage:" |
fprintf(stderr, "usage:" |
#ifndef VERIFYONLY |
#ifndef VERIFYONLY |
|
"\t%1$s -C [-q] -p pubkey -x sigfile [files...]\n" |
"\t%1$s -G [-n] [-c comment] -p pubkey -s seckey\n" |
"\t%1$s -G [-n] [-c comment] -p pubkey -s seckey\n" |
"\t%1$s -I [-p pubkey] [-s seckey] [-x sigfile]\n" |
"\t%1$s -I [-p pubkey] [-s seckey] [-x sigfile]\n" |
"\t%1$s -S [-e] [-x sigfile] -s seckey -m message\n" |
"\t%1$s -S [-e] [-x sigfile] -s seckey -m message\n" |
#endif |
#endif |
"\t%1$s -V [-e] [-x sigfile] -p pubkey -m message\n", |
"\t%1$s -V [-eq] [-x sigfile] -p pubkey -m message\n", |
__progname); |
__progname); |
exit(1); |
exit(1); |
} |
} |
|
|
|
|
static void |
static void |
verifymsg(uint8_t *pubkey, uint8_t *msg, unsigned long long msglen, |
verifymsg(uint8_t *pubkey, uint8_t *msg, unsigned long long msglen, |
uint8_t *sig) |
uint8_t *sig, int quiet) |
{ |
{ |
uint8_t *sigbuf, *dummybuf; |
uint8_t *sigbuf, *dummybuf; |
unsigned long long siglen, dummylen; |
unsigned long long siglen, dummylen; |
|
|
if (crypto_sign_ed25519_open(dummybuf, &dummylen, sigbuf, siglen, |
if (crypto_sign_ed25519_open(dummybuf, &dummylen, sigbuf, siglen, |
pubkey) == -1) |
pubkey) == -1) |
errx(1, "signature verification failed"); |
errx(1, "signature verification failed"); |
|
if (!quiet) |
|
printf("Signature Verified\n"); |
free(sigbuf); |
free(sigbuf); |
free(dummybuf); |
free(dummybuf); |
} |
} |
|
|
|
|
static void |
static void |
verify(const char *pubkeyfile, const char *msgfile, const char *sigfile, |
verify(const char *pubkeyfile, const char *msgfile, const char *sigfile, |
int embedded) |
int embedded, int quiet) |
{ |
{ |
struct sig sig; |
struct sig sig; |
struct pubkey pubkey; |
struct pubkey pubkey; |
|
|
errx(1, "verification failed: checked against wrong key"); |
errx(1, "verification failed: checked against wrong key"); |
} |
} |
|
|
verifymsg(pubkey.pubkey, msg, msglen, sig.sig); |
verifymsg(pubkey.pubkey, msg, msglen, sig.sig, quiet); |
if (embedded) { |
if (embedded) { |
fd = xopen(msgfile, O_CREAT|O_TRUNC|O_NOFOLLOW|O_WRONLY, 0666); |
fd = xopen(msgfile, O_CREAT|O_TRUNC|O_NOFOLLOW|O_WRONLY, 0666); |
writeall(fd, msg, msglen, msgfile); |
writeall(fd, msg, msglen, msgfile); |
|
|
free(msg - siglen); |
free(msg - siglen); |
} |
} |
|
|
|
#ifndef VERIFYONLY |
|
struct checksum { |
|
char file[1024]; |
|
char hash[1024]; |
|
char algo[256]; |
|
}; |
|
|
|
static void |
|
verifychecksums(const char *msg, unsigned long long msglen, int argc, |
|
char **argv, int quiet) |
|
{ |
|
char buf[1024]; |
|
char *input, *line, *endline; |
|
struct checksum *checksums = NULL, *c = NULL; |
|
int nchecksums = 0; |
|
int i, j, uselist, count, failcount; |
|
int *failures; |
|
|
|
if (!(input = strndup(msg, msglen))) |
|
err(1, "strndup"); |
|
line = input; |
|
while (line && *line) { |
|
if (!(checksums = realloc(checksums, |
|
sizeof(*c) * (nchecksums + 1)))) |
|
err(1, "realloc"); |
|
c = &checksums[nchecksums++]; |
|
if ((endline = strchr(line, '\n'))) |
|
*endline++ = 0; |
|
if (sscanf(line, "%255s %1023s = %1023s", |
|
c->algo, buf, c->hash) != 3 || |
|
buf[0] != '(' || buf[strlen(buf) - 1] != ')') |
|
errx(1, "unable to parse checksum line %s", line); |
|
buf[strlen(buf) - 1] = 0; |
|
strlcpy(c->file, buf + 1, sizeof(c->file)); |
|
line = endline; |
|
} |
|
free(input); |
|
|
|
if (argc) { |
|
uselist = 0; |
|
count = argc; |
|
} else { |
|
uselist = 1; |
|
count = nchecksums; |
|
} |
|
failures = calloc(count, sizeof(int)); |
|
for (i = 0; i < count; i++) { |
|
if (uselist) { |
|
c = &checksums[i]; |
|
} else { |
|
for (j = 0; j < nchecksums; j++) { |
|
c = &checksums[j]; |
|
if (strcmp(c->file, argv[i]) == 0) |
|
break; |
|
} |
|
if (j == nchecksums) { |
|
failures[i] = 1; |
|
continue; |
|
} |
|
} |
|
|
|
if (strcmp(c->algo, "SHA256") == 0) { |
|
if (!SHA256File(c->file, buf)) { |
|
failures[i] = 1; |
|
continue; |
|
} |
|
} else if (strcmp(c->algo, "SHA512") == 0) { |
|
if (!SHA512File(c->file, buf)) { |
|
failures[i] = 1; |
|
continue; |
|
} |
|
} else { |
|
errx(1, "can't handle algorithm %s", c->algo); |
|
} |
|
if (strcmp(c->hash, buf) != 0) { |
|
failures[i] = 1; |
|
continue; |
|
} |
|
if (!quiet) |
|
printf("%s: OK\n", c->file); |
|
} |
|
failcount = 0; |
|
for (i = 0; i < count; i++) { |
|
if (failures[i]) { |
|
fprintf(stderr, "%s: FAIL\n", |
|
uselist ? checksums[i].file : argv[i]); |
|
failcount++; |
|
} |
|
} |
|
if (failcount) |
|
exit(1); |
|
free(checksums); |
|
} |
|
|
|
static void |
|
check(const char *pubkeyfile, const char *sigfile, int quiet, int argc, |
|
char **argv) |
|
{ |
|
struct sig sig; |
|
struct pubkey pubkey; |
|
unsigned long long msglen, siglen; |
|
uint8_t *msg; |
|
|
|
msg = readmsg(sigfile, &msglen); |
|
|
|
readb64file(pubkeyfile, &pubkey, sizeof(pubkey), NULL); |
|
siglen = parseb64file(sigfile, msg, &sig, sizeof(sig), NULL); |
|
msg += siglen; |
|
msglen -= siglen; |
|
|
|
if (memcmp(pubkey.fingerprint, sig.fingerprint, FPLEN)) { |
|
#ifndef VERIFYONLY |
|
inspect(NULL, pubkeyfile, sigfile); |
|
#endif |
|
errx(1, "verification failed: checked against wrong key"); |
|
} |
|
|
|
verifymsg(pubkey.pubkey, msg, msglen, sig.sig, quiet); |
|
verifychecksums(msg, msglen, argc, argv, quiet); |
|
|
|
free(msg - siglen); |
|
} |
|
#endif |
|
|
int |
int |
main(int argc, char **argv) |
main(int argc, char **argv) |
{ |
{ |
|
|
const char *comment = "signify"; |
const char *comment = "signify"; |
int ch, rounds; |
int ch, rounds; |
int embedded = 0; |
int embedded = 0; |
|
int quiet = 0; |
enum { |
enum { |
NONE, |
NONE, |
|
CHECK, |
GENERATE, |
GENERATE, |
INSPECT, |
INSPECT, |
SIGN, |
SIGN, |
|
|
|
|
rounds = 42; |
rounds = 42; |
|
|
while ((ch = getopt(argc, argv, "GISVc:em:np:s:x:")) != -1) { |
while ((ch = getopt(argc, argv, "CGISVc:em:np:qs:x:")) != -1) { |
switch (ch) { |
switch (ch) { |
#ifndef VERIFYONLY |
#ifndef VERIFYONLY |
|
case 'C': |
|
if (verb) |
|
usage(NULL); |
|
verb = CHECK; |
|
break; |
case 'G': |
case 'G': |
if (verb) |
if (verb) |
usage(NULL); |
usage(NULL); |
|
|
case 'p': |
case 'p': |
pubkeyfile = optarg; |
pubkeyfile = optarg; |
break; |
break; |
|
case 'q': |
|
quiet = 1; |
|
break; |
case 's': |
case 's': |
seckeyfile = optarg; |
seckeyfile = optarg; |
break; |
break; |
|
|
argc -= optind; |
argc -= optind; |
argv += optind; |
argv += optind; |
|
|
|
#ifndef VERIFYONLY |
|
if (verb == CHECK) { |
|
if (!pubkeyfile || !sigfile) |
|
usage("need pubkey and sigfile"); |
|
check(pubkeyfile, sigfile, quiet, argc, argv); |
|
return 0; |
|
} |
|
#endif |
|
|
|
quiet = 1; /* retain quiet default for 5.5 release */ |
|
|
if (argc != 0) |
if (argc != 0) |
usage(NULL); |
usage(NULL); |
|
|
|
|
case VERIFY: |
case VERIFY: |
if (!msgfile || !pubkeyfile) |
if (!msgfile || !pubkeyfile) |
usage("need message and pubkey"); |
usage("need message and pubkey"); |
verify(pubkeyfile, msgfile, sigfile, embedded); |
verify(pubkeyfile, msgfile, sigfile, embedded, quiet); |
break; |
break; |
default: |
default: |
usage(NULL); |
usage(NULL); |