10/14
This commit is contained in:
1 parent
ee4bcc3b77
commit
ae54f74070
53 files changed
+8916
-1424
No files matched your search
+212
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* gsign: make signify-compatible Ed25519 keys and signatures
|
||||
* (REPO_DESIGN.txt section 2). A build/maintainer tool, like
|
||||
* gsha256sum.
|
||||
*
|
||||
* gsign -G -p KEY.pub -s KEY.sec [-c COMMENT]
|
||||
* gsign -S -s KEY.sec -m FILE [-x SIGFILE]
|
||||
* gsign -V -p KEY.pub -m FILE [-x SIGFILE]
|
||||
*
|
||||
* SIGFILE defaults to FILE.sig. Exit 0 on success, 1 otherwise.
|
||||
*/
|
||||
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "sign.h"
|
||||
|
||||
#define USAGE \
|
||||
"usage: gsign [-hv]\n" \
|
||||
" gsign -G -p KEY.pub -s KEY.sec [-c COMMENT]\n" \
|
||||
" gsign -S -s KEY.sec -m FILE [-x SIGFILE]\n" \
|
||||
" gsign -V -p KEY.pub -m FILE [-x SIGFILE]\n"
|
||||
|
||||
static const struct option longopts[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'v' },
|
||||
{ "generate", no_argument, NULL, 'G' },
|
||||
{ "sign", no_argument, NULL, 'S' },
|
||||
{ "verify", no_argument, NULL, 'V' },
|
||||
{ "pubkey", required_argument, NULL, 'p' },
|
||||
{ "seckey", required_argument, NULL, 's' },
|
||||
{ "message", required_argument, NULL, 'm' },
|
||||
{ "sig", required_argument, NULL, 'x' },
|
||||
{ "comment", required_argument, NULL, 'c' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, USAGE);
|
||||
}
|
||||
|
||||
static void
|
||||
help(void)
|
||||
{
|
||||
printf("gsign: Make and check signify-compatible signatures\n");
|
||||
printf(USAGE);
|
||||
printf("\n");
|
||||
printf("%-25s %s\n", "{-h --help}", "Show this message");
|
||||
printf("%-25s %s\n", "{-v --version}", "Show the current version");
|
||||
printf("%-25s %s\n", "{-G --generate}", "Generate a new key pair");
|
||||
printf("%-25s %s\n", "{-S --sign}", "Sign a file");
|
||||
printf("%-25s %s\n", "{-V --verify}", "Verify a file's signature");
|
||||
printf("%-25s %s\n", "{-p --pubkey} KEY.pub", "Public key file");
|
||||
printf("%-25s %s\n", "{-s --seckey} KEY.sec", "Secret key file");
|
||||
printf("%-25s %s\n", "{-m --message} FILE", "File to sign or verify");
|
||||
printf("%-25s %s\n", "{-x --sig} SIGFILE", "Signature file (default: FILE.sig)");
|
||||
printf("%-25s %s\n", "{-c --comment} COMMENT", "Comment for a new key pair (default: gsign)");
|
||||
printf("\n");
|
||||
printf("This program is free software.\n");
|
||||
printf("See the GNU GPL version 3 for details.\n");
|
||||
}
|
||||
|
||||
/* "<what> <path> <problem>." about one file. */
|
||||
static int
|
||||
fail(const char *what, const char *path, int st)
|
||||
{
|
||||
const char *problem;
|
||||
switch (st) {
|
||||
case GL_SIGN_ERR_FORMAT: problem = "is malformed"; break;
|
||||
case GL_SIGN_ERR_ENCRYPTED: problem = "is encrypted: sign with signify"; break;
|
||||
case GL_SIGN_ERR_TOOBIG: problem = "is too large"; break;
|
||||
case GL_SIGN_ERR_EXISTS: problem = "already exists"; break;
|
||||
case GL_SIGN_ERR_WRITE: problem = "cannot be written"; break;
|
||||
default: problem = "cannot be read"; break;
|
||||
}
|
||||
lg_printf(LG_ERR, "%s %s %s.", what, path, problem);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char mode = 0;
|
||||
const char *pub = NULL, *sec = NULL, *msg = NULL, *sig = NULL;
|
||||
const char *comment = "gsign";
|
||||
int c;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "hvGSVp:s:m:x:c:", longopts, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
help();
|
||||
return 0;
|
||||
case 'v':
|
||||
printf("v4.0.0\n");
|
||||
return 0;
|
||||
case 'G': case 'S': case 'V':
|
||||
if (mode && mode != c) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
mode = (char)c;
|
||||
break;
|
||||
case 'p': pub = optarg; break;
|
||||
case 's': sec = optarg; break;
|
||||
case 'm': msg = optarg; break;
|
||||
case 'x': sig = optarg; break;
|
||||
case 'c': comment = optarg; break;
|
||||
default:
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (optind != argc) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
char sigbuf[PATH_MAX];
|
||||
if (msg && !sig) {
|
||||
if ((size_t)snprintf(sigbuf, sizeof sigbuf, "%s.sig", msg) >= sizeof sigbuf) {
|
||||
lg_printf(LG_ERR, "Path too long: %s", msg);
|
||||
return 1;
|
||||
}
|
||||
sig = sigbuf;
|
||||
}
|
||||
|
||||
int st;
|
||||
switch (mode) {
|
||||
case 'G':
|
||||
if (!pub || !sec || msg) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
/* The library refuses these too (O_EXCL); this names which. */
|
||||
struct stat sb;
|
||||
if (lstat(sec, &sb) == 0)
|
||||
return fail("Secret key", sec, GL_SIGN_ERR_EXISTS);
|
||||
if (lstat(pub, &sb) == 0)
|
||||
return fail("Public key", pub, GL_SIGN_ERR_EXISTS);
|
||||
st = gl_sign_generate(pub, sec, comment);
|
||||
if (st == GL_SIGN_ERR_FORMAT) {
|
||||
lg_printf(LG_ERR, "Comment must be one line, at most %d characters.",
|
||||
GL_SIGN_MAX_COMMENT - 11);
|
||||
return 1;
|
||||
}
|
||||
if (st == GL_SIGN_ERR_RANDOM) {
|
||||
lg_printf(LG_ERR, "Cannot get random bytes for a new key.");
|
||||
return 1;
|
||||
}
|
||||
if (st != GL_SIGN_OK) {
|
||||
lg_printf(LG_ERR, "Cannot write %s and %s.", pub, sec);
|
||||
return 1;
|
||||
}
|
||||
lg_printf(LG_SUCCESS, "Wrote %s and %s.", pub, sec);
|
||||
return 0;
|
||||
|
||||
case 'S':
|
||||
if (!sec || !msg || pub) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
if ((st = gl_sign_check_seckey(sec)) != GL_SIGN_OK)
|
||||
return fail("Secret key", sec, st);
|
||||
st = gl_sign_file(sec, msg, sig);
|
||||
if (st == GL_SIGN_ERR_WRITE)
|
||||
return fail("Signature", sig, st);
|
||||
if (st != GL_SIGN_OK)
|
||||
return fail("File", msg, st);
|
||||
lg_printf(LG_SUCCESS, "Signed %s: %s.", msg, sig);
|
||||
return 0;
|
||||
|
||||
case 'V': {
|
||||
if (!pub || !msg || sec) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
gl_sign_pubkey_t pk;
|
||||
gl_sign_sig_t sg;
|
||||
if ((st = gl_sign_read_pubkey(pub, &pk)) != GL_SIGN_OK)
|
||||
return fail("Public key", pub, st);
|
||||
if ((st = gl_sign_read_sig(sig, &sg)) != GL_SIGN_OK)
|
||||
return fail("Signature", sig, st);
|
||||
st = gl_sign_verify_file(pub, msg, sig);
|
||||
switch (st) {
|
||||
case GL_SIGN_OK:
|
||||
lg_printf(LG_SUCCESS, "Signature verified: %s.", msg);
|
||||
return 0;
|
||||
case GL_SIGN_ERR_KEYNUM:
|
||||
lg_printf(LG_ERR, "%s was signed by a different key than %s.", msg, pub);
|
||||
return 1;
|
||||
case GL_SIGN_ERR_BAD:
|
||||
lg_printf(LG_ERR, "Signature does not verify: %s.", msg);
|
||||
return 1;
|
||||
default:
|
||||
return fail("File", msg, st);
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user