File:  [ELWIX - Embedded LightWeight unIX -] / embedtools / src / voucher.c
Revision 1.2: download - view: text, annotated - select for diffs - revision graph
Sun Jul 22 22:46:48 2012 UTC (11 years, 11 months ago) by misho
Branches: MAIN
CVS tags: tools2_0, tools1_2, TOOLS1_2, TOOLS1_1, HEAD
version 1.1

    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>