File:  [ELWIX - Embedded LightWeight unIX -] / embedtools / src / voucher.c
Revision 1.3: download - view: text, annotated - select for diffs - revision graph
Wed Feb 5 15:44:06 2014 UTC (10 years, 4 months ago) by misho
Branches: MAIN
CVS tags: tools2_7, tools2_6, tools2_5, tools2_4, tools2_3, tools2_2, tools2_1, TOOLS2_6, TOOLS2_5, TOOLS2_4, TOOLS2_3, TOOLS2_2, TOOLS2_1, TOOLS2_0, HEAD
version 2.0

    1: /*************************************************************************
    2:  * (C) 2011 AITNET - Sofia/Bulgaria - <office@aitbg.com>
    3:  *  by Michael Pounov <misho@aitbg.com>
    4:  *
    5:  * $Author: misho $
    6:  * $Id: voucher.c,v 1.3 2014/02/05 15:44:06 misho Exp $
    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 - 2014
   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: */
   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: {
   79: 	ait_freeVars(&vs);
   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: 
  161: 	for (i = 0; i < array_Size(vs); i++)
  162: 		printf(" + Voucher[%d]= %s\n", i, AIT_GET_STR(ait_getVars(&vs, i)));
  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: 
  337: 	for (i = 0, code = 0; i < array_Size(v); i++, code = 0) {
  338: 		voucher = AIT_GET_STR(ait_getVars((array_t**) &v, i));
  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;
  443: 		vs = ait_allocVars(cnt);
  444: 		for (i = 0; i < argc; i++)
  445: 			AIT_SET_STR(ait_getVars(&vs, i), argv[i]);
  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>