Annotation of embedtools/src/voucher.c, revision 1.2.4.1
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: {
1.2.4.1 ! misho 34: ait_freeVars(&vs);
1.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:
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:
1.2.4.1 ! misho 116: for (i = 0; i < array_Size(vs); i++)
! 117: printf(" + Voucher[%d]= %s\n", i, AIT_GET_STR(ait_getVars(&vs, i)));
1.2 misho 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:
1.2.4.1 ! misho 292: for (i = 0, code = 0; i < array_Size(v); i++, code = 0) {
! 293: voucher = AIT_GET_STR(ait_getVars(&v, i));
1.2 misho 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;
1.2.4.1 ! misho 398: vs = ait_allocVars(cnt);
1.2 misho 399: for (i = 0; i < argc; i++)
1.2.4.1 ! misho 400: AIT_SET_STR(ait_getVars(&vs, i), argv[i]);
1.2 misho 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>