/* * Secure X Message Passing Library tools. * * (c) Alexander Vdolainen 2016 * * libsxmp is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * libsxmp 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 this program. If not, see ."; * * sxtkeygen - sxt key container tool for generating the keys */ #include #include #define __USE_GNU #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_PATHNAME 4096 #define MAX_FNAME 128 #define MAX_NAMEPREFIX 90 #define FULL_PROGRAM_NAME "SXT key container generation tool" static void __help_print(FILE *fso, const char *fmtname) { fprintf(fso, "\n%s\n\n", FULL_PROGRAM_NAME); /* usage options */ fprintf(fso, "Usage:\n"); fprintf(fso, "\t%s [-t | --type ] [-n | --name ] [ -P | --path ]" " [-H | --hash <64bit hash>] [-p | --passphrase]\n", fmtname); /* defaults */ fprintf(fso, "\t%s -h | --help\n", fmtname); fprintf(fso, "\t%s -v | --version\n", fmtname); /* options description */ fprintf(fso, "\nOptions:\n"); fprintf(fso, "\t%-25s Output key type:\n" "\t\t\t\t\t * ppkp-ed25519 (default)\n", "-t | --type "); fprintf(fso, "\t%-25s Prefix for the output file names.\n", "-n | --name "); fprintf(fso, "\t%-25s Directory path where keys will be located (defaults: ~).\n", "-P | --path "); fprintf(fso, "\t%-25s Include special custom 64bit hash (defaults: none).\n", "-H | --hash <64bit hash>"); fprintf(fso, "\t%-25s Ask a passphrase to encrypt a private key (defaults: key not encrypted).\n", "-p | --passphrase"); fprintf(fso, "\t%-25s Show help screen.\n", "-h | --help"); fprintf(fso, "\t%-25s Print version information.\n", "-v | --version"); return; } extern int passkey_promt(char *passbuf, size_t p_len, int cnf, void *priv); int main(int argc, char **argv) { uint64_t hash = 0; sxtkey_t *pair, *pubkey, *privkey; char *dir = NULL, *nameprefix = NULL, *keytype = NULL; char fullpath[MAX_PATHNAME]; char privname[MAX_FNAME]; char pubname[MAX_FNAME]; struct stat statbuf; int encrypt = 0, opt, type = 0, r; pair = pubkey = privkey = NULL; while(1) { int option_index = 0; static struct option long_options[] = { /* These options a generic ones. */ {"help", no_argument, NULL, 'h'}, /* print out help and version info */ {"version", no_argument, NULL, 'v'}, /* just out a version info */ /* key generation options */ {"type", required_argument, NULL, 't'}, {"name", required_argument, NULL, 'n'}, {"path", required_argument, NULL, 'P'}, {"hash", required_argument, NULL, 'H'}, {"passphrase", no_argument, NULL, 'p'}, /* termnil */ {NULL, 0, NULL, 0}, }; if((opt = getopt_long(argc, argv, "hvt:n:P:H:p", long_options, &option_index)) == -1) break; switch(opt) { case 'h': __help_print(stdout, argv[0]); return 0; break; case 'v': /* TODO: add version output */ return 0; break; case 't': keytype = optarg; break; case 'n': nameprefix = optarg; break; case 'P': dir = optarg; break; case 'H': hash = strtoul(optarg, NULL, 0); break; case 'p': encrypt = 1; break; default: fprintf(stderr, "Aborting.\n"); __help_print(stdout, argv[0]); abort(); } } /* init library */ if((r = sxt_init())) { fprintf(stderr, "Unable to init sxt library(%d).\nAborting.\n", r); abort(); } /* check type */ if(keytype) type = sxtkey_type_fname(keytype); else type = PPKP_ED25519; keytype = (char *)sxtkey_name(type); if(!type) { fprintf(stderr, "Illegal keytype.\nAborting.\n"); abort(); } /* going to check output directory */ if(!dir) dir = getenv("HOME"); if(!dir) { fprintf(stderr, "Cannot get output directory.\nAborting.\n"); abort(); } /* check if this is a directory */ if(stat(dir, &statbuf)) { fprintf(stderr, "Cannot stat given directory (%s).\nAborting.\n", strerror(errno)); abort(); } else if(!S_ISDIR(statbuf.st_mode)) { fprintf(stderr, "Given path isn't a directory.\nAborting.\n"); abort(); } if(nameprefix) { if(strlen(nameprefix) > MAX_NAMEPREFIX) { fprintf(stderr, "Name prefix too long (max: %d).\nAborting.\n", MAX_NAMEPREFIX); abort(); } snprintf(privname, MAX_FNAME, "%s-%s.ppkp", nameprefix, keytype); snprintf(pubname, MAX_FNAME, "%s-%s.pub", nameprefix, keytype); } else { snprintf(privname, MAX_FNAME, "%s.ppkp", keytype); snprintf(pubname, MAX_FNAME, "%s.pub", keytype); } /* ok let's deal with files */ snprintf(fullpath, MAX_PATHNAME, "%s/%s", dir, privname); /* private key file output */ if(!stat(fullpath, &statbuf)) { fprintf(stderr, "Private key file '%s' already exists.\nAborting.\n", fullpath); abort(); } snprintf(fullpath, MAX_PATHNAME, "%s/%s", dir, pubname); /* public key file output */ if(!stat(fullpath, &statbuf)) { fprintf(stderr, "Public key file '%s' already exists.\nAborting.\n", fullpath); abort(); } /* looks like all is fine */ fprintf(stdout, "Going to generate %s keys:\n", keytype); fprintf(stdout, "Output will located in '%s':\n", dir); fprintf(stdout, "\t * Private key: %s\n", privname); fprintf(stdout, "\t * Public key: %s\n", pubname); if(encrypt) { fprintf(stdout, "Private key going to be encrypted.\n"); fprintf(stdout, "Passkey phrase will be asked later.\n"); } /* generate a key first */ if(!(pair = sxtkey_alloc())) { fprintf(stderr, "Not enough memory to allocate a key.\nAborting.\n"); abort(); } fprintf(stdout, "Generating key pair ..."); if((r = sxtkey_generate(pair, type, 0)) != SXT_SUCCESS) { fprintf(stderr, "FAIL.\nError (%d).\nAborting.\n", r); sxtkey_free(pair); abort(); } else fprintf(stdout, "DONE.\n"); /* hash */ if(hash) sxtkey_assign_hash(pair, hash); /* duplicate private */ if((r = sxtkey_dup_private(pair, &privkey)) != SXT_SUCCESS) { fprintf(stderr, "Unable to duplicate private key(%d).\nAborting.\n", r); sxtkey_free(pair); abort(); } /* get public duplicate */ if((r = sxtkey_dup_public(pair, &pubkey)) != SXT_SUCCESS) { fprintf(stderr, "Unable to duplicate public key(%d).\nAborting.\n", r); sxtkey_free(pair); sxtkey_free(privkey); abort(); } /* ok, output private key first */ snprintf(fullpath, MAX_PATHNAME, "%s/%s", dir, privname); if(!encrypt) { /* will not encrypt */ r = sxtkey_export_priv_file(privkey, fullpath, NULL, NULL, NULL); } else { r = sxtkey_export_priv_file(privkey, fullpath, NULL, passkey_promt, (void *)"Enter passkey phrase:"); } if(r != SXT_SUCCESS) { __failed_export: fprintf(stderr, "Unable to perform key export (%d).\nAborting.\n", r); sxtkey_burn(pair); sxtkey_burn(privkey); sxtkey_free(pair); sxtkey_free(privkey); abort(); } /* ok, output public key */ snprintf(fullpath, MAX_PATHNAME, "%s/%s", dir, pubname); r = sxtkey_export_public_file(pubkey, fullpath); if(r != SXT_SUCCESS) goto __failed_export; sxtkey_burn(pair); sxtkey_burn(privkey); sxtkey_burn(pubkey); sxtkey_free(pair); sxtkey_free(privkey); sxtkey_free(pubkey); return 0; }