[BACK]Return to ts.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / openssl

Annotation of src/usr.bin/openssl/ts.c, Revision 1.16

1.16    ! tb          1: /* $OpenBSD: ts.c,v 1.15 2018/02/07 05:47:55 jsing Exp $ */
1.1       jsing       2: /* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
                      3:  * project 2002.
                      4:  */
                      5: /* ====================================================================
                      6:  * Copyright (c) 2001 The OpenSSL Project.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  *
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  *
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in
                     17:  *    the documentation and/or other materials provided with the
                     18:  *    distribution.
                     19:  *
                     20:  * 3. All advertising materials mentioning features or use of this
                     21:  *    software must display the following acknowledgment:
                     22:  *    "This product includes software developed by the OpenSSL Project
                     23:  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
                     24:  *
                     25:  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
                     26:  *    endorse or promote products derived from this software without
                     27:  *    prior written permission. For written permission, please contact
                     28:  *    licensing@OpenSSL.org.
                     29:  *
                     30:  * 5. Products derived from this software may not be called "OpenSSL"
                     31:  *    nor may "OpenSSL" appear in their names without prior written
                     32:  *    permission of the OpenSSL Project.
                     33:  *
                     34:  * 6. Redistributions of any form whatsoever must retain the following
                     35:  *    acknowledgment:
                     36:  *    "This product includes software developed by the OpenSSL Project
                     37:  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
                     38:  *
                     39:  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
                     40:  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     41:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     42:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
                     43:  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     44:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     45:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     46:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     47:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     48:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     49:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
                     50:  * OF THE POSSIBILITY OF SUCH DAMAGE.
                     51:  * ====================================================================
                     52:  *
                     53:  * This product includes cryptographic software written by Eric Young
                     54:  * (eay@cryptsoft.com).  This product includes software written by Tim
                     55:  * Hudson (tjh@cryptsoft.com).
                     56:  *
                     57:  */
                     58:
                     59: #include <stdio.h>
                     60: #include <stdlib.h>
                     61: #include <string.h>
                     62:
                     63: #include "apps.h"
                     64:
                     65: #include <openssl/bio.h>
                     66: #include <openssl/bn.h>
                     67: #include <openssl/err.h>
                     68: #include <openssl/pem.h>
                     69: #include <openssl/ts.h>
                     70:
                     71: /* Length of the nonce of the request in bits (must be a multiple of 8). */
                     72: #define        NONCE_LENGTH            64
                     73:
                     74: /* Macro definitions for the configuration file. */
                     75: #define        ENV_OID_FILE            "oid_file"
                     76:
                     77: /* Local function declarations. */
                     78:
                     79: static ASN1_OBJECT *txt2obj(const char *oid);
                     80: static CONF *load_config_file(const char *configfile);
                     81:
                     82: /* Query related functions. */
                     83: static int query_command(const char *data, char *digest,
                     84:     const EVP_MD * md, const char *policy, int no_nonce,
                     85:     int cert, const char *in, const char *out, int text);
                     86: static BIO *BIO_open_with_default(const char *file, const char *mode,
                     87:     FILE * default_fp);
                     88: static TS_REQ *create_query(BIO * data_bio, char *digest, const EVP_MD * md,
                     89:     const char *policy, int no_nonce, int cert);
                     90: static int create_digest(BIO * input, char *digest,
                     91:     const EVP_MD * md, unsigned char **md_value);
                     92: static ASN1_INTEGER *create_nonce(int bits);
                     93:
                     94: /* Reply related functions. */
1.6       bcook      95: static int reply_command(CONF * conf, char *section,
1.1       jsing      96:     char *queryfile, char *passin, char *inkey,
                     97:     char *signer, char *chain, const char *policy,
                     98:     char *in, int token_in, char *out, int token_out,
                     99:     int text);
                    100: static TS_RESP *read_PKCS7(BIO * in_bio);
1.6       bcook     101: static TS_RESP *create_response(CONF * conf, const char *section,
1.1       jsing     102:     char *queryfile, char *passin, char *inkey,
                    103:     char *signer, char *chain, const char *policy);
                    104: static ASN1_INTEGER *serial_cb(TS_RESP_CTX * ctx, void *data);
                    105: static ASN1_INTEGER *next_serial(const char *serialfile);
                    106: static int save_ts_serial(const char *serialfile, ASN1_INTEGER * serial);
                    107:
                    108: /* Verify related functions. */
                    109: static int verify_command(char *data, char *digest, char *queryfile,
                    110:     char *in, int token_in,
                    111:     char *ca_path, char *ca_file, char *untrusted);
                    112: static TS_VERIFY_CTX *create_verify_ctx(char *data, char *digest,
                    113:     char *queryfile,
                    114:     char *ca_path, char *ca_file,
                    115:     char *untrusted);
                    116: static X509_STORE *create_cert_store(char *ca_path, char *ca_file);
                    117: static int verify_cb(int ok, X509_STORE_CTX * ctx);
                    118:
                    119: int
                    120: ts_main(int argc, char **argv)
                    121: {
                    122:        int ret = 1;
                    123:        char *configfile = NULL;
                    124:        char *section = NULL;
                    125:        CONF *conf = NULL;
                    126:        enum mode {
                    127:                CMD_NONE, CMD_QUERY, CMD_REPLY, CMD_VERIFY
                    128:        } mode = CMD_NONE;
                    129:        char *data = NULL;
                    130:        char *digest = NULL;
                    131:        const EVP_MD *md = NULL;
                    132:        char *policy = NULL;
                    133:        int no_nonce = 0;
                    134:        int cert = 0;
                    135:        char *in = NULL;
                    136:        char *out = NULL;
                    137:        int text = 0;
                    138:        char *queryfile = NULL;
                    139:        char *passin = NULL;    /* Password source. */
                    140:        char *password = NULL;  /* Password itself. */
                    141:        char *inkey = NULL;
                    142:        char *signer = NULL;
                    143:        char *chain = NULL;
                    144:        char *ca_path = NULL;
                    145:        char *ca_file = NULL;
                    146:        char *untrusted = NULL;
                    147:        /* Input is ContentInfo instead of TimeStampResp. */
                    148:        int token_in = 0;
                    149:        /* Output is ContentInfo instead of TimeStampResp. */
                    150:        int token_out = 0;
1.11      doug      151:
                    152:        if (single_execution) {
1.14      deraadt   153:                if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
1.11      doug      154:                        perror("pledge");
1.13      doug      155:                        exit(1);
                    156:                }
1.11      doug      157:        }
1.1       jsing     158:
                    159:        for (argc--, argv++; argc > 0; argc--, argv++) {
                    160:                if (strcmp(*argv, "-config") == 0) {
                    161:                        if (argc-- < 1)
                    162:                                goto usage;
                    163:                        configfile = *++argv;
                    164:                } else if (strcmp(*argv, "-section") == 0) {
                    165:                        if (argc-- < 1)
                    166:                                goto usage;
                    167:                        section = *++argv;
                    168:                } else if (strcmp(*argv, "-query") == 0) {
                    169:                        if (mode != CMD_NONE)
                    170:                                goto usage;
                    171:                        mode = CMD_QUERY;
                    172:                } else if (strcmp(*argv, "-data") == 0) {
                    173:                        if (argc-- < 1)
                    174:                                goto usage;
                    175:                        data = *++argv;
                    176:                } else if (strcmp(*argv, "-digest") == 0) {
                    177:                        if (argc-- < 1)
                    178:                                goto usage;
                    179:                        digest = *++argv;
                    180:                } else if (strcmp(*argv, "-policy") == 0) {
                    181:                        if (argc-- < 1)
                    182:                                goto usage;
                    183:                        policy = *++argv;
                    184:                } else if (strcmp(*argv, "-no_nonce") == 0) {
                    185:                        no_nonce = 1;
                    186:                } else if (strcmp(*argv, "-cert") == 0) {
                    187:                        cert = 1;
                    188:                } else if (strcmp(*argv, "-in") == 0) {
                    189:                        if (argc-- < 1)
                    190:                                goto usage;
                    191:                        in = *++argv;
                    192:                } else if (strcmp(*argv, "-token_in") == 0) {
                    193:                        token_in = 1;
                    194:                } else if (strcmp(*argv, "-out") == 0) {
                    195:                        if (argc-- < 1)
                    196:                                goto usage;
                    197:                        out = *++argv;
                    198:                } else if (strcmp(*argv, "-token_out") == 0) {
                    199:                        token_out = 1;
                    200:                } else if (strcmp(*argv, "-text") == 0) {
                    201:                        text = 1;
                    202:                } else if (strcmp(*argv, "-reply") == 0) {
                    203:                        if (mode != CMD_NONE)
                    204:                                goto usage;
                    205:                        mode = CMD_REPLY;
                    206:                } else if (strcmp(*argv, "-queryfile") == 0) {
                    207:                        if (argc-- < 1)
                    208:                                goto usage;
                    209:                        queryfile = *++argv;
                    210:                } else if (strcmp(*argv, "-passin") == 0) {
                    211:                        if (argc-- < 1)
                    212:                                goto usage;
                    213:                        passin = *++argv;
                    214:                } else if (strcmp(*argv, "-inkey") == 0) {
                    215:                        if (argc-- < 1)
                    216:                                goto usage;
                    217:                        inkey = *++argv;
                    218:                } else if (strcmp(*argv, "-signer") == 0) {
                    219:                        if (argc-- < 1)
                    220:                                goto usage;
                    221:                        signer = *++argv;
                    222:                } else if (strcmp(*argv, "-chain") == 0) {
                    223:                        if (argc-- < 1)
                    224:                                goto usage;
                    225:                        chain = *++argv;
                    226:                } else if (strcmp(*argv, "-verify") == 0) {
                    227:                        if (mode != CMD_NONE)
                    228:                                goto usage;
                    229:                        mode = CMD_VERIFY;
                    230:                } else if (strcmp(*argv, "-CApath") == 0) {
                    231:                        if (argc-- < 1)
                    232:                                goto usage;
                    233:                        ca_path = *++argv;
                    234:                } else if (strcmp(*argv, "-CAfile") == 0) {
                    235:                        if (argc-- < 1)
                    236:                                goto usage;
                    237:                        ca_file = *++argv;
                    238:                } else if (strcmp(*argv, "-untrusted") == 0) {
                    239:                        if (argc-- < 1)
                    240:                                goto usage;
                    241:                        untrusted = *++argv;
                    242:                } else if ((md = EVP_get_digestbyname(*argv + 1)) != NULL) {
                    243:                        /* empty. */
                    244:                } else
                    245:                        goto usage;
                    246:        }
                    247:
                    248:        /* Get the password if required. */
                    249:        if (mode == CMD_REPLY && passin &&
                    250:            !app_passwd(bio_err, passin, NULL, &password, NULL)) {
                    251:                BIO_printf(bio_err, "Error getting password.\n");
                    252:                goto cleanup;
                    253:        }
                    254:        /*
                    255:         * Check consistency of parameters and execute the appropriate
                    256:         * function.
                    257:         */
                    258:        switch (mode) {
                    259:        case CMD_NONE:
                    260:                goto usage;
                    261:        case CMD_QUERY:
                    262:                /*
                    263:                 * Data file and message imprint cannot be specified at the
                    264:                 * same time.
                    265:                 */
                    266:                ret = data != NULL && digest != NULL;
                    267:                if (ret)
                    268:                        goto usage;
                    269:                /* Load the config file for possible policy OIDs. */
                    270:                conf = load_config_file(configfile);
                    271:                ret = !query_command(data, digest, md, policy, no_nonce, cert,
                    272:                    in, out, text);
                    273:                break;
                    274:        case CMD_REPLY:
                    275:                conf = load_config_file(configfile);
                    276:                if (in == NULL) {
                    277:                        ret = !(queryfile != NULL && conf != NULL && !token_in);
                    278:                        if (ret)
                    279:                                goto usage;
                    280:                } else {
                    281:                        /* 'in' and 'queryfile' are exclusive. */
                    282:                        ret = !(queryfile == NULL);
                    283:                        if (ret)
                    284:                                goto usage;
                    285:                }
                    286:
1.6       bcook     287:                ret = !reply_command(conf, section, queryfile,
1.1       jsing     288:                    password, inkey, signer, chain, policy,
                    289:                    in, token_in, out, token_out, text);
                    290:                break;
                    291:        case CMD_VERIFY:
                    292:                ret = !(((queryfile && !data && !digest) ||
                    293:                    (!queryfile && data && !digest) ||
                    294:                    (!queryfile && !data && digest)) && in != NULL);
                    295:                if (ret)
                    296:                        goto usage;
                    297:
                    298:                ret = !verify_command(data, digest, queryfile, in, token_in,
                    299:                    ca_path, ca_file, untrusted);
                    300:        }
                    301:
                    302:        goto cleanup;
                    303:
1.15      jsing     304:  usage:
1.1       jsing     305:        BIO_printf(bio_err, "usage:\n"
                    306:            "ts -query [-config configfile] "
                    307:            "[-data file_to_hash] [-digest digest_bytes]"
1.10      bcook     308:            "[-md4|-md5|-sha1|-ripemd160] "
1.1       jsing     309:            "[-policy object_id] [-no_nonce] [-cert] "
                    310:            "[-in request.tsq] [-out request.tsq] [-text]\n");
                    311:        BIO_printf(bio_err, "or\n"
                    312:            "ts -reply [-config configfile] [-section tsa_section] "
                    313:            "[-queryfile request.tsq] [-passin password] "
                    314:            "[-signer tsa_cert.pem] [-inkey private_key.pem] "
                    315:            "[-chain certs_file.pem] [-policy object_id] "
                    316:            "[-in response.tsr] [-token_in] "
1.6       bcook     317:            "[-out response.tsr] [-token_out] [-text]\n");
1.1       jsing     318:        BIO_printf(bio_err, "or\n"
                    319:            "ts -verify [-data file_to_hash] [-digest digest_bytes] "
                    320:            "[-queryfile request.tsq] "
                    321:            "-in response.tsr [-token_in] "
                    322:            "-CApath ca_path -CAfile ca_file.pem "
                    323:            "-untrusted cert_file.pem\n");
                    324:
1.15      jsing     325:  cleanup:
1.1       jsing     326:        /* Clean up. */
                    327:        NCONF_free(conf);
                    328:        free(password);
                    329:        OBJ_cleanup();
                    330:
                    331:        return (ret);
                    332: }
                    333:
                    334: /*
                    335:  * Configuration file-related function definitions.
                    336:  */
                    337:
                    338: static ASN1_OBJECT *
                    339: txt2obj(const char *oid)
                    340: {
                    341:        ASN1_OBJECT *oid_obj = NULL;
                    342:
                    343:        if (!(oid_obj = OBJ_txt2obj(oid, 0)))
                    344:                BIO_printf(bio_err, "cannot convert %s to OID\n", oid);
                    345:
                    346:        return oid_obj;
                    347: }
                    348:
                    349: static CONF *
                    350: load_config_file(const char *configfile)
                    351: {
                    352:        CONF *conf = NULL;
                    353:        long errorline = -1;
                    354:
                    355:        if (!configfile)
                    356:                configfile = getenv("OPENSSL_CONF");
                    357:
                    358:        if (configfile &&
                    359:            (!(conf = NCONF_new(NULL)) ||
                    360:            NCONF_load(conf, configfile, &errorline) <= 0)) {
                    361:                if (errorline <= 0)
                    362:                        BIO_printf(bio_err, "error loading the config file "
                    363:                            "'%s'\n", configfile);
                    364:                else
                    365:                        BIO_printf(bio_err, "error on line %ld of config file "
                    366:                            "'%s'\n", errorline, configfile);
                    367:        }
                    368:        if (conf != NULL) {
                    369:                const char *p;
                    370:
                    371:                BIO_printf(bio_err, "Using configuration from %s\n",
                    372:                    configfile);
                    373:                p = NCONF_get_string(conf, NULL, ENV_OID_FILE);
                    374:                if (p != NULL) {
                    375:                        BIO *oid_bio = BIO_new_file(p, "r");
                    376:                        if (!oid_bio)
                    377:                                ERR_print_errors(bio_err);
                    378:                        else {
                    379:                                OBJ_create_objects(oid_bio);
                    380:                                BIO_free_all(oid_bio);
                    381:                        }
                    382:                } else
                    383:                        ERR_clear_error();
                    384:                if (!add_oid_section(bio_err, conf))
                    385:                        ERR_print_errors(bio_err);
                    386:        }
                    387:        return conf;
                    388: }
                    389:
                    390: /*
                    391:  * Query-related method definitions.
                    392:  */
                    393:
                    394: static int
                    395: query_command(const char *data, char *digest, const EVP_MD * md,
                    396:     const char *policy, int no_nonce, int cert, const char *in,
                    397:     const char *out, int text)
                    398: {
                    399:        int ret = 0;
                    400:        TS_REQ *query = NULL;
                    401:        BIO *in_bio = NULL;
                    402:        BIO *data_bio = NULL;
                    403:        BIO *out_bio = NULL;
                    404:
                    405:        /* Build query object either from file or from scratch. */
                    406:        if (in != NULL) {
                    407:                if ((in_bio = BIO_new_file(in, "rb")) == NULL)
                    408:                        goto end;
                    409:                query = d2i_TS_REQ_bio(in_bio, NULL);
                    410:        } else {
                    411:                /* Open the file if no explicit digest bytes were specified. */
                    412:                if (!digest &&
                    413:                    !(data_bio = BIO_open_with_default(data, "rb", stdin)))
                    414:                        goto end;
                    415:                /* Creating the query object. */
                    416:                query = create_query(data_bio, digest, md,
                    417:                    policy, no_nonce, cert);
                    418:                /* Saving the random number generator state. */
                    419:        }
                    420:        if (query == NULL)
                    421:                goto end;
                    422:
                    423:        /* Write query either in ASN.1 or in text format. */
                    424:        if ((out_bio = BIO_open_with_default(out, "wb", stdout)) == NULL)
                    425:                goto end;
                    426:        if (text) {
                    427:                /* Text output. */
                    428:                if (!TS_REQ_print_bio(out_bio, query))
                    429:                        goto end;
                    430:        } else {
                    431:                /* ASN.1 output. */
                    432:                if (!i2d_TS_REQ_bio(out_bio, query))
                    433:                        goto end;
                    434:        }
                    435:
                    436:        ret = 1;
                    437:
1.15      jsing     438:  end:
1.1       jsing     439:        ERR_print_errors(bio_err);
                    440:
                    441:        /* Clean up. */
                    442:        BIO_free_all(in_bio);
                    443:        BIO_free_all(data_bio);
                    444:        BIO_free_all(out_bio);
                    445:        TS_REQ_free(query);
                    446:
                    447:        return ret;
                    448: }
                    449:
                    450: static BIO *
                    451: BIO_open_with_default(const char *file, const char *mode, FILE * default_fp)
                    452: {
                    453:        return file == NULL ? BIO_new_fp(default_fp, BIO_NOCLOSE) :
                    454:            BIO_new_file(file, mode);
                    455: }
                    456:
                    457: static TS_REQ *
                    458: create_query(BIO * data_bio, char *digest, const EVP_MD * md,
                    459:     const char *policy, int no_nonce, int cert)
                    460: {
                    461:        int ret = 0;
                    462:        TS_REQ *ts_req = NULL;
                    463:        int len;
                    464:        TS_MSG_IMPRINT *msg_imprint = NULL;
                    465:        X509_ALGOR *algo = NULL;
                    466:        unsigned char *data = NULL;
                    467:        ASN1_OBJECT *policy_obj = NULL;
                    468:        ASN1_INTEGER *nonce_asn1 = NULL;
                    469:
                    470:        /* Setting default message digest. */
                    471:        if (!md && !(md = EVP_get_digestbyname("sha1")))
                    472:                goto err;
                    473:
                    474:        /* Creating request object. */
                    475:        if (!(ts_req = TS_REQ_new()))
                    476:                goto err;
                    477:
                    478:        /* Setting version. */
                    479:        if (!TS_REQ_set_version(ts_req, 1))
                    480:                goto err;
                    481:
                    482:        /* Creating and adding MSG_IMPRINT object. */
                    483:        if (!(msg_imprint = TS_MSG_IMPRINT_new()))
                    484:                goto err;
                    485:
                    486:        /* Adding algorithm. */
                    487:        if (!(algo = X509_ALGOR_new()))
                    488:                goto err;
                    489:        if (!(algo->algorithm = OBJ_nid2obj(EVP_MD_type(md))))
                    490:                goto err;
                    491:        if (!(algo->parameter = ASN1_TYPE_new()))
                    492:                goto err;
                    493:        algo->parameter->type = V_ASN1_NULL;
                    494:        if (!TS_MSG_IMPRINT_set_algo(msg_imprint, algo))
                    495:                goto err;
                    496:
                    497:        /* Adding message digest. */
                    498:        if ((len = create_digest(data_bio, digest, md, &data)) == 0)
                    499:                goto err;
                    500:        if (!TS_MSG_IMPRINT_set_msg(msg_imprint, data, len))
                    501:                goto err;
                    502:
                    503:        if (!TS_REQ_set_msg_imprint(ts_req, msg_imprint))
                    504:                goto err;
                    505:
                    506:        /* Setting policy if requested. */
                    507:        if (policy && !(policy_obj = txt2obj(policy)))
                    508:                goto err;
                    509:        if (policy_obj && !TS_REQ_set_policy_id(ts_req, policy_obj))
                    510:                goto err;
                    511:
                    512:        /* Setting nonce if requested. */
                    513:        if (!no_nonce && !(nonce_asn1 = create_nonce(NONCE_LENGTH)))
                    514:                goto err;
                    515:        if (nonce_asn1 && !TS_REQ_set_nonce(ts_req, nonce_asn1))
                    516:                goto err;
                    517:
                    518:        /* Setting certificate request flag if requested. */
                    519:        if (!TS_REQ_set_cert_req(ts_req, cert))
                    520:                goto err;
                    521:
                    522:        ret = 1;
                    523:
1.15      jsing     524:  err:
1.1       jsing     525:        if (!ret) {
                    526:                TS_REQ_free(ts_req);
                    527:                ts_req = NULL;
                    528:                BIO_printf(bio_err, "could not create query\n");
                    529:        }
                    530:        TS_MSG_IMPRINT_free(msg_imprint);
                    531:        X509_ALGOR_free(algo);
                    532:        free(data);
                    533:        ASN1_OBJECT_free(policy_obj);
                    534:        ASN1_INTEGER_free(nonce_asn1);
                    535:
                    536:        return ts_req;
                    537: }
                    538:
                    539: static int
                    540: create_digest(BIO * input, char *digest, const EVP_MD * md,
                    541:     unsigned char **md_value)
                    542: {
                    543:        int md_value_len;
                    544:
                    545:        md_value_len = EVP_MD_size(md);
                    546:        if (md_value_len < 0)
                    547:                goto err;
                    548:        if (input) {
                    549:                /* Digest must be computed from an input file. */
1.16    ! tb        550:                EVP_MD_CTX *md_ctx;
1.1       jsing     551:                unsigned char buffer[4096];
                    552:                int length;
                    553:
                    554:                *md_value = malloc(md_value_len);
                    555:                if (*md_value == 0)
                    556:                        goto err;
                    557:
1.16    ! tb        558:                if ((md_ctx = EVP_MD_CTX_new()) == NULL)
        !           559:                        goto err;
        !           560:
        !           561:                EVP_DigestInit(md_ctx, md);
1.1       jsing     562:                while ((length = BIO_read(input, buffer, sizeof(buffer))) > 0) {
1.16    ! tb        563:                        EVP_DigestUpdate(md_ctx, buffer, length);
1.1       jsing     564:                }
1.16    ! tb        565:                EVP_DigestFinal(md_ctx, *md_value, NULL);
        !           566:
        !           567:                EVP_MD_CTX_free(md_ctx);
1.1       jsing     568:        } else {
                    569:                /* Digest bytes are specified with digest. */
                    570:                long digest_len;
                    571:                *md_value = string_to_hex(digest, &digest_len);
                    572:                if (!*md_value || md_value_len != digest_len) {
                    573:                        free(*md_value);
                    574:                        *md_value = NULL;
                    575:                        BIO_printf(bio_err, "bad digest, %d bytes "
                    576:                            "must be specified\n", md_value_len);
                    577:                        goto err;
                    578:                }
                    579:        }
                    580:
                    581:        return md_value_len;
1.15      jsing     582:  err:
1.1       jsing     583:        return 0;
                    584: }
                    585:
                    586: static ASN1_INTEGER *
                    587: create_nonce(int bits)
                    588: {
                    589:        unsigned char buf[20];
                    590:        ASN1_INTEGER *nonce = NULL;
                    591:        int len = (bits - 1) / 8 + 1;
                    592:        int i;
                    593:
                    594:        /* Generating random byte sequence. */
                    595:        if (len > (int) sizeof(buf))
                    596:                goto err;
1.3       jsing     597:        arc4random_buf(buf, len);
1.1       jsing     598:
                    599:        /* Find the first non-zero byte and creating ASN1_INTEGER object. */
                    600:        for (i = 0; i < len && !buf[i]; ++i)
                    601:                ;
                    602:        if (!(nonce = ASN1_INTEGER_new()))
                    603:                goto err;
                    604:        free(nonce->data);
                    605:        /* Allocate at least one byte. */
                    606:        nonce->length = len - i;
                    607:        if (!(nonce->data = malloc(nonce->length + 1)))
                    608:                goto err;
                    609:        memcpy(nonce->data, buf + i, nonce->length);
                    610:
                    611:        return nonce;
                    612:
1.15      jsing     613:  err:
1.1       jsing     614:        BIO_printf(bio_err, "could not create nonce\n");
                    615:        ASN1_INTEGER_free(nonce);
                    616:        return NULL;
                    617: }
                    618: /*
                    619:  * Reply-related method definitions.
                    620:  */
                    621:
                    622: static int
1.6       bcook     623: reply_command(CONF * conf, char *section, char *queryfile,
1.1       jsing     624:     char *passin, char *inkey, char *signer, char *chain, const char *policy,
                    625:     char *in, int token_in, char *out, int token_out, int text)
                    626: {
                    627:        int ret = 0;
                    628:        TS_RESP *response = NULL;
                    629:        BIO *in_bio = NULL;
                    630:        BIO *query_bio = NULL;
                    631:        BIO *inkey_bio = NULL;
                    632:        BIO *signer_bio = NULL;
                    633:        BIO *out_bio = NULL;
                    634:
                    635:        /* Build response object either from response or query. */
                    636:        if (in != NULL) {
                    637:                if ((in_bio = BIO_new_file(in, "rb")) == NULL)
                    638:                        goto end;
                    639:                if (token_in) {
                    640:                        /*
                    641:                         * We have a ContentInfo (PKCS7) object, add
                    642:                         * 'granted' status info around it.
                    643:                         */
                    644:                        response = read_PKCS7(in_bio);
                    645:                } else {
                    646:                        /* We have a ready-made TS_RESP object. */
                    647:                        response = d2i_TS_RESP_bio(in_bio, NULL);
                    648:                }
                    649:        } else {
1.6       bcook     650:                response = create_response(conf, section, queryfile,
1.1       jsing     651:                    passin, inkey, signer, chain,
                    652:                    policy);
                    653:                if (response)
                    654:                        BIO_printf(bio_err, "Response has been generated.\n");
                    655:                else
                    656:                        BIO_printf(bio_err, "Response is not generated.\n");
                    657:        }
                    658:        if (response == NULL)
                    659:                goto end;
                    660:
                    661:        /* Write response either in ASN.1 or text format. */
                    662:        if ((out_bio = BIO_open_with_default(out, "wb", stdout)) == NULL)
                    663:                goto end;
                    664:        if (text) {
                    665:                /* Text output. */
                    666:                if (token_out) {
                    667:                        TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response);
                    668:                        if (!TS_TST_INFO_print_bio(out_bio, tst_info))
                    669:                                goto end;
                    670:                } else {
                    671:                        if (!TS_RESP_print_bio(out_bio, response))
                    672:                                goto end;
                    673:                }
                    674:        } else {
                    675:                /* ASN.1 DER output. */
                    676:                if (token_out) {
                    677:                        PKCS7 *token = TS_RESP_get_token(response);
                    678:                        if (!i2d_PKCS7_bio(out_bio, token))
                    679:                                goto end;
                    680:                } else {
                    681:                        if (!i2d_TS_RESP_bio(out_bio, response))
                    682:                                goto end;
                    683:                }
                    684:        }
                    685:
                    686:        ret = 1;
                    687:
1.15      jsing     688:  end:
1.1       jsing     689:        ERR_print_errors(bio_err);
                    690:
                    691:        /* Clean up. */
                    692:        BIO_free_all(in_bio);
                    693:        BIO_free_all(query_bio);
                    694:        BIO_free_all(inkey_bio);
                    695:        BIO_free_all(signer_bio);
                    696:        BIO_free_all(out_bio);
                    697:        TS_RESP_free(response);
                    698:
                    699:        return ret;
                    700: }
                    701:
                    702: /* Reads a PKCS7 token and adds default 'granted' status info to it. */
                    703: static TS_RESP *
                    704: read_PKCS7(BIO * in_bio)
                    705: {
                    706:        int ret = 0;
                    707:        PKCS7 *token = NULL;
                    708:        TS_TST_INFO *tst_info = NULL;
                    709:        TS_RESP *resp = NULL;
                    710:        TS_STATUS_INFO *si = NULL;
                    711:
                    712:        /* Read PKCS7 object and extract the signed time stamp info. */
                    713:        if (!(token = d2i_PKCS7_bio(in_bio, NULL)))
                    714:                goto end;
                    715:        if (!(tst_info = PKCS7_to_TS_TST_INFO(token)))
                    716:                goto end;
                    717:
                    718:        /* Creating response object. */
                    719:        if (!(resp = TS_RESP_new()))
                    720:                goto end;
                    721:
                    722:        /* Create granted status info. */
                    723:        if (!(si = TS_STATUS_INFO_new()))
                    724:                goto end;
                    725:        if (!(ASN1_INTEGER_set(si->status, TS_STATUS_GRANTED)))
                    726:                goto end;
                    727:        if (!TS_RESP_set_status_info(resp, si))
                    728:                goto end;
                    729:
                    730:        /* Setting encapsulated token. */
                    731:        TS_RESP_set_tst_info(resp, token, tst_info);
                    732:        token = NULL;           /* Ownership is lost. */
                    733:        tst_info = NULL;        /* Ownership is lost. */
                    734:
                    735:        ret = 1;
1.15      jsing     736:  end:
1.1       jsing     737:        PKCS7_free(token);
                    738:        TS_TST_INFO_free(tst_info);
                    739:        if (!ret) {
                    740:                TS_RESP_free(resp);
                    741:                resp = NULL;
                    742:        }
                    743:        TS_STATUS_INFO_free(si);
                    744:        return resp;
                    745: }
                    746:
                    747: static TS_RESP *
1.6       bcook     748: create_response(CONF * conf, const char *section,
1.1       jsing     749:     char *queryfile, char *passin, char *inkey,
                    750:     char *signer, char *chain, const char *policy)
                    751: {
                    752:        int ret = 0;
                    753:        TS_RESP *response = NULL;
                    754:        BIO *query_bio = NULL;
                    755:        TS_RESP_CTX *resp_ctx = NULL;
                    756:
                    757:        if (!(query_bio = BIO_new_file(queryfile, "rb")))
                    758:                goto end;
                    759:
                    760:        /* Getting TSA configuration section. */
                    761:        if (!(section = TS_CONF_get_tsa_section(conf, section)))
                    762:                goto end;
                    763:
                    764:        /* Setting up response generation context. */
                    765:        if (!(resp_ctx = TS_RESP_CTX_new()))
                    766:                goto end;
                    767:
                    768:        /* Setting serial number provider callback. */
                    769:        if (!TS_CONF_set_serial(conf, section, serial_cb, resp_ctx))
                    770:                goto end;
                    771:
                    772:        /* Setting TSA signer certificate. */
                    773:        if (!TS_CONF_set_signer_cert(conf, section, signer, resp_ctx))
                    774:                goto end;
                    775:
                    776:        /* Setting TSA signer certificate chain. */
                    777:        if (!TS_CONF_set_certs(conf, section, chain, resp_ctx))
                    778:                goto end;
                    779:
                    780:        /* Setting TSA signer private key. */
                    781:        if (!TS_CONF_set_signer_key(conf, section, inkey, passin, resp_ctx))
                    782:                goto end;
                    783:
                    784:        /* Setting default policy OID. */
                    785:        if (!TS_CONF_set_def_policy(conf, section, policy, resp_ctx))
                    786:                goto end;
                    787:
                    788:        /* Setting acceptable policy OIDs. */
                    789:        if (!TS_CONF_set_policies(conf, section, resp_ctx))
                    790:                goto end;
                    791:
                    792:        /* Setting the acceptable one-way hash algorithms. */
                    793:        if (!TS_CONF_set_digests(conf, section, resp_ctx))
                    794:                goto end;
                    795:
                    796:        /* Setting guaranteed time stamp accuracy. */
                    797:        if (!TS_CONF_set_accuracy(conf, section, resp_ctx))
                    798:                goto end;
                    799:
                    800:        /* Setting the precision of the time. */
                    801:        if (!TS_CONF_set_clock_precision_digits(conf, section, resp_ctx))
                    802:                goto end;
                    803:
                    804:        /* Setting the ordering flaf if requested. */
                    805:        if (!TS_CONF_set_ordering(conf, section, resp_ctx))
                    806:                goto end;
                    807:
                    808:        /* Setting the TSA name required flag if requested. */
                    809:        if (!TS_CONF_set_tsa_name(conf, section, resp_ctx))
                    810:                goto end;
                    811:
                    812:        /* Setting the ESS cert id chain flag if requested. */
                    813:        if (!TS_CONF_set_ess_cert_id_chain(conf, section, resp_ctx))
                    814:                goto end;
                    815:
                    816:        /* Creating the response. */
                    817:        if (!(response = TS_RESP_create_response(resp_ctx, query_bio)))
                    818:                goto end;
                    819:
                    820:        ret = 1;
1.15      jsing     821:  end:
1.1       jsing     822:        if (!ret) {
                    823:                TS_RESP_free(response);
                    824:                response = NULL;
                    825:        }
                    826:        TS_RESP_CTX_free(resp_ctx);
                    827:        BIO_free_all(query_bio);
                    828:
                    829:        return response;
                    830: }
                    831:
                    832: static ASN1_INTEGER *
                    833: serial_cb(TS_RESP_CTX * ctx, void *data)
                    834: {
                    835:        const char *serial_file = (const char *) data;
                    836:        ASN1_INTEGER *serial = next_serial(serial_file);
                    837:
                    838:        if (!serial) {
                    839:                TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
                    840:                    "Error during serial number "
                    841:                    "generation.");
                    842:                TS_RESP_CTX_add_failure_info(ctx,
                    843:                    TS_INFO_ADD_INFO_NOT_AVAILABLE);
                    844:        } else
                    845:                save_ts_serial(serial_file, serial);
                    846:
                    847:        return serial;
                    848: }
                    849:
                    850: static ASN1_INTEGER *
                    851: next_serial(const char *serialfile)
                    852: {
                    853:        int ret = 0;
                    854:        BIO *in = NULL;
                    855:        ASN1_INTEGER *serial = NULL;
                    856:        BIGNUM *bn = NULL;
                    857:
                    858:        if (!(serial = ASN1_INTEGER_new()))
                    859:                goto err;
                    860:
                    861:        if (!(in = BIO_new_file(serialfile, "r"))) {
                    862:                ERR_clear_error();
                    863:                BIO_printf(bio_err, "Warning: could not open file %s for "
                    864:                    "reading, using serial number: 1\n", serialfile);
                    865:                if (!ASN1_INTEGER_set(serial, 1))
                    866:                        goto err;
                    867:        } else {
                    868:                char buf[1024];
                    869:                if (!a2i_ASN1_INTEGER(in, serial, buf, sizeof(buf))) {
                    870:                        BIO_printf(bio_err, "unable to load number from %s\n",
                    871:                            serialfile);
                    872:                        goto err;
                    873:                }
                    874:                if (!(bn = ASN1_INTEGER_to_BN(serial, NULL)))
                    875:                        goto err;
                    876:                ASN1_INTEGER_free(serial);
                    877:                serial = NULL;
                    878:                if (!BN_add_word(bn, 1))
                    879:                        goto err;
                    880:                if (!(serial = BN_to_ASN1_INTEGER(bn, NULL)))
                    881:                        goto err;
                    882:        }
                    883:        ret = 1;
1.15      jsing     884:  err:
1.1       jsing     885:        if (!ret) {
                    886:                ASN1_INTEGER_free(serial);
                    887:                serial = NULL;
                    888:        }
                    889:        BIO_free_all(in);
                    890:        BN_free(bn);
                    891:        return serial;
                    892: }
                    893:
                    894: static int
                    895: save_ts_serial(const char *serialfile, ASN1_INTEGER * serial)
                    896: {
                    897:        int ret = 0;
                    898:        BIO *out = NULL;
                    899:
                    900:        if (!(out = BIO_new_file(serialfile, "w")))
                    901:                goto err;
                    902:        if (i2a_ASN1_INTEGER(out, serial) <= 0)
                    903:                goto err;
                    904:        if (BIO_puts(out, "\n") <= 0)
                    905:                goto err;
                    906:        ret = 1;
1.15      jsing     907:  err:
1.1       jsing     908:        if (!ret)
                    909:                BIO_printf(bio_err, "could not save serial number to %s\n",
                    910:                    serialfile);
                    911:        BIO_free_all(out);
                    912:        return ret;
                    913: }
                    914:
                    915: /*
                    916:  * Verify-related method definitions.
                    917:  */
                    918:
                    919: static int
                    920: verify_command(char *data, char *digest, char *queryfile, char *in,
                    921:     int token_in, char *ca_path, char *ca_file, char *untrusted)
                    922: {
                    923:        BIO *in_bio = NULL;
                    924:        PKCS7 *token = NULL;
                    925:        TS_RESP *response = NULL;
                    926:        TS_VERIFY_CTX *verify_ctx = NULL;
                    927:        int ret = 0;
                    928:
                    929:        /* Decode the token (PKCS7) or response (TS_RESP) files. */
                    930:        if (!(in_bio = BIO_new_file(in, "rb")))
                    931:                goto end;
                    932:        if (token_in) {
                    933:                if (!(token = d2i_PKCS7_bio(in_bio, NULL)))
                    934:                        goto end;
                    935:        } else {
                    936:                if (!(response = d2i_TS_RESP_bio(in_bio, NULL)))
                    937:                        goto end;
                    938:        }
                    939:
                    940:        if (!(verify_ctx = create_verify_ctx(data, digest, queryfile,
                    941:            ca_path, ca_file, untrusted)))
                    942:                goto end;
                    943:
                    944:        /* Checking the token or response against the request. */
                    945:        ret = token_in ?
                    946:            TS_RESP_verify_token(verify_ctx, token) :
                    947:            TS_RESP_verify_response(verify_ctx, response);
                    948:
1.15      jsing     949:  end:
1.1       jsing     950:        printf("Verification: ");
                    951:        if (ret)
                    952:                printf("OK\n");
                    953:        else {
                    954:                printf("FAILED\n");
                    955:                /* Print errors, if there are any. */
                    956:                ERR_print_errors(bio_err);
                    957:        }
                    958:
                    959:        /* Clean up. */
                    960:        BIO_free_all(in_bio);
                    961:        PKCS7_free(token);
                    962:        TS_RESP_free(response);
                    963:        TS_VERIFY_CTX_free(verify_ctx);
                    964:        return ret;
                    965: }
                    966:
                    967: static TS_VERIFY_CTX *
                    968: create_verify_ctx(char *data, char *digest, char *queryfile, char *ca_path,
                    969:     char *ca_file, char *untrusted)
                    970: {
                    971:        TS_VERIFY_CTX *ctx = NULL;
                    972:        BIO *input = NULL;
                    973:        TS_REQ *request = NULL;
                    974:        int ret = 0;
                    975:
                    976:        if (data != NULL || digest != NULL) {
                    977:                if (!(ctx = TS_VERIFY_CTX_new()))
                    978:                        goto err;
                    979:                ctx->flags = TS_VFY_VERSION | TS_VFY_SIGNER;
                    980:                if (data != NULL) {
                    981:                        ctx->flags |= TS_VFY_DATA;
                    982:                        if (!(ctx->data = BIO_new_file(data, "rb")))
                    983:                                goto err;
                    984:                } else if (digest != NULL) {
                    985:                        long imprint_len;
                    986:                        ctx->flags |= TS_VFY_IMPRINT;
                    987:                        if (!(ctx->imprint = string_to_hex(digest,
                    988:                                    &imprint_len))) {
                    989:                                BIO_printf(bio_err, "invalid digest string\n");
                    990:                                goto err;
                    991:                        }
                    992:                        ctx->imprint_len = imprint_len;
                    993:                }
                    994:        } else if (queryfile != NULL) {
                    995:                /*
                    996:                 * The request has just to be read, decoded and converted to
                    997:                 * a verify context object.
                    998:                 */
                    999:                if (!(input = BIO_new_file(queryfile, "rb")))
                   1000:                        goto err;
                   1001:                if (!(request = d2i_TS_REQ_bio(input, NULL)))
                   1002:                        goto err;
                   1003:                if (!(ctx = TS_REQ_to_TS_VERIFY_CTX(request, NULL)))
                   1004:                        goto err;
                   1005:        } else
                   1006:                return NULL;
                   1007:
                   1008:        /* Add the signature verification flag and arguments. */
                   1009:        ctx->flags |= TS_VFY_SIGNATURE;
                   1010:
                   1011:        /* Initialising the X509_STORE object. */
                   1012:        if (!(ctx->store = create_cert_store(ca_path, ca_file)))
                   1013:                goto err;
                   1014:
                   1015:        /* Loading untrusted certificates. */
                   1016:        if (untrusted && !(ctx->certs = TS_CONF_load_certs(untrusted)))
                   1017:                goto err;
                   1018:
                   1019:        ret = 1;
1.15      jsing    1020:  err:
1.1       jsing    1021:        if (!ret) {
                   1022:                TS_VERIFY_CTX_free(ctx);
                   1023:                ctx = NULL;
                   1024:        }
                   1025:        BIO_free_all(input);
                   1026:        TS_REQ_free(request);
                   1027:        return ctx;
                   1028: }
                   1029:
                   1030: static X509_STORE *
                   1031: create_cert_store(char *ca_path, char *ca_file)
                   1032: {
                   1033:        X509_STORE *cert_ctx = NULL;
                   1034:        X509_LOOKUP *lookup = NULL;
                   1035:        int i;
                   1036:
                   1037:        /* Creating the X509_STORE object. */
                   1038:        cert_ctx = X509_STORE_new();
                   1039:
                   1040:        /* Setting the callback for certificate chain verification. */
                   1041:        X509_STORE_set_verify_cb(cert_ctx, verify_cb);
                   1042:
                   1043:        /* Adding a trusted certificate directory source. */
                   1044:        if (ca_path) {
                   1045:                lookup = X509_STORE_add_lookup(cert_ctx,
                   1046:                    X509_LOOKUP_hash_dir());
                   1047:                if (lookup == NULL) {
                   1048:                        BIO_printf(bio_err, "memory allocation failure\n");
                   1049:                        goto err;
                   1050:                }
                   1051:                i = X509_LOOKUP_add_dir(lookup, ca_path, X509_FILETYPE_PEM);
                   1052:                if (!i) {
                   1053:                        BIO_printf(bio_err, "Error loading directory %s\n",
                   1054:                            ca_path);
                   1055:                        goto err;
                   1056:                }
                   1057:        }
                   1058:        /* Adding a trusted certificate file source. */
                   1059:        if (ca_file) {
                   1060:                lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());
                   1061:                if (lookup == NULL) {
                   1062:                        BIO_printf(bio_err, "memory allocation failure\n");
                   1063:                        goto err;
                   1064:                }
                   1065:                i = X509_LOOKUP_load_file(lookup, ca_file, X509_FILETYPE_PEM);
                   1066:                if (!i) {
                   1067:                        BIO_printf(bio_err, "Error loading file %s\n", ca_file);
                   1068:                        goto err;
                   1069:                }
                   1070:        }
                   1071:        return cert_ctx;
1.15      jsing    1072:  err:
1.1       jsing    1073:        X509_STORE_free(cert_ctx);
                   1074:        return NULL;
                   1075: }
                   1076:
                   1077: static int
                   1078: verify_cb(int ok, X509_STORE_CTX * ctx)
                   1079: {
                   1080:        /*
                   1081:        char buf[256];
                   1082:
                   1083:        if (!ok)
                   1084:                {
                   1085:                X509_NAME_oneline(X509_get_subject_name(ctx->current_cert),
                   1086:                                  buf, sizeof(buf));
                   1087:                printf("%s\n", buf);
                   1088:                printf("error %d at %d depth lookup: %s\n",
                   1089:                       ctx->error, ctx->error_depth,
                   1090:                        X509_verify_cert_error_string(ctx->error));
                   1091:                }
                   1092:        */
                   1093:
                   1094:        return ok;
                   1095: }