Annotation of embedtools/src/voucher.c, revision 1.1.2.5
1.1.2.1 misho 1: #include "global.h"
1.1.2.3 misho 2: #include <openssl/pem.h>
3: #include <openssl/rsa.h>
4: #include <openssl/err.h>
1.1.2.1 misho 5:
1.1.2.2 misho 6:
7: cfg_root_t cfg;
1.1.2.4 misho 8: array_t *vs;
1.1.2.2 misho 9: FILE *output;
1.1.2.4 misho 10: int Verbose;
1.1.2.2 misho 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"
1.1.2.3 misho 25: "\t-g\t\tRequest new RSA pair mode\n"
1.1.2.2 misho 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: {
1.1.2.4 misho 34: io_freeVars(&vs);
1.1.2.2 misho 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:
1.1.2.3 misho 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:
1.1.2.4 misho 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:
1.1.2.5 ! misho 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:
1.1.2.4 misho 189: static int
1.1.2.5 ! misho 190: ComputeVouchers(int rid, int cnt, RSA * __restrict key)
1.1.2.4 misho 191: {
1.1.2.5 ! misho 192: int base, clen, alen;
1.1.2.4 misho 193: u_int roll, ticket, cksum, mb;
1.1.2.5 ! misho 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;
1.1.2.4 misho 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:
1.1.2.5 ! misho 206: charset = cfg_getAttribute(&cfg, "voucher", "charset");
! 207: base = strlen(charset);
1.1.2.4 misho 208: clen = RSA_size(key);
209: alen = clen < sizeof(clrcode) ? clen : sizeof(clrcode);
1.1.2.5 ! misho 210: if (((roll + ticket + cksum) >> 3) + 1 > alen) {
1.1.2.4 misho 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:
1.1.2.5 ! misho 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:
1.1.2.4 misho 340: return 0;
341: }
342:
1.1.2.2 misho 343:
1.1.2.1 misho 344: int
345: main(int argc, char **argv)
346: {
1.1.2.2 misho 347: char ch, mode = 0;
1.1.2.4 misho 348: int rid = 0, cnt = 1;
349: register int i;
350: RSA *key;
1.1.2.2 misho 351:
352: output = stdout;
353: atexit(AtExit);
354:
1.1.2.5 ! misho 355: #ifdef __NetBSD__
! 356: srandom(getpid() ^ time(NULL));
! 357: #else
! 358: srandomdev();
! 359: #endif
! 360:
1.1.2.3 misho 361: while ((ch = getopt(argc, argv, "hvrtgc:o:")) != -1)
1.1.2.2 misho 362: switch (ch) {
363: case 'r':
364: mode = 1;
365: break;
366: case 't':
367: mode = 2;
368: break;
1.1.2.3 misho 369: case 'g':
370: return NewRSA();
1.1.2.2 misho 371: case 'c':
372: strlcpy(szConfig, optarg, sizeof szConfig);
373: break;
374: case 'o':
375: RedirOutput(optarg);
376: break;
377: case 'v':
1.1.2.4 misho 378: Verbose++;
1.1.2.2 misho 379: break;
380: case 'h':
381: default:
382: Usage();
383: return 1;
384: }
385: argc -= optind;
386: argv += optind;
1.1.2.4 misho 387: if (!argc || !mode || mode > 2) {
1.1.2.2 misho 388: printf("Error:: not enough parameter or unspecified mode ...\n\n");
389: Usage();
390: return 1;
391: }
1.1.2.4 misho 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:
1.1.2.2 misho 403: if (cfgLoadConfig(szConfig, &cfg)) {
404: printf("Error:: load config #%d - %s\n", cfg_GetErrno(), cfg_GetError());
1.1.2.3 misho 405: return 3;
1.1.2.4 misho 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:
1.1.2.5 ! misho 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: }
1.1.2.2 misho 439: }
440:
1.1.2.4 misho 441: RSA_free(key);
1.1.2.2 misho 442: cfgUnloadConfig(&cfg);
1.1.2.1 misho 443: return 0;
444: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>