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

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: {
        !            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>