Diff for /embedtools/src/voucher.c between versions 1.1.2.2 and 1.1.2.5

version 1.1.2.2, 2012/07/04 15:59:10 version 1.1.2.5, 2012/07/06 09:27:41
Line 1 Line 1
 #include "global.h"  #include "global.h"
   #include <openssl/pem.h>
   #include <openssl/rsa.h>
   #include <openssl/err.h>
   
   
 io_enableDEBUG;  
   
 cfg_root_t cfg;  cfg_root_t cfg;
   array_t *vs;
 FILE *output;  FILE *output;
   int Verbose;
 char szConfig[MAXPATHLEN] = VOUCHER_CFG;  char szConfig[MAXPATHLEN] = VOUCHER_CFG;
 extern char compiled[], compiledby[], compilehost[];  extern char compiled[], compiledby[], compilehost[];
   
Line 19  Usage() Line 22  Usage()
                 "\t-v\t\tVerbose (more -v more verbosity)\n"                  "\t-v\t\tVerbose (more -v more verbosity)\n"
                 "\t-r\t\tRequest new voucher(s) mode\n"                  "\t-r\t\tRequest new voucher(s) mode\n"
                 "\t-t\t\tTest 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-c <config>\tConfig file\n"
                 "\t-o <output>\tOutput file [default=-]\n"                  "\t-o <output>\tOutput file [default=-]\n"
                 "\n", compiled, compiledby, compilehost);                  "\n", compiled, compiledby, compilehost);
Line 27  Usage() Line 31  Usage()
 static void  static void
 AtExit()  AtExit()
 {  {
           io_freeVars(&vs);
         if (output != stdout)          if (output != stdout)
                 fclose(output);                  fclose(output);
 }  }
Line 48  RedirOutput(const char *name) Line 53  RedirOutput(const char *name)
         return 0;          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  int
 main(int argc, char **argv)  main(int argc, char **argv)
 {  {
         char ch, mode = 0;          char ch, mode = 0;
        int rid, cnt = 1;        int rid = 0, cnt = 1;
         register int i;
         RSA *key;
   
         output = stdout;          output = stdout;
         atexit(AtExit);          atexit(AtExit);
   
        while ((ch = getopt(argc, argv, "hvrtc:o:")) != -1)#ifdef __NetBSD__
         srandom(getpid() ^ time(NULL));
 #else
         srandomdev();
 #endif
 
         while ((ch = getopt(argc, argv, "hvrtgc:o:")) != -1)
                 switch (ch) {                  switch (ch) {
                         case 'r':                          case 'r':
                                 mode = 1;                                  mode = 1;
Line 66  main(int argc, char **argv) Line 366  main(int argc, char **argv)
                         case 't':                          case 't':
                                 mode = 2;                                  mode = 2;
                                 break;                                  break;
                           case 'g':
                                   return NewRSA();
                         case 'c':                          case 'c':
                                 strlcpy(szConfig, optarg, sizeof szConfig);                                  strlcpy(szConfig, optarg, sizeof szConfig);
                                 break;                                  break;
Line 73  main(int argc, char **argv) Line 375  main(int argc, char **argv)
                                 RedirOutput(optarg);                                  RedirOutput(optarg);
                                 break;                                  break;
                         case 'v':                          case 'v':
                                io_incDebug;                                Verbose++;
                                 break;                                  break;
                         case 'h':                          case 'h':
                         default:                          default:
Line 82  main(int argc, char **argv) Line 384  main(int argc, char **argv)
                 }                  }
         argc -= optind;          argc -= optind;
         argv += optind;          argv += optind;
        if (!argc || !mode) {        if (!argc || !mode || mode > 2) {
                 printf("Error:: not enough parameter or unspecified mode ...\n\n");                  printf("Error:: not enough parameter or unspecified mode ...\n\n");
                 Usage();                  Usage();
                 return 1;                  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)) {          if (cfgLoadConfig(szConfig, &cfg)) {
                 printf("Error:: load config #%d - %s\n", cfg_GetErrno(), cfg_GetError());                  printf("Error:: load config #%d - %s\n", cfg_GetErrno(), cfg_GetError());
                return 2;                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);          cfgUnloadConfig(&cfg);
         return 0;          return 0;
 }  }

Removed from v.1.1.2.2  
changed lines
  Added in v.1.1.2.5


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