Diff for /embedtools/src/voucher.c between versions 1.1 and 1.2

version 1.1, 2012/07/04 13:49:02 version 1.2, 2012/07/22 22:46:48
Line 0 Line 1
   #include "global.h"
   #include <openssl/pem.h>
   #include <openssl/rsa.h>
   #include <openssl/err.h>
   
   
   cfg_root_t cfg;
   array_t *vs;
   FILE *output;
   int Verbose;
   char szConfig[MAXPATHLEN] = VOUCHER_CFG;
   extern char compiled[], compiledby[], compilehost[];
   
   
   static void
   Usage()
   {
           printf( " -= VOUCHER =- management tool\n"
                   "=== %s === %s@%s ===\n\n"
                   "Syntax: voucher [options] -r <RollID> [count]\n"
                   "\tvoucher [options] -t <voucher> [voucher [voucher ...]]\n\n"
                   "\t-v\t\tVerbose (more -v more verbosity)\n"
                   "\t-r\t\tRequest new voucher(s) mode\n"
                   "\t-t\t\tTest voucher(s) mode\n"
                   "\t-g\t\tRequest new RSA pair mode\n"
                   "\t-c <config>\tConfig file\n"
                   "\t-o <output>\tOutput file [default=-]\n"
                   "\n", compiled, compiledby, compilehost);
   }
   
   static void
   AtExit()
   {
           io_freeVars(&vs);
           if (output != stdout)
                   fclose(output);
   }
   
   static inline int
   RedirOutput(const char *name)
   {
           AtExit();
   
           if (strcmp(name, "-")) {
                   output = fopen(name, "w+");
                   if (!output) {
                           printf("Error:: can't redirect output #%d - %s\n", 
                                           errno, strerror(errno));
                           return -1;
                   }
           } else
                   output = stdout;
           return 0;
   }
   
   static int
   NewRSA()
   {
           RSA *k = RSA_generate_key(VOUCHER_MAX_RSA * 8, 65537, NULL, NULL);
           if (!k) {
                   printf("Error:: can't generate RSA key\n");
                   return 2;
           }
   
           PEM_write_RSAPrivateKey(output, k, NULL, NULL, 0, NULL, NULL);
           PEM_write_RSA_PUBKEY(output, k);
           return 0;
   }
   
   static RSA *
   LoadKey(char mode)
   {
           FILE *f;
           RSA *key = NULL;
           ait_val_t v;
   
   #ifndef NDEBUG
           ERR_load_crypto_strings();
   #endif
   
           AIT_INIT_VAL(&v);
           if (mode == 1)
                   cfg_loadAttribute(&cfg, "voucher", "key_private", &v, VOUCHER_KEY);
           else
                   cfg_loadAttribute(&cfg, "voucher", "key_public", &v, VOUCHER_CRT);
   
           f = fopen(AIT_GET_STR(&v), "r");
           AIT_FREE_VAL(&v);
           if (!f) {
                   printf("Error:: open key #%d - %s\n", errno, strerror(errno));
                   return NULL;
           }
   
           if (mode == 1)
                   key = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL);
           else
                   key = PEM_read_RSA_PUBKEY(f, NULL, NULL, NULL);
   
           fclose(f);
   
           if (!key)
                   printf("Error:: wrong key !!!\n");
           return key;
   }
   
   static void
   ShowConfig(char mode, int rid, int cnt)
   {
           register int i;
   
           if (mode == 1)
                   printf(">>> Request voucher ticket(s) %d for Roll %d\n", cnt, rid);
           else
                   printf(">>> Test voucher ticket(s) %d\n", cnt);
   
           for (i = 0; i < io_arraySize(vs); i++)
                   printf(" + Voucher[%d]= %s\n", i, AIT_GET_STR(io_getVars(&vs, i)));
           printf(" + Roll ID %d bits\n", (int) 
                           strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0));
           printf(" + Ticket ID %d bits\n", (int) 
                           strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0));
           printf(" + CheckSum %d bits\n", (int) 
                           strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0));
           printf(" + Magic 0x%llx\n", (uint64_t) 
                           strtoll(cfg_getAttribute(&cfg, "voucher", "magic"), NULL, 0));
           printf(" + Charset %s\n", cfg_getAttribute(&cfg, "voucher", "charset"));
           if (!cfg_getAttribute(&cfg, "voucher", "key_private"))
                   cfg_setAttribute(&cfg, "voucher", "key_private", VOUCHER_KEY);
           printf(" + Private key %s\n", cfg_getAttribute(&cfg, "voucher", "key_private"));
           if (!cfg_getAttribute(&cfg, "voucher", "key_public"))
                   cfg_setAttribute(&cfg, "voucher", "key_public", VOUCHER_CRT);
           printf(" + Public key %s\n", cfg_getAttribute(&cfg, "voucher", "key_public"));
   }
   
   static int
   CheckConfig(char mode, int rid, int cnt)
   {
           const char *str;
   
           str = cfg_getAttribute(&cfg, "voucher", "charset");
           if (!str || strlen(str) < 2) {
                   printf("Error:: charset too short ... '%s'\n", str);
                   return -1;
           }
           if (strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0) > 31 || 
                           strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0) > 31 || 
                           strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0) > 31) {
                   printf("Error:: bits must be between 1..31\n");
                   return -1;
           }
           if (mode == 1) {
                   if (rid >= 1LL << strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0)) {
                           printf("Error:: Roll bits must be 0..%lu\n", 
                                           strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0));
                           return -1;
                   }
                   if (cnt < 1 || cnt >= 1LL << strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0)) {
                           printf("Error:: Ticket bits count must be 1..%lu\n", 
                                           strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0));
                           return -1;
                   }
           }
   
           return 0;
   }
   
   static inline void
   ll2buf(uint64_t ll, u_char * __restrict buf, int len)
   {
           register int i;
   
           for (i = len - 1; i >= 0; i--) {
                   buf[i] = ll & 0xff;
                   ll >>= 8;
           }
   }
   
   static inline void
   buf2ll(u_char * __restrict buf, uint64_t * __restrict ll, int len)
   {
           register int i;
   
           for (i = 1, *ll = buf[0]; i < len; i++) {
                   *ll <<= 8;
                   *ll += buf[i];
           }
   }
   
   static int
   ComputeVouchers(int rid, int cnt, RSA * __restrict key)
   {
           int base, clen, alen;
           u_int roll, ticket, cksum, mb;
           uint64_t clrcode, code, magic;
           register int i, num;
           const char *charset;
           u_char clrbuf[VOUCHER_MAX_RSA], codebuf[VOUCHER_MAX_LEN], *p = codebuf;
   
           /* prepare vars */
           roll = strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0);
           ticket = strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0);
           cksum = strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0);
   
           magic = strtoll(cfg_getAttribute(&cfg, "voucher", "magic"), NULL, 0);
   
           charset = cfg_getAttribute(&cfg, "voucher", "charset");
           base = strlen(charset);
           clen = RSA_size(key);
           alen = clen < sizeof(clrcode) ? clen : sizeof(clrcode);
           if (((roll + ticket + cksum) >> 3) + 1 > alen) {
                   printf("Error: roll+ticket+cksum bits too large for given key\n");
                   return -1;
           }
   
           mb = alen * 8 - (roll + ticket + cksum + 1);
           if (mb > 0)
                   magic &= (1LL << mb) - 1;
           else {
                   mb ^= mb;
                   magic ^= magic;
           }
   
           for (i = 1; i <= cnt; i++) {
                   clrcode = magic << cksum;
                   clrcode += (rid + i) % (1 << cksum);
                   clrcode <<= ticket;
                   clrcode += i;
                   clrcode = (clrcode << roll) + rid;
                   clrcode &= 0xffffffffffffffffLL >> (65 - 8 * clen);
   
                   ll2buf(clrcode, clrbuf, clen);
   
                   if (RSA_private_encrypt(clen, clrbuf, codebuf, key, RSA_NO_PADDING) == -1) {
                           printf("Error:: ticket[%d] RSA private encrypt %s\n", i, 
                                           ERR_error_string(ERR_get_error(), NULL));
                           continue;
                   }
   
                   buf2ll(codebuf, &code, clen);
   
                   /* pretty print */
                   memset(codebuf, 0, sizeof codebuf);
                   for (p = codebuf, num = sizeof codebuf; code && num; num--) {
                           *p++ = charset[code % base];
                           code /= base;
                   }
                   if (code) {
                           printf("Error:: voucher gets too long ... (%llu)\n", code);
                           continue;
                   }
   
                   printf("Voucher[%d]= %s\n", i, codebuf);
           }
   
           return 0;
   }
   
   static int
   TestVouchers(array_t * __restrict v, RSA * __restrict key)
   {
           int base, clen, alen;
           u_int roll, ticket, cksum, mb;
           uint64_t clrcode, code, magic;
           register int i, checksum, rid, cnt;
           const char *charset, *voucher;
           u_char clrbuf[VOUCHER_MAX_RSA], codebuf[VOUCHER_MAX_LEN], *p, *s;
   
           /* prepare vars */
           roll = strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0);
           ticket = strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0);
           cksum = strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0);
   
           magic = strtoll(cfg_getAttribute(&cfg, "voucher", "magic"), NULL, 0);
   
           charset = cfg_getAttribute(&cfg, "voucher", "charset");
           base = strlen(charset);
           clen = RSA_size(key);
           alen = clen < sizeof(clrcode) ? clen : sizeof(clrcode);
           if (((roll + ticket + cksum) >> 3) + 1 > alen) {
                   printf("Error: roll+ticket+cksum bits too large for given key\n");
                   return -1;
           }
   
           mb = alen * 8 - (roll + ticket + cksum + 1);
           if (mb > 0)
                   magic &= (1LL << mb) - 1;
           else {
                   mb ^= mb;
                   magic ^= magic;
           }
   
           for (i = 0, code = 0; i < io_arraySize(v); i++, code = 0) {
                   voucher = AIT_GET_STR(io_getVars(&v, i));
   
                   /* convert from voucher string to number */
                   p = (u_char*) strrchr(voucher, '\0'); 
                   while (p > (u_char*) voucher) {
                           p--;
                           if (*p == ' ')
                                   break;
                           code *= base;
                           s = (u_char*) strchr(charset, *p);
                           if (!s) {
                                   VERB(1) printf("Error:: illegal character (%c) found in %s\n", 
                                                   *p, voucher);
                                   printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
                                   break;
                           }
                           code += (s - (u_char*) charset);
                   }
   
                   ll2buf(code, codebuf, clen);
   
                   if (RSA_public_decrypt(clen, codebuf, clrbuf, key, RSA_NO_PADDING) == -1) {
                           VERB(1) printf("Error:: ticket[%d] RSA decrypt failed %s\n", i, 
                                           ERR_error_string(ERR_get_error(), NULL));
                           printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
                           continue;
                   }
   
                   buf2ll(clrbuf, &clrcode, clen);
   
                   rid = clrcode & ((1 << roll) - 1);
                   cnt = (clrcode >> roll) & ((1 << ticket) - 1);
                   checksum = (clrcode >> (ticket + roll)) & ((1 << cksum) - 1);
                   if (magic != ((clrcode >> (roll + ticket + cksum)))) {
                           VERB(1) printf("Error:: ticket[%d] invalid magic\n", i);
                           printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
                           continue;
                   }
                   if ((cnt + rid) % (1L << cksum) != checksum) {
                           VERB(1) printf("Error:: ticket[%d] invalid checksum\n", i);
                           printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
                           continue;
                   }
   
                   printf("Ticket[%d] = %s \"%s\" %d %d\n", i, VOUCHER_OK, voucher, rid, cnt);
           }
   
           return 0;
   }
   
   
   int
   main(int argc, char **argv)
   {
           char ch, mode = 0;
           int rid = 0, cnt = 1;
           register int i;
           RSA *key;
   
           output = stdout;
           atexit(AtExit);
   
   #ifdef __NetBSD__
           srandom(getpid() ^ time(NULL));
   #else
           srandomdev();
   #endif
   
           while ((ch = getopt(argc, argv, "hvrtgc:o:")) != -1)
                   switch (ch) {
                           case 'r':
                                   mode = 1;
                                   break;
                           case 't':
                                   mode = 2;
                                   break;
                           case 'g':
                                   return NewRSA();
                           case 'c':
                                   strlcpy(szConfig, optarg, sizeof szConfig);
                                   break;
                           case 'o':
                                   RedirOutput(optarg);
                                   break;
                           case 'v':
                                   Verbose++;
                                   break;
                           case 'h':
                           default:
                                   Usage();
                                   return 1;
                   }
           argc -= optind;
           argv += optind;
           if (!argc || !mode || mode > 2) {
                   printf("Error:: not enough parameter or unspecified mode ...\n\n");
                   Usage();
                   return 1;
           }
           if (mode == 1) {
                   if (argc > 1)
                           cnt = strtol(argv[1], NULL, 0);
                   rid = strtol(argv[0], NULL, 0);
           } else {
                   cnt = argc;
                   vs = io_allocVars(cnt);
                   for (i = 0; i < argc; i++)
                           AIT_SET_STR(io_getVars(&vs, i), argv[i]);
           }
   
           if (cfgLoadConfig(szConfig, &cfg)) {
                   printf("Error:: load config #%d - %s\n", cfg_GetErrno(), cfg_GetError());
                   return 3;
           } else {
                   VERB(1) ShowConfig(mode, rid, cnt);
                   if (CheckConfig(mode, rid, cnt)) {
                           cfgUnloadConfig(&cfg);
                           return 3;
                   }
           }
   
           if (!(key = LoadKey(mode))) {
                   cfgUnloadConfig(&cfg);
                   return 4;
           }
           if (RSA_size(key) > VOUCHER_MAX_RSA) {
                   printf("Error:: RSA key size %d bits. Max %d bits\n", 
                                   RSA_size(key) * 8, VOUCHER_MAX_RSA * 8);
                   RSA_free(key);
                   cfgUnloadConfig(&cfg);
                   return 5;
           } else
                   VERB(1) printf(" + Key size %d bits\n\n", RSA_size(key) * 8);
   
           if (mode == 1) {
                   if (ComputeVouchers(rid, cnt, key)) {
                           RSA_free(key);
                           cfgUnloadConfig(&cfg);
                           return 6;
                   }
           } else {
                   if (TestVouchers(vs, key)) {
                           RSA_free(key);
                           cfgUnloadConfig(&cfg);
                           return 6;
                   }
           }
   
           RSA_free(key);
           cfgUnloadConfig(&cfg);
           return 0;
   }

Removed from v.1.1  
changed lines
  Added in v.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>