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

1.3     ! misho       1: /*************************************************************************
        !             2:  * (C) 2011 AITNET - Sofia/Bulgaria - <office@aitbg.com>
        !             3:  *  by Michael Pounov <misho@aitbg.com>
        !             4:  *
        !             5:  * $Author: misho $
        !             6:  * $Id: voucher.c,v 1.2.4.4 2014/01/30 01:03:27 misho Exp $
        !             7:  *
        !             8:  *************************************************************************
        !             9: The ELWIX and AITNET software is distributed under the following
        !            10: terms:
        !            11: 
        !            12: All of the documentation and software included in the ELWIX and AITNET
        !            13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
        !            14: 
        !            15: Copyright 2004 - 2014
        !            16:        by Michael Pounov <misho@elwix.org>.  All rights reserved.
        !            17: 
        !            18: Redistribution and use in source and binary forms, with or without
        !            19: modification, are permitted provided that the following conditions
        !            20: are met:
        !            21: 1. Redistributions of source code must retain the above copyright
        !            22:    notice, this list of conditions and the following disclaimer.
        !            23: 2. Redistributions in binary form must reproduce the above copyright
        !            24:    notice, this list of conditions and the following disclaimer in the
        !            25:    documentation and/or other materials provided with the distribution.
        !            26: 3. All advertising materials mentioning features or use of this software
        !            27:    must display the following acknowledgement:
        !            28: This product includes software developed by Michael Pounov <misho@elwix.org>
        !            29: ELWIX - Embedded LightWeight unIX and its contributors.
        !            30: 4. Neither the name of AITNET nor the names of its contributors
        !            31:    may be used to endorse or promote products derived from this software
        !            32:    without specific prior written permission.
        !            33: 
        !            34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
        !            35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            37: ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            44: SUCH DAMAGE.
        !            45: */
1.2       misho      46: #include "global.h"
                     47: #include <openssl/pem.h>
                     48: #include <openssl/rsa.h>
                     49: #include <openssl/err.h>
                     50: 
                     51: 
                     52: cfg_root_t cfg;
                     53: array_t *vs;
                     54: FILE *output;
                     55: int Verbose;
                     56: char szConfig[MAXPATHLEN] = VOUCHER_CFG;
                     57: extern char compiled[], compiledby[], compilehost[];
                     58: 
                     59: 
                     60: static void
                     61: Usage()
                     62: {
                     63:        printf( " -= VOUCHER =- management tool\n"
                     64:                "=== %s === %s@%s ===\n\n"
                     65:                "Syntax: voucher [options] -r <RollID> [count]\n"
                     66:                "\tvoucher [options] -t <voucher> [voucher [voucher ...]]\n\n"
                     67:                "\t-v\t\tVerbose (more -v more verbosity)\n"
                     68:                "\t-r\t\tRequest new voucher(s) mode\n"
                     69:                "\t-t\t\tTest voucher(s) mode\n"
                     70:                "\t-g\t\tRequest new RSA pair mode\n"
                     71:                "\t-c <config>\tConfig file\n"
                     72:                "\t-o <output>\tOutput file [default=-]\n"
                     73:                "\n", compiled, compiledby, compilehost);
                     74: }
                     75: 
                     76: static void
                     77: AtExit()
                     78: {
1.3     ! misho      79:        ait_freeVars(&vs);
1.2       misho      80:        if (output != stdout)
                     81:                fclose(output);
                     82: }
                     83: 
                     84: static inline int
                     85: RedirOutput(const char *name)
                     86: {
                     87:        AtExit();
                     88: 
                     89:        if (strcmp(name, "-")) {
                     90:                output = fopen(name, "w+");
                     91:                if (!output) {
                     92:                        printf("Error:: can't redirect output #%d - %s\n", 
                     93:                                        errno, strerror(errno));
                     94:                        return -1;
                     95:                }
                     96:        } else
                     97:                output = stdout;
                     98:        return 0;
                     99: }
                    100: 
                    101: static int
                    102: NewRSA()
                    103: {
                    104:        RSA *k = RSA_generate_key(VOUCHER_MAX_RSA * 8, 65537, NULL, NULL);
                    105:        if (!k) {
                    106:                printf("Error:: can't generate RSA key\n");
                    107:                return 2;
                    108:        }
                    109: 
                    110:        PEM_write_RSAPrivateKey(output, k, NULL, NULL, 0, NULL, NULL);
                    111:        PEM_write_RSA_PUBKEY(output, k);
                    112:        return 0;
                    113: }
                    114: 
                    115: static RSA *
                    116: LoadKey(char mode)
                    117: {
                    118:        FILE *f;
                    119:        RSA *key = NULL;
                    120:        ait_val_t v;
                    121: 
                    122: #ifndef NDEBUG
                    123:        ERR_load_crypto_strings();
                    124: #endif
                    125: 
                    126:        AIT_INIT_VAL(&v);
                    127:        if (mode == 1)
                    128:                cfg_loadAttribute(&cfg, "voucher", "key_private", &v, VOUCHER_KEY);
                    129:        else
                    130:                cfg_loadAttribute(&cfg, "voucher", "key_public", &v, VOUCHER_CRT);
                    131: 
                    132:        f = fopen(AIT_GET_STR(&v), "r");
                    133:        AIT_FREE_VAL(&v);
                    134:        if (!f) {
                    135:                printf("Error:: open key #%d - %s\n", errno, strerror(errno));
                    136:                return NULL;
                    137:        }
                    138: 
                    139:        if (mode == 1)
                    140:                key = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL);
                    141:        else
                    142:                key = PEM_read_RSA_PUBKEY(f, NULL, NULL, NULL);
                    143: 
                    144:        fclose(f);
                    145: 
                    146:        if (!key)
                    147:                printf("Error:: wrong key !!!\n");
                    148:        return key;
                    149: }
                    150: 
                    151: static void
                    152: ShowConfig(char mode, int rid, int cnt)
                    153: {
                    154:        register int i;
                    155: 
                    156:        if (mode == 1)
                    157:                printf(">>> Request voucher ticket(s) %d for Roll %d\n", cnt, rid);
                    158:        else
                    159:                printf(">>> Test voucher ticket(s) %d\n", cnt);
                    160: 
1.3     ! misho     161:        for (i = 0; i < array_Size(vs); i++)
        !           162:                printf(" + Voucher[%d]= %s\n", i, AIT_GET_STR(ait_getVars(&vs, i)));
1.2       misho     163:        printf(" + Roll ID %d bits\n", (int) 
                    164:                        strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0));
                    165:        printf(" + Ticket ID %d bits\n", (int) 
                    166:                        strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0));
                    167:        printf(" + CheckSum %d bits\n", (int) 
                    168:                        strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0));
                    169:        printf(" + Magic 0x%llx\n", (uint64_t) 
                    170:                        strtoll(cfg_getAttribute(&cfg, "voucher", "magic"), NULL, 0));
                    171:        printf(" + Charset %s\n", cfg_getAttribute(&cfg, "voucher", "charset"));
                    172:        if (!cfg_getAttribute(&cfg, "voucher", "key_private"))
                    173:                cfg_setAttribute(&cfg, "voucher", "key_private", VOUCHER_KEY);
                    174:        printf(" + Private key %s\n", cfg_getAttribute(&cfg, "voucher", "key_private"));
                    175:        if (!cfg_getAttribute(&cfg, "voucher", "key_public"))
                    176:                cfg_setAttribute(&cfg, "voucher", "key_public", VOUCHER_CRT);
                    177:        printf(" + Public key %s\n", cfg_getAttribute(&cfg, "voucher", "key_public"));
                    178: }
                    179: 
                    180: static int
                    181: CheckConfig(char mode, int rid, int cnt)
                    182: {
                    183:        const char *str;
                    184: 
                    185:        str = cfg_getAttribute(&cfg, "voucher", "charset");
                    186:        if (!str || strlen(str) < 2) {
                    187:                printf("Error:: charset too short ... '%s'\n", str);
                    188:                return -1;
                    189:        }
                    190:        if (strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0) > 31 || 
                    191:                        strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0) > 31 || 
                    192:                        strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0) > 31) {
                    193:                printf("Error:: bits must be between 1..31\n");
                    194:                return -1;
                    195:        }
                    196:        if (mode == 1) {
                    197:                if (rid >= 1LL << strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0)) {
                    198:                        printf("Error:: Roll bits must be 0..%lu\n", 
                    199:                                        strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0));
                    200:                        return -1;
                    201:                }
                    202:                if (cnt < 1 || cnt >= 1LL << strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0)) {
                    203:                        printf("Error:: Ticket bits count must be 1..%lu\n", 
                    204:                                        strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0));
                    205:                        return -1;
                    206:                }
                    207:        }
                    208: 
                    209:        return 0;
                    210: }
                    211: 
                    212: static inline void
                    213: ll2buf(uint64_t ll, u_char * __restrict buf, int len)
                    214: {
                    215:        register int i;
                    216: 
                    217:        for (i = len - 1; i >= 0; i--) {
                    218:                buf[i] = ll & 0xff;
                    219:                ll >>= 8;
                    220:        }
                    221: }
                    222: 
                    223: static inline void
                    224: buf2ll(u_char * __restrict buf, uint64_t * __restrict ll, int len)
                    225: {
                    226:        register int i;
                    227: 
                    228:        for (i = 1, *ll = buf[0]; i < len; i++) {
                    229:                *ll <<= 8;
                    230:                *ll += buf[i];
                    231:        }
                    232: }
                    233: 
                    234: static int
                    235: ComputeVouchers(int rid, int cnt, RSA * __restrict key)
                    236: {
                    237:        int base, clen, alen;
                    238:        u_int roll, ticket, cksum, mb;
                    239:        uint64_t clrcode, code, magic;
                    240:        register int i, num;
                    241:        const char *charset;
                    242:        u_char clrbuf[VOUCHER_MAX_RSA], codebuf[VOUCHER_MAX_LEN], *p = codebuf;
                    243: 
                    244:        /* prepare vars */
                    245:        roll = strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0);
                    246:        ticket = strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0);
                    247:        cksum = strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0);
                    248: 
                    249:        magic = strtoll(cfg_getAttribute(&cfg, "voucher", "magic"), NULL, 0);
                    250: 
                    251:        charset = cfg_getAttribute(&cfg, "voucher", "charset");
                    252:        base = strlen(charset);
                    253:        clen = RSA_size(key);
                    254:        alen = clen < sizeof(clrcode) ? clen : sizeof(clrcode);
                    255:        if (((roll + ticket + cksum) >> 3) + 1 > alen) {
                    256:                printf("Error: roll+ticket+cksum bits too large for given key\n");
                    257:                return -1;
                    258:        }
                    259: 
                    260:        mb = alen * 8 - (roll + ticket + cksum + 1);
                    261:        if (mb > 0)
                    262:                magic &= (1LL << mb) - 1;
                    263:        else {
                    264:                mb ^= mb;
                    265:                magic ^= magic;
                    266:        }
                    267: 
                    268:        for (i = 1; i <= cnt; i++) {
                    269:                clrcode = magic << cksum;
                    270:                clrcode += (rid + i) % (1 << cksum);
                    271:                clrcode <<= ticket;
                    272:                clrcode += i;
                    273:                clrcode = (clrcode << roll) + rid;
                    274:                clrcode &= 0xffffffffffffffffLL >> (65 - 8 * clen);
                    275: 
                    276:                ll2buf(clrcode, clrbuf, clen);
                    277: 
                    278:                if (RSA_private_encrypt(clen, clrbuf, codebuf, key, RSA_NO_PADDING) == -1) {
                    279:                        printf("Error:: ticket[%d] RSA private encrypt %s\n", i, 
                    280:                                        ERR_error_string(ERR_get_error(), NULL));
                    281:                        continue;
                    282:                }
                    283: 
                    284:                buf2ll(codebuf, &code, clen);
                    285: 
                    286:                /* pretty print */
                    287:                memset(codebuf, 0, sizeof codebuf);
                    288:                for (p = codebuf, num = sizeof codebuf; code && num; num--) {
                    289:                        *p++ = charset[code % base];
                    290:                        code /= base;
                    291:                }
                    292:                if (code) {
                    293:                        printf("Error:: voucher gets too long ... (%llu)\n", code);
                    294:                        continue;
                    295:                }
                    296: 
                    297:                printf("Voucher[%d]= %s\n", i, codebuf);
                    298:        }
                    299: 
                    300:        return 0;
                    301: }
                    302: 
                    303: static int
                    304: TestVouchers(array_t * __restrict v, RSA * __restrict key)
                    305: {
                    306:        int base, clen, alen;
                    307:        u_int roll, ticket, cksum, mb;
                    308:        uint64_t clrcode, code, magic;
                    309:        register int i, checksum, rid, cnt;
                    310:        const char *charset, *voucher;
                    311:        u_char clrbuf[VOUCHER_MAX_RSA], codebuf[VOUCHER_MAX_LEN], *p, *s;
                    312: 
                    313:        /* prepare vars */
                    314:        roll = strtol(cfg_getAttribute(&cfg, "voucher", "rollbits"), NULL, 0);
                    315:        ticket = strtol(cfg_getAttribute(&cfg, "voucher", "ticketbits"), NULL, 0);
                    316:        cksum = strtol(cfg_getAttribute(&cfg, "voucher", "cksumbits"), NULL, 0);
                    317: 
                    318:        magic = strtoll(cfg_getAttribute(&cfg, "voucher", "magic"), NULL, 0);
                    319: 
                    320:        charset = cfg_getAttribute(&cfg, "voucher", "charset");
                    321:        base = strlen(charset);
                    322:        clen = RSA_size(key);
                    323:        alen = clen < sizeof(clrcode) ? clen : sizeof(clrcode);
                    324:        if (((roll + ticket + cksum) >> 3) + 1 > alen) {
                    325:                printf("Error: roll+ticket+cksum bits too large for given key\n");
                    326:                return -1;
                    327:        }
                    328: 
                    329:        mb = alen * 8 - (roll + ticket + cksum + 1);
                    330:        if (mb > 0)
                    331:                magic &= (1LL << mb) - 1;
                    332:        else {
                    333:                mb ^= mb;
                    334:                magic ^= magic;
                    335:        }
                    336: 
1.3     ! misho     337:        for (i = 0, code = 0; i < array_Size(v); i++, code = 0) {
        !           338:                voucher = AIT_GET_STR(ait_getVars((array_t**) &v, i));
1.2       misho     339: 
                    340:                /* convert from voucher string to number */
                    341:                p = (u_char*) strrchr(voucher, '\0'); 
                    342:                while (p > (u_char*) voucher) {
                    343:                        p--;
                    344:                        if (*p == ' ')
                    345:                                break;
                    346:                        code *= base;
                    347:                        s = (u_char*) strchr(charset, *p);
                    348:                        if (!s) {
                    349:                                VERB(1) printf("Error:: illegal character (%c) found in %s\n", 
                    350:                                                *p, voucher);
                    351:                                printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
                    352:                                break;
                    353:                        }
                    354:                        code += (s - (u_char*) charset);
                    355:                }
                    356: 
                    357:                ll2buf(code, codebuf, clen);
                    358: 
                    359:                if (RSA_public_decrypt(clen, codebuf, clrbuf, key, RSA_NO_PADDING) == -1) {
                    360:                        VERB(1) printf("Error:: ticket[%d] RSA decrypt failed %s\n", i, 
                    361:                                        ERR_error_string(ERR_get_error(), NULL));
                    362:                        printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
                    363:                        continue;
                    364:                }
                    365: 
                    366:                buf2ll(clrbuf, &clrcode, clen);
                    367: 
                    368:                rid = clrcode & ((1 << roll) - 1);
                    369:                cnt = (clrcode >> roll) & ((1 << ticket) - 1);
                    370:                checksum = (clrcode >> (ticket + roll)) & ((1 << cksum) - 1);
                    371:                if (magic != ((clrcode >> (roll + ticket + cksum)))) {
                    372:                        VERB(1) printf("Error:: ticket[%d] invalid magic\n", i);
                    373:                        printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
                    374:                        continue;
                    375:                }
                    376:                if ((cnt + rid) % (1L << cksum) != checksum) {
                    377:                        VERB(1) printf("Error:: ticket[%d] invalid checksum\n", i);
                    378:                        printf("Ticket[%d] = %s \"%s\"\n", i, VOUCHER_ERR, voucher);
                    379:                        continue;
                    380:                }
                    381: 
                    382:                printf("Ticket[%d] = %s \"%s\" %d %d\n", i, VOUCHER_OK, voucher, rid, cnt);
                    383:        }
                    384: 
                    385:        return 0;
                    386: }
                    387: 
                    388: 
                    389: int
                    390: main(int argc, char **argv)
                    391: {
                    392:        char ch, mode = 0;
                    393:        int rid = 0, cnt = 1;
                    394:        register int i;
                    395:        RSA *key;
                    396: 
                    397:        output = stdout;
                    398:        atexit(AtExit);
                    399: 
                    400: #ifdef __NetBSD__
                    401:        srandom(getpid() ^ time(NULL));
                    402: #else
                    403:        srandomdev();
                    404: #endif
                    405: 
                    406:        while ((ch = getopt(argc, argv, "hvrtgc:o:")) != -1)
                    407:                switch (ch) {
                    408:                        case 'r':
                    409:                                mode = 1;
                    410:                                break;
                    411:                        case 't':
                    412:                                mode = 2;
                    413:                                break;
                    414:                        case 'g':
                    415:                                return NewRSA();
                    416:                        case 'c':
                    417:                                strlcpy(szConfig, optarg, sizeof szConfig);
                    418:                                break;
                    419:                        case 'o':
                    420:                                RedirOutput(optarg);
                    421:                                break;
                    422:                        case 'v':
                    423:                                Verbose++;
                    424:                                break;
                    425:                        case 'h':
                    426:                        default:
                    427:                                Usage();
                    428:                                return 1;
                    429:                }
                    430:        argc -= optind;
                    431:        argv += optind;
                    432:        if (!argc || !mode || mode > 2) {
                    433:                printf("Error:: not enough parameter or unspecified mode ...\n\n");
                    434:                Usage();
                    435:                return 1;
                    436:        }
                    437:        if (mode == 1) {
                    438:                if (argc > 1)
                    439:                        cnt = strtol(argv[1], NULL, 0);
                    440:                rid = strtol(argv[0], NULL, 0);
                    441:        } else {
                    442:                cnt = argc;
1.3     ! misho     443:                vs = ait_allocVars(cnt);
1.2       misho     444:                for (i = 0; i < argc; i++)
1.3     ! misho     445:                        AIT_SET_STR(ait_getVars(&vs, i), argv[i]);
1.2       misho     446:        }
                    447: 
                    448:        if (cfgLoadConfig(szConfig, &cfg)) {
                    449:                printf("Error:: load config #%d - %s\n", cfg_GetErrno(), cfg_GetError());
                    450:                return 3;
                    451:        } else {
                    452:                VERB(1) ShowConfig(mode, rid, cnt);
                    453:                if (CheckConfig(mode, rid, cnt)) {
                    454:                        cfgUnloadConfig(&cfg);
                    455:                        return 3;
                    456:                }
                    457:        }
                    458: 
                    459:        if (!(key = LoadKey(mode))) {
                    460:                cfgUnloadConfig(&cfg);
                    461:                return 4;
                    462:        }
                    463:        if (RSA_size(key) > VOUCHER_MAX_RSA) {
                    464:                printf("Error:: RSA key size %d bits. Max %d bits\n", 
                    465:                                RSA_size(key) * 8, VOUCHER_MAX_RSA * 8);
                    466:                RSA_free(key);
                    467:                cfgUnloadConfig(&cfg);
                    468:                return 5;
                    469:        } else
                    470:                VERB(1) printf(" + Key size %d bits\n\n", RSA_size(key) * 8);
                    471: 
                    472:        if (mode == 1) {
                    473:                if (ComputeVouchers(rid, cnt, key)) {
                    474:                        RSA_free(key);
                    475:                        cfgUnloadConfig(&cfg);
                    476:                        return 6;
                    477:                }
                    478:        } else {
                    479:                if (TestVouchers(vs, key)) {
                    480:                        RSA_free(key);
                    481:                        cfgUnloadConfig(&cfg);
                    482:                        return 6;
                    483:                }
                    484:        }
                    485: 
                    486:        RSA_free(key);
                    487:        cfgUnloadConfig(&cfg);
                    488:        return 0;
                    489: }

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