/*
This file is part of msr.
msr is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
msr is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with Foobar. If not, see .
*/
#include
#include
#include "io.h"
enum opt_key {O_PUBKEY_STR, O_SECKEY_STR, O_PUBKEY_COMMENT, O_SECKEY_COMMENT,
O_PUBKEY_FLE, O_SECKEY_FLE, O_SIG_FLE, O_SIGN_INLINE, O_PASS_FLE};
enum action {A_NULL, A_SIGN_D, A_SIGN_T, A_VERIFY_D, A_VERIFY_T, A_GEN};
typedef struct option_state_s {
char *pkstr, *pkfn, *pkc;
char *skstr, *skfn, *skc, *skpf;
char *utc, *tc;
char *fn, *sfn;
char quiet;
enum action action;
} * OptionState;
static struct argp_option options[] = {
// Actions
{"generate", 'G', "FILE", OPTION_ARG_OPTIONAL, "Generate a new key pair, storing in `FILE.{pub,key}' (FILE defaults to msr)", 1},
{"sign-detached", 'S', "FILE", 0, "Sign FILE by generating a separate signature", 1},
{"sign-text", 'T', "FILE", 0, "Sign FILE by appending a signature", 1},
{"verify-detached", 'V', "FILE", 0, "Verify the detached signature on FILE", 1},
{"verify-text", 'X', "FILE", 0, "Verify the inline text signature in FILE", 1},
// Odd-one-out
{"signature-file", 'f', "FILE", 0, "Use FILE as the signature file for detached signing and verification purposes", 2},
// Keys
{"pubkey-file", 'p', "FILE", 0, "Use the public key in FILE", 3},
{"pubkey-string", O_PUBKEY_STR, "STR", 0, "Use the public key encoded in STR", 3},
{"seckey-file", 's', "FILE", 0, "Use the secret key in FILE", 3},
{"seckey-string", O_SECKEY_STR, "STR", 0, "Use the secret key encoded in STR", 3},
{"password-file", O_PASS_FLE, "FILE", 0, "Load secret key passphrase from FILE", 4},
// Comments
{"comment-untrusted", 'u', "STR", 0, "Use STR for the default untrusted comment when making a detached signature", 5},
{"comment-trusted", 't', "STR", 0, "Use STR for the trusted comment when making a detached signature", 5},
{"comment-pubkey", O_PUBKEY_COMMENT, "STR", 0, "Use STR for the default untrusted comment in the generated public key file", 5},
{"comment-seckey", O_SECKEY_COMMENT, "STR", 0, "Use STR for the default untrusted comment in the generated secret key file", 5},
// Miscellaneous
{"quiet", 'q', 0, 0, "Produce no output",6},
{0,0,0,0,0,0}
};
char *action_to_string(enum action a) {
switch (a) {
case A_GEN: return "generation of key pair";
case A_SIGN_D: return "signing detached";
case A_SIGN_T: return "signing inline text";
case A_VERIFY_D: return "verification of detached signature";
case A_VERIFY_T: return "verification of inline text signature";
default: return "null action";
}
}
// --- Some macros to make argument checking sane ---
#define FAIL(str) (argp_error(state, (str)))
#define ACT_CHECK { if (s->action!=A_NULL) FAIL("Cannot execute conflicting actions."); }
#define BADARG(arg) (argp_error(state, "%s stipulated for %s",arg,action_to_string(s->action)))
#define ARGCHECK(a,b,c,d,e,f,g,h,i,j) { \
if(a && s->pkc) BADARG("public key comment"); \
if(b && s->pkfn) BADARG("public key file"); \
if(c && s->pkstr) BADARG("public key string"); \
if(d && s->skc) BADARG("secret key comment"); \
if(e && s->skfn) BADARG("secret key file"); \
if(f && s->skstr) BADARG("secret key string"); \
if(g && s->tc) BADARG("trusted comment"); \
if(h && s->utc) BADARG("untrusted comment"); \
if(i && s->skpf) BADARG("secret key password file"); \
if(j && s->sfn) BADARG("signature file"); }
error_t parse_opt(int key, char *arg, struct argp_state *state) {
OptionState s = state->input;
switch (key) {
case ARGP_KEY_FINI: {
switch (s->action) {
case A_NULL: argp_state_help(state,state->out_stream,ARGP_HELP_SEE);
case A_GEN: { ARGCHECK(0,1,1,0,1,1,1,1,1,1); break; };
case A_VERIFY_D:
case A_SIGN_D: { ARGCHECK(1,0,0,1,0,0,0,0,0,0); break; }
case A_VERIFY_T:
case A_SIGN_T: { ARGCHECK(1,0,0,1,0,0,1,1,0,1); break; }
}
break;
}
case ARGP_KEY_INIT: {
s->action = A_NULL;
s->pkc = s->pkfn = s->pkstr = NULL;
s->skc = s->skfn = s->skstr = NULL;
s->tc = s->utc = NULL;
s->fn = s->sfn = NULL;
s->skpf = NULL;
s->quiet = 0;
break;
}
case 'G': {ACT_CHECK; s->action = A_GEN; s->fn = arg; break; }
case 'S': {ACT_CHECK; s->action = A_SIGN_D; s->fn = arg; break; }
case 'T': {ACT_CHECK; s->action = A_SIGN_T; s->fn = arg; break; }
case 'V': {ACT_CHECK; s->action = A_VERIFY_D; s->fn = arg; break; }
case 'X': {ACT_CHECK; s->action = A_VERIFY_T; s->fn = arg; break; }
case 'p': {
if (s->pkfn) FAIL("Already set public key filename.");
if (s->pkstr) FAIL("Already set public key string.");
s->pkfn = arg;
break;
}
case O_PUBKEY_STR: {
if (s->pkfn) FAIL("Already set public key filename.");
if (s->pkstr) FAIL("Already set public key string.");
s->pkstr = arg;
break;
}
case 's': {
if (s->skfn) FAIL("Already set private key filename.");
if (s->skstr) FAIL("Already set private key string.");
s->skfn = arg;
break;
}
case O_SECKEY_STR: {
if (s->skfn) FAIL("Already set private key filename.");
if (s->skstr) FAIL("Already set private key string.");
s->skstr = arg;
break;
}
case O_PASS_FLE: {
if (s->skpf) FAIL("Already set secret key password file.");
s->skpf = arg;
}
case 't': {
if (s->tc) FAIL("Already set trusted comment string.");
s->tc = arg;
break;
}
case 'u': {
if (s->utc) FAIL("Already set untrusted comment string.");
s->utc = arg;
break;
}
case O_PUBKEY_COMMENT: {
if (s->pkc) FAIL("Already set public key comment.");
s->pkc = arg;
break;
}
case O_SECKEY_COMMENT: {
if (s->skc) FAIL("Already set secret key comment.");
s->skc = arg;
break;
}
case 'f': {
if (s->sfn) FAIL("Already set signature file name.");
s->sfn = arg;
break;
}
case 'q': {s->quiet = 1; break; }
default: return ARGP_ERR_UNKNOWN;
}
return 0;
}
const char *argp_program_version = "msr 0.0.2";
const char *argp_program_bug_address = "http://github.com/tslilc/msr or ";
static char doc[] = "msr -- small public key verification tool.\v\
Copyright (C) 2015 Tslil Clingman\nThis is free software and is \
licensed under the terms of the GNU GPL version three or later. This \
program comes with ABSOLUTELY NO WARRANTY; consult the LICENSE file \
for details.";
static struct argp argp = {options, parse_opt, NULL, doc, NULL, NULL, NULL};
int main(int argc, char ** argv) {
struct option_state_s s;
argp_parse(&argp,argc,argv, ARGP_NO_ARGS, 0, &s);
if (s.quiet) verbose = 0;
if (sodium_init() == -1) {
puts("Unable to initialise libsodium");
return 1;
}
Error e;
SecretKey sk;
PublicKey pk;
switch (s.action) {
case A_GEN: {
e = generate_to_file(s.fn,s.skpf,s.pkc,s.skc);
if (e != SUCCESS) exit(1);
break;
}
case A_SIGN_D: {
if (s.skstr) e = read_seckey_string(s.skstr,&sk);
else e = read_seckey_file(s.skstr,&sk);
if (e != SUCCESS) exit(1);
e = sign_detached(s.fn,s.sfn,s.utc,s.tc,s.skpf,sk);
if ( e != SUCCESS ) exit(1);
break;
}
case A_SIGN_T: {
if (s.skstr) e = read_seckey_string(s.skstr,&sk);
else e = read_seckey_file(s.skstr,&sk);
if (e != SUCCESS) exit(1);
e = sign_attached(s.fn,s.skpf,sk);
if ( e != SUCCESS ) exit(1);
break;
}
case A_VERIFY_D: {
if (s.pkstr) e = read_pubkey_string(s.pkstr,&pk);
else e = read_pubkey_file(s.pkfn,&pk);
if (e != SUCCESS) exit(1);
e = verify_detached(s.fn,s.sfn,pk);
if ( e != SUCCESS ) exit(1);
break;
}
case A_VERIFY_T: {
if (s.pkstr) e = read_pubkey_string(s.pkstr,&pk);
else e = read_pubkey_file(s.pkfn,&pk);
if (e != SUCCESS) exit(1);
e = verify_attached(s.fn,pk);
if ( e != SUCCESS ) exit(1);
break;
}
// Should not be here
case A_NULL: exit(1);
}
return 0;
}