Annotation of embedtools/src/voucher.c, revision 1.2.4.3
1.2.4.2 misho 1: /*************************************************************************
2: * (C) 2011 AITNET - Sofia/Bulgaria - <office@aitbg.com>
3: * by Michael Pounov <misho@aitbg.com>
4: *
5: * $Author: misho $
1.2.4.3 ! misho 6: * $Id: voucher.c,v 1.2.4.2 2013/01/18 13:21:06 misho Exp $
1.2.4.2 misho 7: *
8: *************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
1.2 misho 46: #include "global.h"
47: #include <openssl/pem.h>
48: #include <openssl/rsa.h>
49: #include <openssl/err.h>
50:
51:
52: cfg_root_t cfg;
53: array_t *vs;
54: FILE *output;
55: int Verbose;
56: char szConfig[MAXPATHLEN] = VOUCHER_CFG;
57: extern char compiled[], compiledby[], compilehost[];
58:
59:
60: static void
61: Usage()
62: {
63: printf( " -= VOUCHER =- management tool\n"
64: "=== %s === %s@%s ===\n\n"
65: "Syntax: voucher [options] -r <RollID> [count]\n"
66: "\tvoucher [options] -t <voucher> [voucher [voucher ...]]\n\n"
67: "\t-v\t\tVerbose (more -v more verbosity)\n"
68: "\t-r\t\tRequest new voucher(s) mode\n"
69: "\t-t\t\tTest voucher(s) mode\n"
70: "\t-g\t\tRequest new RSA pair mode\n"
71: "\t-c <config>\tConfig file\n"
72: "\t-o <output>\tOutput file [default=-]\n"
73: "\n", compiled, compiledby, compilehost);
74: }
75:
76: static void
77: AtExit()
78: {
1.2.4.1 misho 79: ait_freeVars(&vs);
1.2 misho 80: if (output != stdout)
81: fclose(output);
82: }
83:
84: static inline int
85: RedirOutput(const char *name)
86: {
87: AtExit();
88:
89: if (strcmp(name, "-")) {
90: output = fopen(name, "w+");
91: if (!output) {
92: printf("Error:: can't redirect output #%d - %s\n",
93: errno, strerror(errno));
94: return -1;
95: }
96: } else
97: output = stdout;
98: return 0;
99: }
100:
101: static int
102: NewRSA()
103: {
104: RSA *k = RSA_generate_key(VOUCHER_MAX_RSA * 8, 65537, NULL, NULL);
105: if (!k) {
106: printf("Error:: can't generate RSA key\n");
107: return 2;
108: }
109:
110: PEM_write_RSAPrivateKey(output, k, NULL, NULL, 0, NULL, NULL);
111: PEM_write_RSA_PUBKEY(output, k);
112: return 0;
113: }
114:
115: static RSA *
116: LoadKey(char mode)
117: {
118: FILE *f;
119: RSA *key = NULL;
120: ait_val_t v;
121:
122: #ifndef NDEBUG
123: ERR_load_crypto_strings();
124: #endif
125:
126: AIT_INIT_VAL(&v);
127: if (mode == 1)
128: cfg_loadAttribute(&cfg, "voucher", "key_private", &v, VOUCHER_KEY);
129: else
130: cfg_loadAttribute(&cfg, "voucher", "key_public", &v, VOUCHER_CRT);
131:
132: f = fopen(AIT_GET_STR(&v), "r");
133: AIT_FREE_VAL(&v);
134: if (!f) {
135: printf("Error:: open key #%d - %s\n", errno, strerror(errno));
136: return NULL;
137: }
138:
139: if (mode == 1)
140: key = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL);
141: else
142: key = PEM_read_RSA_PUBKEY(f, NULL, NULL, NULL);
143:
144: fclose(f);
145:
146: if (!key)
147: printf("Error:: wrong key !!!\n");
148: return key;
149: }
150:
151: static void
152: ShowConfig(char mode, int rid, int cnt)
153: {
154: register int i;
155:
156: if (mode == 1)
157: printf(">>> Request voucher ticket(s) %d for Roll %d\n", cnt, rid);
158: else
159: printf(">>> Test voucher ticket(s) %d\n", cnt);
160:
1.2.4.1 misho 161: for (i = 0; i < array_Size(vs); i++)
162: printf(" + Voucher[%d]= %s\n", i, AIT_GET_STR(ait_getVars(&vs, i)));
1.2 misho 163: printf(" + Roll ID %d bits\n", (int)
164: strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0));
165: printf(" + Ticket ID %d bits\n", (int)
166: strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0));
167: printf(" + CheckSum %d bits\n", (int)
168: strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0));
169: printf(" + Magic 0x%llx\n", (uint64_t)
170: strtoll(cfg_getAttribute(&cfg, "voucher", "magic"), NULL, 0));
171: printf(" + Charset %s\n", cfg_getAttribute(&cfg, "voucher", "charset"));
172: if (!cfg_getAttribute(&cfg, "voucher", "key_private"))
173: cfg_setAttribute(&cfg, "voucher", "key_private", VOUCHER_KEY);
174: printf(" + Private key %s\n", cfg_getAttribute(&cfg, "voucher", "key_private"));
175: if (!cfg_getAttribute(&cfg, "voucher", "key_public"))
176: cfg_setAttribute(&cfg, "voucher", "key_public", VOUCHER_CRT);
177: printf(" + Public key %s\n", cfg_getAttribute(&cfg, "voucher", "key_public"));
178: }
179:
180: static int
181: CheckConfig(char mode, int rid, int cnt)
182: {
183: const char *str;
184:
185: str = cfg_getAttribute(&cfg, "voucher", "charset");
186: if (!str || strlen(str) < 2) {
187: printf("Error:: charset too short ... '%s'\n", str);
188: return -1;
189: }
190: if (strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0) > 31 ||
191: strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0) > 31 ||
192: strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0) > 31) {
193: printf("Error:: bits must be between 1..31\n");
194: return -1;
195: }
196: if (mode == 1) {
197: if (rid >= 1LL << strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0)) {
198: printf("Error:: Roll bits must be 0..%lu\n",
199: strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0));
200: return -1;
201: }
202: if (cnt < 1 || cnt >= 1LL << strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0)) {
203: printf("Error:: Ticket bits count must be 1..%lu\n",
204: strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0));
205: return -1;
206: }
207: }
208:
209: return 0;
210: }
211:
212: static inline void
213: ll2buf(uint64_t ll, u_char * __restrict buf, int len)
214: {
215: register int i;
216:
217: for (i = len - 1; i >= 0; i--) {
218: buf[i] = ll & 0xff;
219: ll >>= 8;
220: }
221: }
222:
223: static inline void
224: buf2ll(u_char * __restrict buf, uint64_t * __restrict ll, int len)
225: {
226: register int i;
227:
228: for (i = 1, *ll = buf[0]; i < len; i++) {
229: *ll <<= 8;
230: *ll += buf[i];
231: }
232: }
233:
234: static int
235: ComputeVouchers(int rid, int cnt, RSA * __restrict key)
236: {
237: int base, clen, alen;
238: u_int roll, ticket, cksum, mb;
239: uint64_t clrcode, code, magic;
240: register int i, num;
241: const char *charset;
242: u_char clrbuf[VOUCHER_MAX_RSA], codebuf[VOUCHER_MAX_LEN], *p = codebuf;
243:
244: /* prepare vars */
245: roll = strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0);
246: ticket = strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0);
247: cksum = strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0);
248:
249: magic = strtoll(cfg_getAttribute(&cfg, "voucher", "magic"), NULL, 0);
250:
251: charset = cfg_getAttribute(&cfg, "voucher", "charset");
252: base = strlen(charset);
253: clen = RSA_size(key);
254: alen = clen < sizeof(clrcode) ? clen : sizeof(clrcode);
255: if (((roll + ticket + cksum) >> 3) + 1 > alen) {
256: printf("Error: roll+ticket+cksum bits too large for given key\n");
257: return -1;
258: }
259:
260: mb = alen * 8 - (roll + ticket + cksum + 1);
261: if (mb > 0)
262: magic &= (1LL << mb) - 1;
263: else {
264: mb ^= mb;
265: magic ^= magic;
266: }
267:
268: for (i = 1; i <= cnt; i++) {
269: clrcode = magic << cksum;
270: clrcode += (rid + i) % (1 << cksum);
271: clrcode <<= ticket;
272: clrcode += i;
273: clrcode = (clrcode << roll) + rid;
274: clrcode &= 0xffffffffffffffffLL >> (65 - 8 * clen);
275:
276: ll2buf(clrcode, clrbuf, clen);
277:
278: if (RSA_private_encrypt(clen, clrbuf, codebuf, key, RSA_NO_PADDING) == -1) {
279: printf("Error:: ticket[%d] RSA private encrypt %s\n", i,
280: ERR_error_string(ERR_get_error(), NULL));
281: continue;
282: }
283:
284: buf2ll(codebuf, &code, clen);
285:
286: /* pretty print */
287: memset(codebuf, 0, sizeof codebuf);
288: for (p = codebuf, num = sizeof codebuf; code && num; num--) {
289: *p++ = charset[code % base];
290: code /= base;
291: }
292: if (code) {
293: printf("Error:: voucher gets too long ... (%llu)\n", code);
294: continue;
295: }
296:
297: printf("Voucher[%d]= %s\n", i, codebuf);
298: }
299:
300: return 0;
301: }
302:
303: static int
304: TestVouchers(array_t * __restrict v, RSA * __restrict key)
305: {
306: int base, clen, alen;
307: u_int roll, ticket, cksum, mb;
308: uint64_t clrcode, code, magic;
309: register int i, checksum, rid, cnt;
310: const char *charset, *voucher;
311: u_char clrbuf[VOUCHER_MAX_RSA], codebuf[VOUCHER_MAX_LEN], *p, *s;
312:
313: /* prepare vars */
314: roll = strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0);
315: ticket = strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0);
316: cksum = strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0);
317:
318: magic = strtoll(cfg_getAttribute(&cfg, "voucher", "magic"), NULL, 0);
319:
320: charset = cfg_getAttribute(&cfg, "voucher", "charset");
321: base = strlen(charset);
322: clen = RSA_size(key);
323: alen = clen < sizeof(clrcode) ? clen : sizeof(clrcode);
324: if (((roll + ticket + cksum) >> 3) + 1 > alen) {
325: printf("Error: roll+ticket+cksum bits too large for given key\n");
326: return -1;
327: }
328:
329: mb = alen * 8 - (roll + ticket + cksum + 1);
330: if (mb > 0)
331: magic &= (1LL << mb) - 1;
332: else {
333: mb ^= mb;
334: magic ^= magic;
335: }
336:
1.2.4.1 misho 337: for (i = 0, code = 0; i < array_Size(v); i++, code = 0) {
1.2.4.3 ! misho 338: voucher = AIT_GET_STR(ait_getVars((array_t**) &v, i));
1.2 misho 339:
340: /* convert from voucher string to number */
341: p = (u_char*) strrchr(voucher, '\0');
342: while (p > (u_char*) voucher) {
343: p--;
344: if (*p == ' ')
345: break;
346: code *= base;
347: s = (u_char*) strchr(charset, *p);
348: if (!s) {
349: VERB(1) printf("Error:: illegal character (%c) found in %s\n",
350: *p, voucher);
351: printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
352: break;
353: }
354: code += (s - (u_char*) charset);
355: }
356:
357: ll2buf(code, codebuf, clen);
358:
359: if (RSA_public_decrypt(clen, codebuf, clrbuf, key, RSA_NO_PADDING) == -1) {
360: VERB(1) printf("Error:: ticket[%d] RSA decrypt failed %s\n", i,
361: ERR_error_string(ERR_get_error(), NULL));
362: printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
363: continue;
364: }
365:
366: buf2ll(clrbuf, &clrcode, clen);
367:
368: rid = clrcode & ((1 << roll) - 1);
369: cnt = (clrcode >> roll) & ((1 << ticket) - 1);
370: checksum = (clrcode >> (ticket + roll)) & ((1 << cksum) - 1);
371: if (magic != ((clrcode >> (roll + ticket + cksum)))) {
372: VERB(1) printf("Error:: ticket[%d] invalid magic\n", i);
373: printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
374: continue;
375: }
376: if ((cnt + rid) % (1L << cksum) != checksum) {
377: VERB(1) printf("Error:: ticket[%d] invalid checksum\n", i);
378: printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
379: continue;
380: }
381:
382: printf("Ticket[%d] = %s \"%s\" %d %d\n", i, VOUCHER_OK, voucher, rid, cnt);
383: }
384:
385: return 0;
386: }
387:
388:
389: int
390: main(int argc, char **argv)
391: {
392: char ch, mode = 0;
393: int rid = 0, cnt = 1;
394: register int i;
395: RSA *key;
396:
397: output = stdout;
398: atexit(AtExit);
399:
400: #ifdef __NetBSD__
401: srandom(getpid() ^ time(NULL));
402: #else
403: srandomdev();
404: #endif
405:
406: while ((ch = getopt(argc, argv, "hvrtgc:o:")) != -1)
407: switch (ch) {
408: case 'r':
409: mode = 1;
410: break;
411: case 't':
412: mode = 2;
413: break;
414: case 'g':
415: return NewRSA();
416: case 'c':
417: strlcpy(szConfig, optarg, sizeof szConfig);
418: break;
419: case 'o':
420: RedirOutput(optarg);
421: break;
422: case 'v':
423: Verbose++;
424: break;
425: case 'h':
426: default:
427: Usage();
428: return 1;
429: }
430: argc -= optind;
431: argv += optind;
432: if (!argc || !mode || mode > 2) {
433: printf("Error:: not enough parameter or unspecified mode ...\n\n");
434: Usage();
435: return 1;
436: }
437: if (mode == 1) {
438: if (argc > 1)
439: cnt = strtol(argv[1], NULL, 0);
440: rid = strtol(argv[0], NULL, 0);
441: } else {
442: cnt = argc;
1.2.4.1 misho 443: vs = ait_allocVars(cnt);
1.2 misho 444: for (i = 0; i < argc; i++)
1.2.4.1 misho 445: AIT_SET_STR(ait_getVars(&vs, i), argv[i]);
1.2 misho 446: }
447:
448: if (cfgLoadConfig(szConfig, &cfg)) {
449: printf("Error:: load config #%d - %s\n", cfg_GetErrno(), cfg_GetError());
450: return 3;
451: } else {
452: VERB(1) ShowConfig(mode, rid, cnt);
453: if (CheckConfig(mode, rid, cnt)) {
454: cfgUnloadConfig(&cfg);
455: return 3;
456: }
457: }
458:
459: if (!(key = LoadKey(mode))) {
460: cfgUnloadConfig(&cfg);
461: return 4;
462: }
463: if (RSA_size(key) > VOUCHER_MAX_RSA) {
464: printf("Error:: RSA key size %d bits. Max %d bits\n",
465: RSA_size(key) * 8, VOUCHER_MAX_RSA * 8);
466: RSA_free(key);
467: cfgUnloadConfig(&cfg);
468: return 5;
469: } else
470: VERB(1) printf(" + Key size %d bits\n\n", RSA_size(key) * 8);
471:
472: if (mode == 1) {
473: if (ComputeVouchers(rid, cnt, key)) {
474: RSA_free(key);
475: cfgUnloadConfig(&cfg);
476: return 6;
477: }
478: } else {
479: if (TestVouchers(vs, key)) {
480: RSA_free(key);
481: cfgUnloadConfig(&cfg);
482: return 6;
483: }
484: }
485:
486: RSA_free(key);
487: cfgUnloadConfig(&cfg);
488: return 0;
489: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>