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

1.1.2.1   misho       1: #include "global.h"
1.1.2.3   misho       2: #include <openssl/pem.h>
                      3: #include <openssl/rsa.h>
                      4: #include <openssl/err.h>
1.1.2.1   misho       5: 
1.1.2.2   misho       6: 
                      7: cfg_root_t cfg;
1.1.2.4   misho       8: array_t *vs;
1.1.2.2   misho       9: FILE *output;
1.1.2.4   misho      10: int Verbose;
1.1.2.2   misho      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"
1.1.2.3   misho      25:                "\t-g\t\tRequest new RSA pair mode\n"
1.1.2.2   misho      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.1.2.4   misho      34:        io_freeVars(&vs);
1.1.2.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: 
1.1.2.3   misho      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: 
1.1.2.4   misho      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: 
1.1.2.5 ! misho     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: 
1.1.2.4   misho     189: static int
1.1.2.5 ! misho     190: ComputeVouchers(int rid, int cnt, RSA * __restrict key)
1.1.2.4   misho     191: {
1.1.2.5 ! misho     192:        int base, clen, alen;
1.1.2.4   misho     193:        u_int roll, ticket, cksum, mb;
1.1.2.5 ! misho     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;
1.1.2.4   misho     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: 
1.1.2.5 ! misho     206:        charset = cfg_getAttribute(&cfg, "voucher", "charset");
        !           207:        base = strlen(charset);
1.1.2.4   misho     208:        clen = RSA_size(key);
                    209:        alen = clen < sizeof(clrcode) ? clen : sizeof(clrcode);
1.1.2.5 ! misho     210:        if (((roll + ticket + cksum) >> 3) + 1 > alen) {
1.1.2.4   misho     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: 
1.1.2.5 ! misho     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: 
1.1.2.4   misho     340:        return 0;
                    341: }
                    342: 
1.1.2.2   misho     343: 
1.1.2.1   misho     344: int
                    345: main(int argc, char **argv)
                    346: {
1.1.2.2   misho     347:        char ch, mode = 0;
1.1.2.4   misho     348:        int rid = 0, cnt = 1;
                    349:        register int i;
                    350:        RSA *key;
1.1.2.2   misho     351: 
                    352:        output = stdout;
                    353:        atexit(AtExit);
                    354: 
1.1.2.5 ! misho     355: #ifdef __NetBSD__
        !           356:        srandom(getpid() ^ time(NULL));
        !           357: #else
        !           358:        srandomdev();
        !           359: #endif
        !           360: 
1.1.2.3   misho     361:        while ((ch = getopt(argc, argv, "hvrtgc:o:")) != -1)
1.1.2.2   misho     362:                switch (ch) {
                    363:                        case 'r':
                    364:                                mode = 1;
                    365:                                break;
                    366:                        case 't':
                    367:                                mode = 2;
                    368:                                break;
1.1.2.3   misho     369:                        case 'g':
                    370:                                return NewRSA();
1.1.2.2   misho     371:                        case 'c':
                    372:                                strlcpy(szConfig, optarg, sizeof szConfig);
                    373:                                break;
                    374:                        case 'o':
                    375:                                RedirOutput(optarg);
                    376:                                break;
                    377:                        case 'v':
1.1.2.4   misho     378:                                Verbose++;
1.1.2.2   misho     379:                                break;
                    380:                        case 'h':
                    381:                        default:
                    382:                                Usage();
                    383:                                return 1;
                    384:                }
                    385:        argc -= optind;
                    386:        argv += optind;
1.1.2.4   misho     387:        if (!argc || !mode || mode > 2) {
1.1.2.2   misho     388:                printf("Error:: not enough parameter or unspecified mode ...\n\n");
                    389:                Usage();
                    390:                return 1;
                    391:        }
1.1.2.4   misho     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: 
1.1.2.2   misho     403:        if (cfgLoadConfig(szConfig, &cfg)) {
                    404:                printf("Error:: load config #%d - %s\n", cfg_GetErrno(), cfg_GetError());
1.1.2.3   misho     405:                return 3;
1.1.2.4   misho     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: 
1.1.2.5 ! misho     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:                }
1.1.2.2   misho     439:        }
                    440: 
1.1.2.4   misho     441:        RSA_free(key);
1.1.2.2   misho     442:        cfgUnloadConfig(&cfg);
1.1.2.1   misho     443:        return 0;
                    444: }

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