Annotation of embedtools/src/voucher.c, revision 1.2
1.2 ! misho 1: #include "global.h"
! 2: #include <openssl/pem.h>
! 3: #include <openssl/rsa.h>
! 4: #include <openssl/err.h>
! 5:
! 6:
! 7: cfg_root_t cfg;
! 8: array_t *vs;
! 9: FILE *output;
! 10: int Verbose;
! 11: char szConfig[MAXPATHLEN] = VOUCHER_CFG;
! 12: extern char compiled[], compiledby[], compilehost[];
! 13:
! 14:
! 15: static void
! 16: Usage()
! 17: {
! 18: printf( " -= VOUCHER =- management tool\n"
! 19: "=== %s === %s@%s ===\n\n"
! 20: "Syntax: voucher [options] -r <RollID> [count]\n"
! 21: "\tvoucher [options] -t <voucher> [voucher [voucher ...]]\n\n"
! 22: "\t-v\t\tVerbose (more -v more verbosity)\n"
! 23: "\t-r\t\tRequest new voucher(s) mode\n"
! 24: "\t-t\t\tTest voucher(s) mode\n"
! 25: "\t-g\t\tRequest new RSA pair mode\n"
! 26: "\t-c <config>\tConfig file\n"
! 27: "\t-o <output>\tOutput file [default=-]\n"
! 28: "\n", compiled, compiledby, compilehost);
! 29: }
! 30:
! 31: static void
! 32: AtExit()
! 33: {
! 34: io_freeVars(&vs);
! 35: if (output != stdout)
! 36: fclose(output);
! 37: }
! 38:
! 39: static inline int
! 40: RedirOutput(const char *name)
! 41: {
! 42: AtExit();
! 43:
! 44: if (strcmp(name, "-")) {
! 45: output = fopen(name, "w+");
! 46: if (!output) {
! 47: printf("Error:: can't redirect output #%d - %s\n",
! 48: errno, strerror(errno));
! 49: return -1;
! 50: }
! 51: } else
! 52: output = stdout;
! 53: return 0;
! 54: }
! 55:
! 56: static int
! 57: NewRSA()
! 58: {
! 59: RSA *k = RSA_generate_key(VOUCHER_MAX_RSA * 8, 65537, NULL, NULL);
! 60: if (!k) {
! 61: printf("Error:: can't generate RSA key\n");
! 62: return 2;
! 63: }
! 64:
! 65: PEM_write_RSAPrivateKey(output, k, NULL, NULL, 0, NULL, NULL);
! 66: PEM_write_RSA_PUBKEY(output, k);
! 67: return 0;
! 68: }
! 69:
! 70: static RSA *
! 71: LoadKey(char mode)
! 72: {
! 73: FILE *f;
! 74: RSA *key = NULL;
! 75: ait_val_t v;
! 76:
! 77: #ifndef NDEBUG
! 78: ERR_load_crypto_strings();
! 79: #endif
! 80:
! 81: AIT_INIT_VAL(&v);
! 82: if (mode == 1)
! 83: cfg_loadAttribute(&cfg, "voucher", "key_private", &v, VOUCHER_KEY);
! 84: else
! 85: cfg_loadAttribute(&cfg, "voucher", "key_public", &v, VOUCHER_CRT);
! 86:
! 87: f = fopen(AIT_GET_STR(&v), "r");
! 88: AIT_FREE_VAL(&v);
! 89: if (!f) {
! 90: printf("Error:: open key #%d - %s\n", errno, strerror(errno));
! 91: return NULL;
! 92: }
! 93:
! 94: if (mode == 1)
! 95: key = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL);
! 96: else
! 97: key = PEM_read_RSA_PUBKEY(f, NULL, NULL, NULL);
! 98:
! 99: fclose(f);
! 100:
! 101: if (!key)
! 102: printf("Error:: wrong key !!!\n");
! 103: return key;
! 104: }
! 105:
! 106: static void
! 107: ShowConfig(char mode, int rid, int cnt)
! 108: {
! 109: register int i;
! 110:
! 111: if (mode == 1)
! 112: printf(">>> Request voucher ticket(s) %d for Roll %d\n", cnt, rid);
! 113: else
! 114: printf(">>> Test voucher ticket(s) %d\n", cnt);
! 115:
! 116: for (i = 0; i < io_arraySize(vs); i++)
! 117: printf(" + Voucher[%d]= %s\n", i, AIT_GET_STR(io_getVars(&vs, i)));
! 118: printf(" + Roll ID %d bits\n", (int)
! 119: strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0));
! 120: printf(" + Ticket ID %d bits\n", (int)
! 121: strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0));
! 122: printf(" + CheckSum %d bits\n", (int)
! 123: strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0));
! 124: printf(" + Magic 0x%llx\n", (uint64_t)
! 125: strtoll(cfg_getAttribute(&cfg, "voucher", "magic"), NULL, 0));
! 126: printf(" + Charset %s\n", cfg_getAttribute(&cfg, "voucher", "charset"));
! 127: if (!cfg_getAttribute(&cfg, "voucher", "key_private"))
! 128: cfg_setAttribute(&cfg, "voucher", "key_private", VOUCHER_KEY);
! 129: printf(" + Private key %s\n", cfg_getAttribute(&cfg, "voucher", "key_private"));
! 130: if (!cfg_getAttribute(&cfg, "voucher", "key_public"))
! 131: cfg_setAttribute(&cfg, "voucher", "key_public", VOUCHER_CRT);
! 132: printf(" + Public key %s\n", cfg_getAttribute(&cfg, "voucher", "key_public"));
! 133: }
! 134:
! 135: static int
! 136: CheckConfig(char mode, int rid, int cnt)
! 137: {
! 138: const char *str;
! 139:
! 140: str = cfg_getAttribute(&cfg, "voucher", "charset");
! 141: if (!str || strlen(str) < 2) {
! 142: printf("Error:: charset too short ... '%s'\n", str);
! 143: return -1;
! 144: }
! 145: if (strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0) > 31 ||
! 146: strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0) > 31 ||
! 147: strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0) > 31) {
! 148: printf("Error:: bits must be between 1..31\n");
! 149: return -1;
! 150: }
! 151: if (mode == 1) {
! 152: if (rid >= 1LL << strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0)) {
! 153: printf("Error:: Roll bits must be 0..%lu\n",
! 154: strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0));
! 155: return -1;
! 156: }
! 157: if (cnt < 1 || cnt >= 1LL << strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0)) {
! 158: printf("Error:: Ticket bits count must be 1..%lu\n",
! 159: strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0));
! 160: return -1;
! 161: }
! 162: }
! 163:
! 164: return 0;
! 165: }
! 166:
! 167: static inline void
! 168: ll2buf(uint64_t ll, u_char * __restrict buf, int len)
! 169: {
! 170: register int i;
! 171:
! 172: for (i = len - 1; i >= 0; i--) {
! 173: buf[i] = ll & 0xff;
! 174: ll >>= 8;
! 175: }
! 176: }
! 177:
! 178: static inline void
! 179: buf2ll(u_char * __restrict buf, uint64_t * __restrict ll, int len)
! 180: {
! 181: register int i;
! 182:
! 183: for (i = 1, *ll = buf[0]; i < len; i++) {
! 184: *ll <<= 8;
! 185: *ll += buf[i];
! 186: }
! 187: }
! 188:
! 189: static int
! 190: ComputeVouchers(int rid, int cnt, RSA * __restrict key)
! 191: {
! 192: int base, clen, alen;
! 193: u_int roll, ticket, cksum, mb;
! 194: uint64_t clrcode, code, magic;
! 195: register int i, num;
! 196: const char *charset;
! 197: u_char clrbuf[VOUCHER_MAX_RSA], codebuf[VOUCHER_MAX_LEN], *p = codebuf;
! 198:
! 199: /* prepare vars */
! 200: roll = strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0);
! 201: ticket = strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0);
! 202: cksum = strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0);
! 203:
! 204: magic = strtoll(cfg_getAttribute(&cfg, "voucher", "magic"), NULL, 0);
! 205:
! 206: charset = cfg_getAttribute(&cfg, "voucher", "charset");
! 207: base = strlen(charset);
! 208: clen = RSA_size(key);
! 209: alen = clen < sizeof(clrcode) ? clen : sizeof(clrcode);
! 210: if (((roll + ticket + cksum) >> 3) + 1 > alen) {
! 211: printf("Error: roll+ticket+cksum bits too large for given key\n");
! 212: return -1;
! 213: }
! 214:
! 215: mb = alen * 8 - (roll + ticket + cksum + 1);
! 216: if (mb > 0)
! 217: magic &= (1LL << mb) - 1;
! 218: else {
! 219: mb ^= mb;
! 220: magic ^= magic;
! 221: }
! 222:
! 223: for (i = 1; i <= cnt; i++) {
! 224: clrcode = magic << cksum;
! 225: clrcode += (rid + i) % (1 << cksum);
! 226: clrcode <<= ticket;
! 227: clrcode += i;
! 228: clrcode = (clrcode << roll) + rid;
! 229: clrcode &= 0xffffffffffffffffLL >> (65 - 8 * clen);
! 230:
! 231: ll2buf(clrcode, clrbuf, clen);
! 232:
! 233: if (RSA_private_encrypt(clen, clrbuf, codebuf, key, RSA_NO_PADDING) == -1) {
! 234: printf("Error:: ticket[%d] RSA private encrypt %s\n", i,
! 235: ERR_error_string(ERR_get_error(), NULL));
! 236: continue;
! 237: }
! 238:
! 239: buf2ll(codebuf, &code, clen);
! 240:
! 241: /* pretty print */
! 242: memset(codebuf, 0, sizeof codebuf);
! 243: for (p = codebuf, num = sizeof codebuf; code && num; num--) {
! 244: *p++ = charset[code % base];
! 245: code /= base;
! 246: }
! 247: if (code) {
! 248: printf("Error:: voucher gets too long ... (%llu)\n", code);
! 249: continue;
! 250: }
! 251:
! 252: printf("Voucher[%d]= %s\n", i, codebuf);
! 253: }
! 254:
! 255: return 0;
! 256: }
! 257:
! 258: static int
! 259: TestVouchers(array_t * __restrict v, RSA * __restrict key)
! 260: {
! 261: int base, clen, alen;
! 262: u_int roll, ticket, cksum, mb;
! 263: uint64_t clrcode, code, magic;
! 264: register int i, checksum, rid, cnt;
! 265: const char *charset, *voucher;
! 266: u_char clrbuf[VOUCHER_MAX_RSA], codebuf[VOUCHER_MAX_LEN], *p, *s;
! 267:
! 268: /* prepare vars */
! 269: roll = strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0);
! 270: ticket = strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0);
! 271: cksum = strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0);
! 272:
! 273: magic = strtoll(cfg_getAttribute(&cfg, "voucher", "magic"), NULL, 0);
! 274:
! 275: charset = cfg_getAttribute(&cfg, "voucher", "charset");
! 276: base = strlen(charset);
! 277: clen = RSA_size(key);
! 278: alen = clen < sizeof(clrcode) ? clen : sizeof(clrcode);
! 279: if (((roll + ticket + cksum) >> 3) + 1 > alen) {
! 280: printf("Error: roll+ticket+cksum bits too large for given key\n");
! 281: return -1;
! 282: }
! 283:
! 284: mb = alen * 8 - (roll + ticket + cksum + 1);
! 285: if (mb > 0)
! 286: magic &= (1LL << mb) - 1;
! 287: else {
! 288: mb ^= mb;
! 289: magic ^= magic;
! 290: }
! 291:
! 292: for (i = 0, code = 0; i < io_arraySize(v); i++, code = 0) {
! 293: voucher = AIT_GET_STR(io_getVars(&v, i));
! 294:
! 295: /* convert from voucher string to number */
! 296: p = (u_char*) strrchr(voucher, '\0');
! 297: while (p > (u_char*) voucher) {
! 298: p--;
! 299: if (*p == ' ')
! 300: break;
! 301: code *= base;
! 302: s = (u_char*) strchr(charset, *p);
! 303: if (!s) {
! 304: VERB(1) printf("Error:: illegal character (%c) found in %s\n",
! 305: *p, voucher);
! 306: printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
! 307: break;
! 308: }
! 309: code += (s - (u_char*) charset);
! 310: }
! 311:
! 312: ll2buf(code, codebuf, clen);
! 313:
! 314: if (RSA_public_decrypt(clen, codebuf, clrbuf, key, RSA_NO_PADDING) == -1) {
! 315: VERB(1) printf("Error:: ticket[%d] RSA decrypt failed %s\n", i,
! 316: ERR_error_string(ERR_get_error(), NULL));
! 317: printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
! 318: continue;
! 319: }
! 320:
! 321: buf2ll(clrbuf, &clrcode, clen);
! 322:
! 323: rid = clrcode & ((1 << roll) - 1);
! 324: cnt = (clrcode >> roll) & ((1 << ticket) - 1);
! 325: checksum = (clrcode >> (ticket + roll)) & ((1 << cksum) - 1);
! 326: if (magic != ((clrcode >> (roll + ticket + cksum)))) {
! 327: VERB(1) printf("Error:: ticket[%d] invalid magic\n", i);
! 328: printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
! 329: continue;
! 330: }
! 331: if ((cnt + rid) % (1L << cksum) != checksum) {
! 332: VERB(1) printf("Error:: ticket[%d] invalid checksum\n", i);
! 333: printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
! 334: continue;
! 335: }
! 336:
! 337: printf("Ticket[%d] = %s \"%s\" %d %d\n", i, VOUCHER_OK, voucher, rid, cnt);
! 338: }
! 339:
! 340: return 0;
! 341: }
! 342:
! 343:
! 344: int
! 345: main(int argc, char **argv)
! 346: {
! 347: char ch, mode = 0;
! 348: int rid = 0, cnt = 1;
! 349: register int i;
! 350: RSA *key;
! 351:
! 352: output = stdout;
! 353: atexit(AtExit);
! 354:
! 355: #ifdef __NetBSD__
! 356: srandom(getpid() ^ time(NULL));
! 357: #else
! 358: srandomdev();
! 359: #endif
! 360:
! 361: while ((ch = getopt(argc, argv, "hvrtgc:o:")) != -1)
! 362: switch (ch) {
! 363: case 'r':
! 364: mode = 1;
! 365: break;
! 366: case 't':
! 367: mode = 2;
! 368: break;
! 369: case 'g':
! 370: return NewRSA();
! 371: case 'c':
! 372: strlcpy(szConfig, optarg, sizeof szConfig);
! 373: break;
! 374: case 'o':
! 375: RedirOutput(optarg);
! 376: break;
! 377: case 'v':
! 378: Verbose++;
! 379: break;
! 380: case 'h':
! 381: default:
! 382: Usage();
! 383: return 1;
! 384: }
! 385: argc -= optind;
! 386: argv += optind;
! 387: if (!argc || !mode || mode > 2) {
! 388: printf("Error:: not enough parameter or unspecified mode ...\n\n");
! 389: Usage();
! 390: return 1;
! 391: }
! 392: if (mode == 1) {
! 393: if (argc > 1)
! 394: cnt = strtol(argv[1], NULL, 0);
! 395: rid = strtol(argv[0], NULL, 0);
! 396: } else {
! 397: cnt = argc;
! 398: vs = io_allocVars(cnt);
! 399: for (i = 0; i < argc; i++)
! 400: AIT_SET_STR(io_getVars(&vs, i), argv[i]);
! 401: }
! 402:
! 403: if (cfgLoadConfig(szConfig, &cfg)) {
! 404: printf("Error:: load config #%d - %s\n", cfg_GetErrno(), cfg_GetError());
! 405: return 3;
! 406: } else {
! 407: VERB(1) ShowConfig(mode, rid, cnt);
! 408: if (CheckConfig(mode, rid, cnt)) {
! 409: cfgUnloadConfig(&cfg);
! 410: return 3;
! 411: }
! 412: }
! 413:
! 414: if (!(key = LoadKey(mode))) {
! 415: cfgUnloadConfig(&cfg);
! 416: return 4;
! 417: }
! 418: if (RSA_size(key) > VOUCHER_MAX_RSA) {
! 419: printf("Error:: RSA key size %d bits. Max %d bits\n",
! 420: RSA_size(key) * 8, VOUCHER_MAX_RSA * 8);
! 421: RSA_free(key);
! 422: cfgUnloadConfig(&cfg);
! 423: return 5;
! 424: } else
! 425: VERB(1) printf(" + Key size %d bits\n\n", RSA_size(key) * 8);
! 426:
! 427: if (mode == 1) {
! 428: if (ComputeVouchers(rid, cnt, key)) {
! 429: RSA_free(key);
! 430: cfgUnloadConfig(&cfg);
! 431: return 6;
! 432: }
! 433: } else {
! 434: if (TestVouchers(vs, key)) {
! 435: RSA_free(key);
! 436: cfgUnloadConfig(&cfg);
! 437: return 6;
! 438: }
! 439: }
! 440:
! 441: RSA_free(key);
! 442: cfgUnloadConfig(&cfg);
! 443: return 0;
! 444: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>