--- embedtools/src/voucher.c 2012/07/04 13:49:02 1.1.2.1 +++ embedtools/src/voucher.c 2012/07/05 09:00:23 1.1.2.4 @@ -1,8 +1,288 @@ #include "global.h" +#include +#include +#include +cfg_root_t cfg; +array_t *vs; +FILE *output; +int Verbose; +char szConfig[MAXPATHLEN] = VOUCHER_CFG; +extern char compiled[], compiledby[], compilehost[]; + + +static void +Usage() +{ + printf( " -= VOUCHER =- management tool\n" + "=== %s === %s@%s ===\n\n" + "Syntax: voucher [options] -r [count]\n" + "\tvoucher [options] -t [voucher [voucher ...]]\n\n" + "\t-v\t\tVerbose (more -v more verbosity)\n" + "\t-r\t\tRequest new voucher(s) mode\n" + "\t-t\t\tTest voucher(s) mode\n" + "\t-g\t\tRequest new RSA pair mode\n" + "\t-c \tConfig file\n" + "\t-o \tOutput file [default=-]\n" + "\n", compiled, compiledby, compilehost); +} + +static void +AtExit() +{ + io_freeVars(&vs); + if (output != stdout) + fclose(output); +} + +static inline int +RedirOutput(const char *name) +{ + AtExit(); + + if (strcmp(name, "-")) { + output = fopen(name, "w+"); + if (!output) { + printf("Error:: can't redirect output #%d - %s\n", + errno, strerror(errno)); + return -1; + } + } else + output = stdout; + return 0; +} + +static int +NewRSA() +{ + RSA *k = RSA_generate_key(VOUCHER_MAX_RSA * 8, 65537, NULL, NULL); + if (!k) { + printf("Error:: can't generate RSA key\n"); + return 2; + } + + PEM_write_RSAPrivateKey(output, k, NULL, NULL, 0, NULL, NULL); + PEM_write_RSA_PUBKEY(output, k); + return 0; +} + +static RSA * +LoadKey(char mode) +{ + FILE *f; + RSA *key = NULL; + ait_val_t v; + +#ifndef NDEBUG + ERR_load_crypto_strings(); +#endif + + AIT_INIT_VAL(&v); + if (mode == 1) + cfg_loadAttribute(&cfg, "voucher", "key_private", &v, VOUCHER_KEY); + else + cfg_loadAttribute(&cfg, "voucher", "key_public", &v, VOUCHER_CRT); + + f = fopen(AIT_GET_STR(&v), "r"); + AIT_FREE_VAL(&v); + if (!f) { + printf("Error:: open key #%d - %s\n", errno, strerror(errno)); + return NULL; + } + + if (mode == 1) + key = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL); + else + key = PEM_read_RSA_PUBKEY(f, NULL, NULL, NULL); + + fclose(f); + + if (!key) + printf("Error:: wrong key !!!\n"); + return key; +} + +static void +ShowConfig(char mode, int rid, int cnt) +{ + register int i; + + if (mode == 1) + printf(">>> Request voucher ticket(s) %d for Roll %d\n", cnt, rid); + else + printf(">>> Test voucher ticket(s) %d\n", cnt); + + for (i = 0; i < io_arraySize(vs); i++) + printf(" + Voucher[%d]= %s\n", i, AIT_GET_STR(io_getVars(&vs, i))); + printf(" + Roll ID %d bits\n", (int) + strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0)); + printf(" + Ticket ID %d bits\n", (int) + strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0)); + printf(" + CheckSum %d bits\n", (int) + strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0)); + printf(" + Magic 0x%llx\n", (uint64_t) + strtoll(cfg_getAttribute(&cfg, "voucher", "magic"), NULL, 0)); + printf(" + Charset %s\n", cfg_getAttribute(&cfg, "voucher", "charset")); + if (!cfg_getAttribute(&cfg, "voucher", "key_private")) + cfg_setAttribute(&cfg, "voucher", "key_private", VOUCHER_KEY); + printf(" + Private key %s\n", cfg_getAttribute(&cfg, "voucher", "key_private")); + if (!cfg_getAttribute(&cfg, "voucher", "key_public")) + cfg_setAttribute(&cfg, "voucher", "key_public", VOUCHER_CRT); + printf(" + Public key %s\n", cfg_getAttribute(&cfg, "voucher", "key_public")); +} + +static int +CheckConfig(char mode, int rid, int cnt) +{ + const char *str; + + str = cfg_getAttribute(&cfg, "voucher", "charset"); + if (!str || strlen(str) < 2) { + printf("Error:: charset too short ... '%s'\n", str); + return -1; + } + if (strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0) > 31 || + strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0) > 31 || + strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0) > 31) { + printf("Error:: bits must be between 1..31\n"); + return -1; + } + if (mode == 1) { + if (rid >= 1LL << strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0)) { + printf("Error:: Roll bits must be 0..%lu\n", + strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0)); + return -1; + } + if (cnt < 1 || cnt >= 1LL << strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0)) { + printf("Error:: Ticket bits count must be 1..%lu\n", + strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0)); + return -1; + } + } + + return 0; +} + +static int +ComputeVouchers(RSA * __restrict key) +{ + int base, vlen, clen, alen; + u_int roll, ticket, cksum, mb; + uint64_t clrcode, magic; + + /* prepare vars */ + roll = strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0); + ticket = strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0); + cksum = strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0); + + magic = strtoll(cfg_getAttribute(&cfg, "voucher", "magic"), NULL, 0); + + base = strlen(cfg_getAttribute(&cfg, "voucher", "charset")); + vlen = ((roll + ticket + cksum) >> 3) + 1; + clen = RSA_size(key); + alen = clen < sizeof(clrcode) ? clen : sizeof(clrcode); + if (vlen > alen) { + printf("Error: roll+ticket+cksum bits too large for given key\n"); + return -1; + } + + mb = alen * 8 - (roll + ticket + cksum + 1); + if (mb > 0) + magic &= (1LL << mb) - 1; + else { + mb ^= mb; + magic ^= magic; + } + + return 0; +} + + int main(int argc, char **argv) { + char ch, mode = 0; + int rid = 0, cnt = 1; + register int i; + RSA *key; + + output = stdout; + atexit(AtExit); + + while ((ch = getopt(argc, argv, "hvrtgc:o:")) != -1) + switch (ch) { + case 'r': + mode = 1; + break; + case 't': + mode = 2; + break; + case 'g': + return NewRSA(); + case 'c': + strlcpy(szConfig, optarg, sizeof szConfig); + break; + case 'o': + RedirOutput(optarg); + break; + case 'v': + Verbose++; + break; + case 'h': + default: + Usage(); + return 1; + } + argc -= optind; + argv += optind; + if (!argc || !mode || mode > 2) { + printf("Error:: not enough parameter or unspecified mode ...\n\n"); + Usage(); + return 1; + } + if (mode == 1) { + if (argc > 1) + cnt = strtol(argv[1], NULL, 0); + rid = strtol(argv[0], NULL, 0); + } else { + cnt = argc; + vs = io_allocVars(cnt); + for (i = 0; i < argc; i++) + AIT_SET_STR(io_getVars(&vs, i), argv[i]); + } + + if (cfgLoadConfig(szConfig, &cfg)) { + printf("Error:: load config #%d - %s\n", cfg_GetErrno(), cfg_GetError()); + return 3; + } else { + VERB(1) ShowConfig(mode, rid, cnt); + if (CheckConfig(mode, rid, cnt)) { + cfgUnloadConfig(&cfg); + return 3; + } + } + + if (!(key = LoadKey(mode))) { + cfgUnloadConfig(&cfg); + return 4; + } + if (RSA_size(key) > VOUCHER_MAX_RSA) { + printf("Error:: RSA key size %d bits. Max %d bits\n", + RSA_size(key) * 8, VOUCHER_MAX_RSA * 8); + RSA_free(key); + cfgUnloadConfig(&cfg); + return 5; + } else + VERB(1) printf(" + Key size %d bits\n\n", RSA_size(key) * 8); + + if (ComputeVouchers(key)) { + RSA_free(key); + cfgUnloadConfig(&cfg); + return 6; + } + + RSA_free(key); + cfgUnloadConfig(&cfg); return 0; }