Annotation of embedtools/src/voucher.c, revision 1.2.4.1

1.2       misho       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: {
1.2.4.1 ! misho      34:        ait_freeVars(&vs);
1.2       misho      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: 
1.2.4.1 ! misho     116:        for (i = 0; i < array_Size(vs); i++)
        !           117:                printf(" + Voucher[%d]= %s\n", i, AIT_GET_STR(ait_getVars(&vs, i)));
1.2       misho     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: 
1.2.4.1 ! misho     292:        for (i = 0, code = 0; i < array_Size(v); i++, code = 0) {
        !           293:                voucher = AIT_GET_STR(ait_getVars(&v, i));
1.2       misho     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;
1.2.4.1 ! misho     398:                vs = ait_allocVars(cnt);
1.2       misho     399:                for (i = 0; i < argc; i++)
1.2.4.1 ! misho     400:                        AIT_SET_STR(ait_getVars(&vs, i), argv[i]);
1.2       misho     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>