[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.23

1.23    ! inoguchi    1: /* $OpenBSD: ts.c,v 1.22 2022/03/24 14:07:08 inoguchi 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. */
1.20      inoguchi   83: static int query_command(const char *data, char *digest, const EVP_MD *md,
                     84:     const char *policy, int no_nonce, int cert, const char *in, const char *out,
                     85:     int text);
1.1       jsing      86: static BIO *BIO_open_with_default(const char *file, const char *mode,
1.19      inoguchi   87:     FILE *default_fp);
                     88: static TS_REQ *create_query(BIO *data_bio, char *digest, const EVP_MD *md,
1.1       jsing      89:     const char *policy, int no_nonce, int cert);
1.20      inoguchi   90: static int create_digest(BIO *input, char *digest, const EVP_MD *md,
                     91:     unsigned char **md_value);
1.1       jsing      92: static ASN1_INTEGER *create_nonce(int bits);
                     93:
                     94: /* Reply related functions. */
1.20      inoguchi   95: static int reply_command(CONF *conf, char *section, char *queryfile,
                     96:     char *passin, char *inkey, char *signer, char *chain, const char *policy,
                     97:     char *in, int token_in, char *out, int token_out, int text);
1.19      inoguchi   98: static TS_RESP *read_PKCS7(BIO *in_bio);
                     99: static TS_RESP *create_response(CONF *conf, const char *section,
1.20      inoguchi  100:     char *queryfile, char *passin, char *inkey, char *signer, char *chain,
                    101:     const char *policy);
1.19      inoguchi  102: static ASN1_INTEGER *serial_cb(TS_RESP_CTX *ctx, void *data);
1.1       jsing     103: static ASN1_INTEGER *next_serial(const char *serialfile);
1.19      inoguchi  104: static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial);
1.1       jsing     105:
                    106: /* Verify related functions. */
1.20      inoguchi  107: static int verify_command(char *data, char *digest, char *queryfile, char *in,
                    108:     int token_in, char *ca_path, char *ca_file, char *untrusted);
1.1       jsing     109: static TS_VERIFY_CTX *create_verify_ctx(char *data, char *digest,
1.20      inoguchi  110:     char *queryfile, char *ca_path, char *ca_file, char *untrusted);
1.1       jsing     111: static X509_STORE *create_cert_store(char *ca_path, char *ca_file);
1.19      inoguchi  112: static int verify_cb(int ok, X509_STORE_CTX *ctx);
1.1       jsing     113:
1.18      inoguchi  114: enum mode {
                    115:        CMD_NONE, CMD_QUERY, CMD_REPLY, CMD_VERIFY
                    116: };
                    117:
                    118: static struct {
                    119:        char *ca_file;
                    120:        char *ca_path;
                    121:        int cert;
                    122:        char *chain;
                    123:        char *configfile;
                    124:        char *data;
                    125:        char *digest;
                    126:        char *in;
                    127:        char *inkey;
                    128:        const EVP_MD *md;
                    129:        int mode;
                    130:        int no_nonce;
                    131:        char *out;
                    132:        char *passin;
                    133:        char *policy;
                    134:        char *queryfile;
                    135:        char *section;
                    136:        char *signer;
                    137:        int text;
                    138:        int token_in;
                    139:        int token_out;
                    140:        char *untrusted;
                    141: } ts_config;
                    142:
                    143: static int
                    144: ts_opt_md(int argc, char **argv, int *argsused)
                    145: {
                    146:        char *name = argv[0];
                    147:
                    148:        if (*name++ != '-')
                    149:                return (1);
                    150:
                    151:        if ((ts_config.md = EVP_get_digestbyname(name)) == NULL)
                    152:                return (1);
                    153:
                    154:        *argsused = 1;
                    155:        return (0);
                    156: }
                    157:
                    158: static int
                    159: ts_opt_query(void)
                    160: {
                    161:        if (ts_config.mode != CMD_NONE)
                    162:                return (1);
                    163:        ts_config.mode = CMD_QUERY;
                    164:        return (0);
                    165: }
                    166:
                    167: static int
                    168: ts_opt_reply(void)
                    169: {
                    170:        if (ts_config.mode != CMD_NONE)
                    171:                return (1);
                    172:        ts_config.mode = CMD_REPLY;
                    173:        return (0);
                    174: }
                    175:
                    176: static int
                    177: ts_opt_verify(void)
                    178: {
                    179:        if (ts_config.mode != CMD_NONE)
                    180:                return (1);
                    181:        ts_config.mode = CMD_VERIFY;
                    182:        return (0);
                    183: }
                    184:
                    185: static const struct option ts_options[] = {
                    186:        {
                    187:                .name = "CAfile",
                    188:                .argname = "file",
                    189:                .desc = "Certificate Authority file",
                    190:                .type = OPTION_ARG,
                    191:                .opt.arg = &ts_config.ca_file,
                    192:        },
                    193:        {
                    194:                .name = "CApath",
                    195:                .argname = "path",
                    196:                .desc = "Certificate Authority path",
                    197:                .type = OPTION_ARG,
                    198:                .opt.arg = &ts_config.ca_path,
                    199:        },
                    200:        {
                    201:                .name = "cert",
                    202:                .desc = "Include signing certificate in the response",
                    203:                .type = OPTION_FLAG,
                    204:                .opt.flag = &ts_config.cert,
                    205:        },
                    206:        {
                    207:                .name = "chain",
                    208:                .argname = "file",
                    209:                .desc = "PEM certificates that will be included in the response",
                    210:                .type = OPTION_ARG,
                    211:                .opt.arg = &ts_config.chain,
                    212:        },
                    213:        {
                    214:                .name = "config",
                    215:                .argname = "file",
                    216:                .desc = "Specify an alternative configuration file",
                    217:                .type = OPTION_ARG,
                    218:                .opt.arg = &ts_config.configfile,
                    219:        },
                    220:        {
                    221:                .name = "data",
                    222:                .argname = "file",
                    223:                .desc = "Data file for which the time stamp request needs to be created",
                    224:                .type = OPTION_ARG,
                    225:                .opt.arg = &ts_config.data,
                    226:        },
                    227:        {
                    228:                .name = "digest",
                    229:                .argname = "arg",
                    230:                .desc = "Specify the message imprint explicitly without the data file",
                    231:                .type = OPTION_ARG,
                    232:                .opt.arg = &ts_config.digest,
                    233:        },
                    234:        {
                    235:                .name = "in",
                    236:                .argname = "file",
                    237:                .desc = "Input file",
                    238:                .type = OPTION_ARG,
                    239:                .opt.arg = &ts_config.in,
                    240:        },
                    241:        {
                    242:                .name = "inkey",
                    243:                .argname = "file",
                    244:                .desc = "Input key file",
                    245:                .type = OPTION_ARG,
                    246:                .opt.arg = &ts_config.inkey,
                    247:        },
                    248:        {
                    249:                .name = "no_nonce",
                    250:                .desc = "Specify no nonce in the request",
                    251:                .type = OPTION_FLAG,
                    252:                .opt.flag = &ts_config.no_nonce,
                    253:        },
                    254:        {
                    255:                .name = "out",
                    256:                .argname = "file",
                    257:                .desc = "Output file",
                    258:                .type = OPTION_ARG,
                    259:                .opt.arg = &ts_config.out,
                    260:        },
                    261:        {
                    262:                .name = "passin",
                    263:                .argname = "src",
                    264:                .desc = "Private key password source",
                    265:                .type = OPTION_ARG,
                    266:                .opt.arg = &ts_config.passin,
                    267:        },
                    268:        {
                    269:                .name = "policy",
                    270:                .argname = "object_id",
                    271:                .desc = "Policy for the TSA to use when creating the time stamp token",
                    272:                .type = OPTION_ARG,
                    273:                .opt.arg = &ts_config.policy,
                    274:        },
                    275:        {
                    276:                .name = "query",
                    277:                .desc = "Create and print a time stamp request",
                    278:                .type = OPTION_FUNC,
                    279:                .opt.func = ts_opt_query,
                    280:        },
                    281:        {
                    282:                .name = "queryfile",
                    283:                .argname = "file",
                    284:                .desc = "File containing a DER-encoded time stamp request",
                    285:                .type = OPTION_ARG,
                    286:                .opt.arg = &ts_config.queryfile,
                    287:        },
                    288:        {
                    289:                .name = "reply",
                    290:                .desc = "Create a time stamp response",
                    291:                .type = OPTION_FUNC,
                    292:                .opt.func = ts_opt_reply,
                    293:        },
                    294:        {
                    295:                .name = "section",
                    296:                .argname = "arg",
                    297:                .desc = "TSA section containing the settings for response generation",
                    298:                .type = OPTION_ARG,
                    299:                .opt.arg = &ts_config.section,
                    300:        },
                    301:        {
                    302:                .name = "signer",
                    303:                .argname = "file",
                    304:                .desc = "Signer certificate file",
                    305:                .type = OPTION_ARG,
                    306:                .opt.arg = &ts_config.signer,
                    307:        },
                    308:        {
                    309:                .name = "text",
                    310:                .desc = "Output in human-readable text format",
                    311:                .type = OPTION_FLAG,
                    312:                .opt.flag = &ts_config.text,
                    313:        },
                    314:        {
                    315:                .name = "token_in",
                    316:                .desc = "Input is a DER-encoded time stamp token",
                    317:                .type = OPTION_FLAG,
                    318:                .opt.flag = &ts_config.token_in,
                    319:        },
                    320:        {
                    321:                .name = "token_out",
                    322:                .desc = "Output is a DER-encoded time stamp token",
                    323:                .type = OPTION_FLAG,
                    324:                .opt.flag = &ts_config.token_out,
                    325:        },
                    326:        {
                    327:                .name = "untrusted",
                    328:                .argname = "file",
                    329:                .desc = "File containing untrusted certificates",
                    330:                .type = OPTION_ARG,
                    331:                .opt.arg = &ts_config.untrusted,
                    332:        },
                    333:        {
                    334:                .name = "verify",
                    335:                .desc = "Verify a time stamp response",
                    336:                .type = OPTION_FUNC,
                    337:                .opt.func = ts_opt_verify,
                    338:        },
                    339:        {
                    340:                .name = NULL,
                    341:                .desc = "",
                    342:                .type = OPTION_ARGV_FUNC,
                    343:                .opt.argvfunc = ts_opt_md,
                    344:        },
                    345:        { NULL },
                    346: };
                    347:
                    348: static void
                    349: ts_usage(void)
                    350: {
                    351:        fprintf(stderr, "usage:\n"
                    352:            "ts -query [-md4 | -md5 | -ripemd160 | -sha1] [-cert]\n"
                    353:            "    [-config configfile] [-data file_to_hash]\n"
                    354:            "    [-digest digest_bytes] [-in request.tsq] [-no_nonce]\n"
                    355:            "    [-out request.tsq] [-policy object_id] [-text]\n");
                    356:        fprintf(stderr, "\n"
                    357:            "ts -reply [-chain certs_file.pem] [-config configfile]\n"
                    358:            "    [-in response.tsr] [-inkey private.pem] [-out response.tsr]\n"
                    359:            "    [-passin arg] [-policy object_id] [-queryfile request.tsq]\n"
                    360:            "    [-section tsa_section] [-signer tsa_cert.pem] [-text]\n"
                    361:            "    [-token_in] [-token_out]\n");
                    362:        fprintf(stderr, "\n"
                    363:            "ts -verify [-CAfile trusted_certs.pem]\n"
                    364:            "    [-CApath trusted_cert_path] [-data file_to_hash]\n"
                    365:            "    [-digest digest_bytes] [-in response.tsr]\n"
                    366:            "    [-queryfile request.tsq] [-token_in]\n"
                    367:            "    [-untrusted cert_file.pem]\n");
                    368:        fprintf(stderr, "\n");
                    369:        options_usage(ts_options);
                    370:        fprintf(stderr, "\n");
                    371: }
                    372:
1.1       jsing     373: int
                    374: ts_main(int argc, char **argv)
                    375: {
                    376:        int ret = 1;
                    377:        CONF *conf = NULL;
                    378:        char *password = NULL;  /* Password itself. */
1.11      doug      379:
                    380:        if (single_execution) {
1.14      deraadt   381:                if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
1.11      doug      382:                        perror("pledge");
1.13      doug      383:                        exit(1);
                    384:                }
1.11      doug      385:        }
1.1       jsing     386:
1.18      inoguchi  387:        memset(&ts_config, 0, sizeof(ts_config));
                    388:        ts_config.mode = CMD_NONE;
                    389:
                    390:        if (options_parse(argc, argv, ts_options, NULL, NULL) != 0)
                    391:                goto usage;
1.1       jsing     392:
                    393:        /* Get the password if required. */
1.21      inoguchi  394:        if (ts_config.mode == CMD_REPLY && ts_config.passin != NULL &&
1.18      inoguchi  395:            !app_passwd(bio_err, ts_config.passin, NULL, &password, NULL)) {
1.1       jsing     396:                BIO_printf(bio_err, "Error getting password.\n");
                    397:                goto cleanup;
                    398:        }
                    399:        /*
                    400:         * Check consistency of parameters and execute the appropriate
                    401:         * function.
                    402:         */
1.18      inoguchi  403:        switch (ts_config.mode) {
1.1       jsing     404:        case CMD_NONE:
                    405:                goto usage;
                    406:        case CMD_QUERY:
                    407:                /*
                    408:                 * Data file and message imprint cannot be specified at the
                    409:                 * same time.
                    410:                 */
1.18      inoguchi  411:                ret = ts_config.data != NULL && ts_config.digest != NULL;
1.1       jsing     412:                if (ret)
                    413:                        goto usage;
                    414:                /* Load the config file for possible policy OIDs. */
1.18      inoguchi  415:                conf = load_config_file(ts_config.configfile);
1.20      inoguchi  416:                ret = !query_command(ts_config.data, ts_config.digest,
                    417:                    ts_config.md, ts_config.policy, ts_config.no_nonce,
                    418:                    ts_config.cert, ts_config.in, ts_config.out,
                    419:                    ts_config.text);
1.1       jsing     420:                break;
                    421:        case CMD_REPLY:
1.18      inoguchi  422:                conf = load_config_file(ts_config.configfile);
                    423:                if (ts_config.in == NULL) {
1.20      inoguchi  424:                        ret = !(ts_config.queryfile != NULL && conf != NULL &&
                    425:                            !ts_config.token_in);
1.1       jsing     426:                        if (ret)
                    427:                                goto usage;
                    428:                } else {
                    429:                        /* 'in' and 'queryfile' are exclusive. */
1.18      inoguchi  430:                        ret = !(ts_config.queryfile == NULL);
1.1       jsing     431:                        if (ret)
                    432:                                goto usage;
                    433:                }
                    434:
1.20      inoguchi  435:                ret = !reply_command(conf, ts_config.section,
                    436:                    ts_config.queryfile, password, ts_config.inkey,
                    437:                    ts_config.signer, ts_config.chain, ts_config.policy,
                    438:                    ts_config.in, ts_config.token_in, ts_config.out,
                    439:                    ts_config.token_out, ts_config.text);
1.1       jsing     440:                break;
                    441:        case CMD_VERIFY:
1.21      inoguchi  442:                ret = !(((ts_config.queryfile != NULL && ts_config.data == NULL &&
                    443:                    ts_config.digest == NULL) ||
                    444:                    (ts_config.queryfile == NULL && ts_config.data != NULL &&
                    445:                    ts_config.digest == NULL) ||
                    446:                    (ts_config.queryfile == NULL && ts_config.data == NULL &&
                    447:                    ts_config.digest != NULL)) &&
1.20      inoguchi  448:                    ts_config.in != NULL);
1.1       jsing     449:                if (ret)
                    450:                        goto usage;
                    451:
1.20      inoguchi  452:                ret = !verify_command(ts_config.data, ts_config.digest,
                    453:                    ts_config.queryfile, ts_config.in, ts_config.token_in,
1.18      inoguchi  454:                    ts_config.ca_path, ts_config.ca_file, ts_config.untrusted);
1.1       jsing     455:        }
                    456:
                    457:        goto cleanup;
                    458:
1.15      jsing     459:  usage:
1.18      inoguchi  460:        ts_usage();
1.1       jsing     461:
1.15      jsing     462:  cleanup:
1.1       jsing     463:        /* Clean up. */
                    464:        NCONF_free(conf);
                    465:        free(password);
                    466:        OBJ_cleanup();
                    467:
                    468:        return (ret);
                    469: }
                    470:
                    471: /*
                    472:  * Configuration file-related function definitions.
                    473:  */
                    474:
                    475: static ASN1_OBJECT *
                    476: txt2obj(const char *oid)
                    477: {
                    478:        ASN1_OBJECT *oid_obj = NULL;
                    479:
1.21      inoguchi  480:        if ((oid_obj = OBJ_txt2obj(oid, 0)) == NULL)
1.1       jsing     481:                BIO_printf(bio_err, "cannot convert %s to OID\n", oid);
                    482:
                    483:        return oid_obj;
                    484: }
                    485:
                    486: static CONF *
                    487: load_config_file(const char *configfile)
                    488: {
                    489:        CONF *conf = NULL;
                    490:        long errorline = -1;
                    491:
1.21      inoguchi  492:        if (configfile == NULL)
1.1       jsing     493:                configfile = getenv("OPENSSL_CONF");
                    494:
1.21      inoguchi  495:        if (configfile != NULL &&
                    496:            ((conf = NCONF_new(NULL)) == NULL ||
1.1       jsing     497:            NCONF_load(conf, configfile, &errorline) <= 0)) {
                    498:                if (errorline <= 0)
                    499:                        BIO_printf(bio_err, "error loading the config file "
                    500:                            "'%s'\n", configfile);
                    501:                else
                    502:                        BIO_printf(bio_err, "error on line %ld of config file "
                    503:                            "'%s'\n", errorline, configfile);
                    504:        }
                    505:        if (conf != NULL) {
                    506:                const char *p;
                    507:
                    508:                BIO_printf(bio_err, "Using configuration from %s\n",
                    509:                    configfile);
                    510:                p = NCONF_get_string(conf, NULL, ENV_OID_FILE);
                    511:                if (p != NULL) {
                    512:                        BIO *oid_bio = BIO_new_file(p, "r");
1.21      inoguchi  513:                        if (oid_bio == NULL)
1.1       jsing     514:                                ERR_print_errors(bio_err);
                    515:                        else {
                    516:                                OBJ_create_objects(oid_bio);
                    517:                                BIO_free_all(oid_bio);
                    518:                        }
                    519:                } else
                    520:                        ERR_clear_error();
                    521:                if (!add_oid_section(bio_err, conf))
                    522:                        ERR_print_errors(bio_err);
                    523:        }
                    524:        return conf;
                    525: }
                    526:
                    527: /*
                    528:  * Query-related method definitions.
                    529:  */
                    530:
                    531: static int
1.19      inoguchi  532: query_command(const char *data, char *digest, const EVP_MD *md,
1.20      inoguchi  533:     const char *policy, int no_nonce, int cert, const char *in, const char *out,
                    534:     int text)
1.1       jsing     535: {
                    536:        int ret = 0;
                    537:        TS_REQ *query = NULL;
                    538:        BIO *in_bio = NULL;
                    539:        BIO *data_bio = NULL;
                    540:        BIO *out_bio = NULL;
                    541:
                    542:        /* Build query object either from file or from scratch. */
                    543:        if (in != NULL) {
                    544:                if ((in_bio = BIO_new_file(in, "rb")) == NULL)
                    545:                        goto end;
                    546:                query = d2i_TS_REQ_bio(in_bio, NULL);
                    547:        } else {
                    548:                /* Open the file if no explicit digest bytes were specified. */
1.21      inoguchi  549:                if (digest == NULL &&
                    550:                    (data_bio = BIO_open_with_default(data, "rb", stdin)) == NULL)
1.1       jsing     551:                        goto end;
                    552:                /* Creating the query object. */
                    553:                query = create_query(data_bio, digest, md,
                    554:                    policy, no_nonce, cert);
                    555:                /* Saving the random number generator state. */
                    556:        }
                    557:        if (query == NULL)
                    558:                goto end;
                    559:
                    560:        /* Write query either in ASN.1 or in text format. */
                    561:        if ((out_bio = BIO_open_with_default(out, "wb", stdout)) == NULL)
                    562:                goto end;
                    563:        if (text) {
                    564:                /* Text output. */
                    565:                if (!TS_REQ_print_bio(out_bio, query))
                    566:                        goto end;
                    567:        } else {
                    568:                /* ASN.1 output. */
                    569:                if (!i2d_TS_REQ_bio(out_bio, query))
                    570:                        goto end;
                    571:        }
                    572:
                    573:        ret = 1;
                    574:
1.15      jsing     575:  end:
1.1       jsing     576:        ERR_print_errors(bio_err);
                    577:
                    578:        /* Clean up. */
                    579:        BIO_free_all(in_bio);
                    580:        BIO_free_all(data_bio);
                    581:        BIO_free_all(out_bio);
                    582:        TS_REQ_free(query);
                    583:
                    584:        return ret;
                    585: }
                    586:
                    587: static BIO *
1.19      inoguchi  588: BIO_open_with_default(const char *file, const char *mode, FILE *default_fp)
1.1       jsing     589: {
                    590:        return file == NULL ? BIO_new_fp(default_fp, BIO_NOCLOSE) :
                    591:            BIO_new_file(file, mode);
                    592: }
                    593:
                    594: static TS_REQ *
1.20      inoguchi  595: create_query(BIO *data_bio, char *digest, const EVP_MD *md, const char *policy,
                    596:     int no_nonce, int cert)
1.1       jsing     597: {
                    598:        int ret = 0;
                    599:        TS_REQ *ts_req = NULL;
                    600:        int len;
                    601:        TS_MSG_IMPRINT *msg_imprint = NULL;
                    602:        X509_ALGOR *algo = NULL;
                    603:        unsigned char *data = NULL;
                    604:        ASN1_OBJECT *policy_obj = NULL;
                    605:        ASN1_INTEGER *nonce_asn1 = NULL;
                    606:
                    607:        /* Setting default message digest. */
1.21      inoguchi  608:        if (md == NULL && (md = EVP_get_digestbyname("sha1")) == NULL)
1.1       jsing     609:                goto err;
                    610:
                    611:        /* Creating request object. */
1.21      inoguchi  612:        if ((ts_req = TS_REQ_new()) == NULL)
1.1       jsing     613:                goto err;
                    614:
                    615:        /* Setting version. */
                    616:        if (!TS_REQ_set_version(ts_req, 1))
                    617:                goto err;
                    618:
                    619:        /* Creating and adding MSG_IMPRINT object. */
1.21      inoguchi  620:        if ((msg_imprint = TS_MSG_IMPRINT_new()) == NULL)
1.1       jsing     621:                goto err;
                    622:
                    623:        /* Adding algorithm. */
1.21      inoguchi  624:        if ((algo = X509_ALGOR_new()) == NULL)
1.1       jsing     625:                goto err;
1.21      inoguchi  626:        if ((algo->algorithm = OBJ_nid2obj(EVP_MD_type(md))) == NULL)
1.1       jsing     627:                goto err;
1.21      inoguchi  628:        if ((algo->parameter = ASN1_TYPE_new()) == NULL)
1.1       jsing     629:                goto err;
                    630:        algo->parameter->type = V_ASN1_NULL;
                    631:        if (!TS_MSG_IMPRINT_set_algo(msg_imprint, algo))
                    632:                goto err;
                    633:
                    634:        /* Adding message digest. */
                    635:        if ((len = create_digest(data_bio, digest, md, &data)) == 0)
                    636:                goto err;
                    637:        if (!TS_MSG_IMPRINT_set_msg(msg_imprint, data, len))
                    638:                goto err;
                    639:
                    640:        if (!TS_REQ_set_msg_imprint(ts_req, msg_imprint))
                    641:                goto err;
                    642:
                    643:        /* Setting policy if requested. */
1.21      inoguchi  644:        if (policy != NULL && (policy_obj = txt2obj(policy)) == NULL)
1.1       jsing     645:                goto err;
1.21      inoguchi  646:        if (policy_obj != NULL && !TS_REQ_set_policy_id(ts_req, policy_obj))
1.1       jsing     647:                goto err;
                    648:
                    649:        /* Setting nonce if requested. */
1.21      inoguchi  650:        if (!no_nonce && (nonce_asn1 = create_nonce(NONCE_LENGTH)) == NULL)
1.1       jsing     651:                goto err;
1.21      inoguchi  652:        if (nonce_asn1 != NULL && !TS_REQ_set_nonce(ts_req, nonce_asn1))
1.1       jsing     653:                goto err;
                    654:
                    655:        /* Setting certificate request flag if requested. */
                    656:        if (!TS_REQ_set_cert_req(ts_req, cert))
                    657:                goto err;
                    658:
                    659:        ret = 1;
                    660:
1.15      jsing     661:  err:
1.1       jsing     662:        if (!ret) {
                    663:                TS_REQ_free(ts_req);
                    664:                ts_req = NULL;
                    665:                BIO_printf(bio_err, "could not create query\n");
                    666:        }
                    667:        TS_MSG_IMPRINT_free(msg_imprint);
                    668:        X509_ALGOR_free(algo);
                    669:        free(data);
                    670:        ASN1_OBJECT_free(policy_obj);
                    671:        ASN1_INTEGER_free(nonce_asn1);
                    672:
                    673:        return ts_req;
                    674: }
                    675:
                    676: static int
1.19      inoguchi  677: create_digest(BIO *input, char *digest, const EVP_MD *md,
1.1       jsing     678:     unsigned char **md_value)
                    679: {
                    680:        int md_value_len;
1.23    ! inoguchi  681:        EVP_MD_CTX *md_ctx = NULL;
1.1       jsing     682:
                    683:        md_value_len = EVP_MD_size(md);
                    684:        if (md_value_len < 0)
                    685:                goto err;
1.23    ! inoguchi  686:
1.21      inoguchi  687:        if (input != NULL) {
1.1       jsing     688:                /* Digest must be computed from an input file. */
                    689:                unsigned char buffer[4096];
                    690:                int length;
                    691:
                    692:                *md_value = malloc(md_value_len);
1.17      tb        693:                if (*md_value == NULL)
1.1       jsing     694:                        goto err;
                    695:
1.16      tb        696:                if ((md_ctx = EVP_MD_CTX_new()) == NULL)
                    697:                        goto err;
                    698:
1.23    ! inoguchi  699:                if (!EVP_DigestInit(md_ctx, md))
        !           700:                        goto err;
        !           701:
1.1       jsing     702:                while ((length = BIO_read(input, buffer, sizeof(buffer))) > 0) {
1.23    ! inoguchi  703:                        if (!EVP_DigestUpdate(md_ctx, buffer, length))
        !           704:                                goto err;
1.1       jsing     705:                }
1.23    ! inoguchi  706:
        !           707:                if (!EVP_DigestFinal(md_ctx, *md_value, NULL))
        !           708:                        goto err;
1.16      tb        709:
                    710:                EVP_MD_CTX_free(md_ctx);
1.23    ! inoguchi  711:                md_ctx = NULL;
        !           712:
1.1       jsing     713:        } else {
                    714:                /* Digest bytes are specified with digest. */
                    715:                long digest_len;
1.23    ! inoguchi  716:
1.1       jsing     717:                *md_value = string_to_hex(digest, &digest_len);
1.21      inoguchi  718:                if (*md_value == NULL || md_value_len != digest_len) {
1.1       jsing     719:                        free(*md_value);
                    720:                        *md_value = NULL;
                    721:                        BIO_printf(bio_err, "bad digest, %d bytes "
                    722:                            "must be specified\n", md_value_len);
                    723:                        goto err;
                    724:                }
                    725:        }
                    726:
                    727:        return md_value_len;
1.23    ! inoguchi  728:
1.15      jsing     729:  err:
1.23    ! inoguchi  730:        EVP_MD_CTX_free(md_ctx);
1.1       jsing     731:        return 0;
                    732: }
                    733:
                    734: static ASN1_INTEGER *
                    735: create_nonce(int bits)
                    736: {
                    737:        unsigned char buf[20];
                    738:        ASN1_INTEGER *nonce = NULL;
                    739:        int len = (bits - 1) / 8 + 1;
                    740:        int i;
                    741:
                    742:        /* Generating random byte sequence. */
                    743:        if (len > (int) sizeof(buf))
                    744:                goto err;
1.3       jsing     745:        arc4random_buf(buf, len);
1.1       jsing     746:
                    747:        /* Find the first non-zero byte and creating ASN1_INTEGER object. */
                    748:        for (i = 0; i < len && !buf[i]; ++i)
                    749:                ;
1.21      inoguchi  750:        if ((nonce = ASN1_INTEGER_new()) == NULL)
1.1       jsing     751:                goto err;
                    752:        free(nonce->data);
                    753:        /* Allocate at least one byte. */
                    754:        nonce->length = len - i;
1.21      inoguchi  755:        if ((nonce->data = malloc(nonce->length + 1)) == NULL)
1.1       jsing     756:                goto err;
                    757:        memcpy(nonce->data, buf + i, nonce->length);
                    758:
                    759:        return nonce;
                    760:
1.15      jsing     761:  err:
1.1       jsing     762:        BIO_printf(bio_err, "could not create nonce\n");
                    763:        ASN1_INTEGER_free(nonce);
                    764:        return NULL;
                    765: }
1.20      inoguchi  766:
1.1       jsing     767: /*
                    768:  * Reply-related method definitions.
                    769:  */
                    770:
                    771: static int
1.20      inoguchi  772: reply_command(CONF *conf, char *section, char *queryfile, char *passin,
                    773:     char *inkey, char *signer, char *chain, const char *policy, char *in,
                    774:     int token_in, char *out, int token_out, int text)
1.1       jsing     775: {
                    776:        int ret = 0;
                    777:        TS_RESP *response = NULL;
                    778:        BIO *in_bio = NULL;
                    779:        BIO *query_bio = NULL;
                    780:        BIO *inkey_bio = NULL;
                    781:        BIO *signer_bio = NULL;
                    782:        BIO *out_bio = NULL;
                    783:
                    784:        /* Build response object either from response or query. */
                    785:        if (in != NULL) {
                    786:                if ((in_bio = BIO_new_file(in, "rb")) == NULL)
                    787:                        goto end;
                    788:                if (token_in) {
                    789:                        /*
                    790:                         * We have a ContentInfo (PKCS7) object, add
                    791:                         * 'granted' status info around it.
                    792:                         */
                    793:                        response = read_PKCS7(in_bio);
                    794:                } else {
                    795:                        /* We have a ready-made TS_RESP object. */
                    796:                        response = d2i_TS_RESP_bio(in_bio, NULL);
                    797:                }
                    798:        } else {
1.21      inoguchi  799:                response = create_response(conf, section, queryfile, passin,
                    800:                                inkey, signer, chain, policy);
                    801:                if (response != NULL)
1.1       jsing     802:                        BIO_printf(bio_err, "Response has been generated.\n");
                    803:                else
                    804:                        BIO_printf(bio_err, "Response is not generated.\n");
                    805:        }
                    806:        if (response == NULL)
                    807:                goto end;
                    808:
                    809:        /* Write response either in ASN.1 or text format. */
                    810:        if ((out_bio = BIO_open_with_default(out, "wb", stdout)) == NULL)
                    811:                goto end;
                    812:        if (text) {
                    813:                /* Text output. */
                    814:                if (token_out) {
                    815:                        TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response);
                    816:                        if (!TS_TST_INFO_print_bio(out_bio, tst_info))
                    817:                                goto end;
                    818:                } else {
                    819:                        if (!TS_RESP_print_bio(out_bio, response))
                    820:                                goto end;
                    821:                }
                    822:        } else {
                    823:                /* ASN.1 DER output. */
                    824:                if (token_out) {
                    825:                        PKCS7 *token = TS_RESP_get_token(response);
                    826:                        if (!i2d_PKCS7_bio(out_bio, token))
                    827:                                goto end;
                    828:                } else {
                    829:                        if (!i2d_TS_RESP_bio(out_bio, response))
                    830:                                goto end;
                    831:                }
                    832:        }
                    833:
                    834:        ret = 1;
                    835:
1.15      jsing     836:  end:
1.1       jsing     837:        ERR_print_errors(bio_err);
                    838:
                    839:        /* Clean up. */
                    840:        BIO_free_all(in_bio);
                    841:        BIO_free_all(query_bio);
                    842:        BIO_free_all(inkey_bio);
                    843:        BIO_free_all(signer_bio);
                    844:        BIO_free_all(out_bio);
                    845:        TS_RESP_free(response);
                    846:
                    847:        return ret;
                    848: }
                    849:
                    850: /* Reads a PKCS7 token and adds default 'granted' status info to it. */
                    851: static TS_RESP *
1.19      inoguchi  852: read_PKCS7(BIO *in_bio)
1.1       jsing     853: {
                    854:        int ret = 0;
                    855:        PKCS7 *token = NULL;
                    856:        TS_TST_INFO *tst_info = NULL;
                    857:        TS_RESP *resp = NULL;
                    858:        TS_STATUS_INFO *si = NULL;
                    859:
                    860:        /* Read PKCS7 object and extract the signed time stamp info. */
1.21      inoguchi  861:        if ((token = d2i_PKCS7_bio(in_bio, NULL)) == NULL)
1.1       jsing     862:                goto end;
1.21      inoguchi  863:        if ((tst_info = PKCS7_to_TS_TST_INFO(token)) == NULL)
1.1       jsing     864:                goto end;
                    865:
                    866:        /* Creating response object. */
1.21      inoguchi  867:        if ((resp = TS_RESP_new()) == NULL)
1.1       jsing     868:                goto end;
                    869:
                    870:        /* Create granted status info. */
1.21      inoguchi  871:        if ((si = TS_STATUS_INFO_new()) == NULL)
1.1       jsing     872:                goto end;
                    873:        if (!(ASN1_INTEGER_set(si->status, TS_STATUS_GRANTED)))
                    874:                goto end;
                    875:        if (!TS_RESP_set_status_info(resp, si))
                    876:                goto end;
                    877:
                    878:        /* Setting encapsulated token. */
                    879:        TS_RESP_set_tst_info(resp, token, tst_info);
                    880:        token = NULL;           /* Ownership is lost. */
                    881:        tst_info = NULL;        /* Ownership is lost. */
                    882:
                    883:        ret = 1;
1.15      jsing     884:  end:
1.1       jsing     885:        PKCS7_free(token);
                    886:        TS_TST_INFO_free(tst_info);
                    887:        if (!ret) {
                    888:                TS_RESP_free(resp);
                    889:                resp = NULL;
                    890:        }
                    891:        TS_STATUS_INFO_free(si);
                    892:        return resp;
                    893: }
                    894:
                    895: static TS_RESP *
1.20      inoguchi  896: create_response(CONF *conf, const char *section, char *queryfile, char *passin,
                    897:     char *inkey, char *signer, char *chain, const char *policy)
1.1       jsing     898: {
                    899:        int ret = 0;
                    900:        TS_RESP *response = NULL;
                    901:        BIO *query_bio = NULL;
                    902:        TS_RESP_CTX *resp_ctx = NULL;
                    903:
1.21      inoguchi  904:        if ((query_bio = BIO_new_file(queryfile, "rb")) == NULL)
1.1       jsing     905:                goto end;
                    906:
                    907:        /* Getting TSA configuration section. */
1.21      inoguchi  908:        if ((section = TS_CONF_get_tsa_section(conf, section)) == NULL)
1.1       jsing     909:                goto end;
                    910:
                    911:        /* Setting up response generation context. */
1.21      inoguchi  912:        if ((resp_ctx = TS_RESP_CTX_new()) == NULL)
1.1       jsing     913:                goto end;
                    914:
                    915:        /* Setting serial number provider callback. */
                    916:        if (!TS_CONF_set_serial(conf, section, serial_cb, resp_ctx))
                    917:                goto end;
                    918:
                    919:        /* Setting TSA signer certificate. */
                    920:        if (!TS_CONF_set_signer_cert(conf, section, signer, resp_ctx))
                    921:                goto end;
                    922:
                    923:        /* Setting TSA signer certificate chain. */
                    924:        if (!TS_CONF_set_certs(conf, section, chain, resp_ctx))
                    925:                goto end;
                    926:
                    927:        /* Setting TSA signer private key. */
                    928:        if (!TS_CONF_set_signer_key(conf, section, inkey, passin, resp_ctx))
                    929:                goto end;
                    930:
                    931:        /* Setting default policy OID. */
                    932:        if (!TS_CONF_set_def_policy(conf, section, policy, resp_ctx))
                    933:                goto end;
                    934:
                    935:        /* Setting acceptable policy OIDs. */
                    936:        if (!TS_CONF_set_policies(conf, section, resp_ctx))
                    937:                goto end;
                    938:
                    939:        /* Setting the acceptable one-way hash algorithms. */
                    940:        if (!TS_CONF_set_digests(conf, section, resp_ctx))
                    941:                goto end;
                    942:
                    943:        /* Setting guaranteed time stamp accuracy. */
                    944:        if (!TS_CONF_set_accuracy(conf, section, resp_ctx))
                    945:                goto end;
                    946:
                    947:        /* Setting the precision of the time. */
                    948:        if (!TS_CONF_set_clock_precision_digits(conf, section, resp_ctx))
                    949:                goto end;
                    950:
                    951:        /* Setting the ordering flaf if requested. */
                    952:        if (!TS_CONF_set_ordering(conf, section, resp_ctx))
                    953:                goto end;
                    954:
                    955:        /* Setting the TSA name required flag if requested. */
                    956:        if (!TS_CONF_set_tsa_name(conf, section, resp_ctx))
                    957:                goto end;
                    958:
                    959:        /* Setting the ESS cert id chain flag if requested. */
                    960:        if (!TS_CONF_set_ess_cert_id_chain(conf, section, resp_ctx))
                    961:                goto end;
                    962:
                    963:        /* Creating the response. */
1.21      inoguchi  964:        if ((response = TS_RESP_create_response(resp_ctx, query_bio)) == NULL)
1.1       jsing     965:                goto end;
                    966:
                    967:        ret = 1;
1.15      jsing     968:  end:
1.1       jsing     969:        if (!ret) {
                    970:                TS_RESP_free(response);
                    971:                response = NULL;
                    972:        }
                    973:        TS_RESP_CTX_free(resp_ctx);
                    974:        BIO_free_all(query_bio);
                    975:
                    976:        return response;
                    977: }
                    978:
                    979: static ASN1_INTEGER *
1.19      inoguchi  980: serial_cb(TS_RESP_CTX *ctx, void *data)
1.1       jsing     981: {
                    982:        const char *serial_file = (const char *) data;
                    983:        ASN1_INTEGER *serial = next_serial(serial_file);
                    984:
1.21      inoguchi  985:        if (serial == NULL) {
1.1       jsing     986:                TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
                    987:                    "Error during serial number "
                    988:                    "generation.");
                    989:                TS_RESP_CTX_add_failure_info(ctx,
                    990:                    TS_INFO_ADD_INFO_NOT_AVAILABLE);
                    991:        } else
                    992:                save_ts_serial(serial_file, serial);
                    993:
                    994:        return serial;
                    995: }
                    996:
                    997: static ASN1_INTEGER *
                    998: next_serial(const char *serialfile)
                    999: {
                   1000:        int ret = 0;
                   1001:        BIO *in = NULL;
                   1002:        ASN1_INTEGER *serial = NULL;
                   1003:        BIGNUM *bn = NULL;
                   1004:
1.21      inoguchi 1005:        if ((serial = ASN1_INTEGER_new()) == NULL)
1.1       jsing    1006:                goto err;
                   1007:
1.21      inoguchi 1008:        if ((in = BIO_new_file(serialfile, "r")) == NULL) {
1.1       jsing    1009:                ERR_clear_error();
                   1010:                BIO_printf(bio_err, "Warning: could not open file %s for "
                   1011:                    "reading, using serial number: 1\n", serialfile);
                   1012:                if (!ASN1_INTEGER_set(serial, 1))
                   1013:                        goto err;
                   1014:        } else {
                   1015:                char buf[1024];
                   1016:                if (!a2i_ASN1_INTEGER(in, serial, buf, sizeof(buf))) {
                   1017:                        BIO_printf(bio_err, "unable to load number from %s\n",
                   1018:                            serialfile);
                   1019:                        goto err;
                   1020:                }
1.21      inoguchi 1021:                if ((bn = ASN1_INTEGER_to_BN(serial, NULL)) == NULL)
1.1       jsing    1022:                        goto err;
                   1023:                ASN1_INTEGER_free(serial);
                   1024:                serial = NULL;
                   1025:                if (!BN_add_word(bn, 1))
                   1026:                        goto err;
1.21      inoguchi 1027:                if ((serial = BN_to_ASN1_INTEGER(bn, NULL)) == NULL)
1.1       jsing    1028:                        goto err;
                   1029:        }
                   1030:        ret = 1;
1.15      jsing    1031:  err:
1.1       jsing    1032:        if (!ret) {
                   1033:                ASN1_INTEGER_free(serial);
                   1034:                serial = NULL;
                   1035:        }
                   1036:        BIO_free_all(in);
                   1037:        BN_free(bn);
                   1038:        return serial;
                   1039: }
                   1040:
                   1041: static int
1.19      inoguchi 1042: save_ts_serial(const char *serialfile, ASN1_INTEGER *serial)
1.1       jsing    1043: {
                   1044:        int ret = 0;
                   1045:        BIO *out = NULL;
                   1046:
1.21      inoguchi 1047:        if ((out = BIO_new_file(serialfile, "w")) == NULL)
1.1       jsing    1048:                goto err;
                   1049:        if (i2a_ASN1_INTEGER(out, serial) <= 0)
                   1050:                goto err;
                   1051:        if (BIO_puts(out, "\n") <= 0)
                   1052:                goto err;
                   1053:        ret = 1;
1.15      jsing    1054:  err:
1.1       jsing    1055:        if (!ret)
                   1056:                BIO_printf(bio_err, "could not save serial number to %s\n",
                   1057:                    serialfile);
                   1058:        BIO_free_all(out);
                   1059:        return ret;
                   1060: }
                   1061:
                   1062: /*
                   1063:  * Verify-related method definitions.
                   1064:  */
                   1065:
                   1066: static int
                   1067: verify_command(char *data, char *digest, char *queryfile, char *in,
                   1068:     int token_in, char *ca_path, char *ca_file, char *untrusted)
                   1069: {
                   1070:        BIO *in_bio = NULL;
                   1071:        PKCS7 *token = NULL;
                   1072:        TS_RESP *response = NULL;
                   1073:        TS_VERIFY_CTX *verify_ctx = NULL;
                   1074:        int ret = 0;
                   1075:
                   1076:        /* Decode the token (PKCS7) or response (TS_RESP) files. */
1.21      inoguchi 1077:        if ((in_bio = BIO_new_file(in, "rb")) == NULL)
1.1       jsing    1078:                goto end;
                   1079:        if (token_in) {
1.21      inoguchi 1080:                if ((token = d2i_PKCS7_bio(in_bio, NULL)) == NULL)
1.1       jsing    1081:                        goto end;
                   1082:        } else {
1.21      inoguchi 1083:                if ((response = d2i_TS_RESP_bio(in_bio, NULL)) == NULL)
1.1       jsing    1084:                        goto end;
                   1085:        }
                   1086:
1.21      inoguchi 1087:        if ((verify_ctx = create_verify_ctx(data, digest, queryfile,
                   1088:            ca_path, ca_file, untrusted)) == NULL)
1.1       jsing    1089:                goto end;
                   1090:
                   1091:        /* Checking the token or response against the request. */
                   1092:        ret = token_in ?
                   1093:            TS_RESP_verify_token(verify_ctx, token) :
                   1094:            TS_RESP_verify_response(verify_ctx, response);
                   1095:
1.15      jsing    1096:  end:
1.1       jsing    1097:        printf("Verification: ");
                   1098:        if (ret)
                   1099:                printf("OK\n");
                   1100:        else {
                   1101:                printf("FAILED\n");
                   1102:                /* Print errors, if there are any. */
                   1103:                ERR_print_errors(bio_err);
                   1104:        }
                   1105:
                   1106:        /* Clean up. */
                   1107:        BIO_free_all(in_bio);
                   1108:        PKCS7_free(token);
                   1109:        TS_RESP_free(response);
                   1110:        TS_VERIFY_CTX_free(verify_ctx);
                   1111:        return ret;
                   1112: }
                   1113:
                   1114: static TS_VERIFY_CTX *
                   1115: create_verify_ctx(char *data, char *digest, char *queryfile, char *ca_path,
                   1116:     char *ca_file, char *untrusted)
                   1117: {
                   1118:        TS_VERIFY_CTX *ctx = NULL;
                   1119:        BIO *input = NULL;
                   1120:        TS_REQ *request = NULL;
                   1121:        int ret = 0;
                   1122:
                   1123:        if (data != NULL || digest != NULL) {
1.21      inoguchi 1124:                if ((ctx = TS_VERIFY_CTX_new()) == NULL)
1.1       jsing    1125:                        goto err;
                   1126:                ctx->flags = TS_VFY_VERSION | TS_VFY_SIGNER;
                   1127:                if (data != NULL) {
                   1128:                        ctx->flags |= TS_VFY_DATA;
1.21      inoguchi 1129:                        if ((ctx->data = BIO_new_file(data, "rb")) == NULL)
1.1       jsing    1130:                                goto err;
                   1131:                } else if (digest != NULL) {
                   1132:                        long imprint_len;
                   1133:                        ctx->flags |= TS_VFY_IMPRINT;
1.21      inoguchi 1134:                        if ((ctx->imprint = string_to_hex(digest,
                   1135:                                    &imprint_len)) == NULL) {
1.1       jsing    1136:                                BIO_printf(bio_err, "invalid digest string\n");
                   1137:                                goto err;
                   1138:                        }
                   1139:                        ctx->imprint_len = imprint_len;
                   1140:                }
                   1141:        } else if (queryfile != NULL) {
                   1142:                /*
                   1143:                 * The request has just to be read, decoded and converted to
                   1144:                 * a verify context object.
                   1145:                 */
1.21      inoguchi 1146:                if ((input = BIO_new_file(queryfile, "rb")) == NULL)
1.1       jsing    1147:                        goto err;
1.21      inoguchi 1148:                if ((request = d2i_TS_REQ_bio(input, NULL)) == NULL)
1.1       jsing    1149:                        goto err;
1.21      inoguchi 1150:                if ((ctx = TS_REQ_to_TS_VERIFY_CTX(request, NULL)) == NULL)
1.1       jsing    1151:                        goto err;
                   1152:        } else
                   1153:                return NULL;
                   1154:
                   1155:        /* Add the signature verification flag and arguments. */
                   1156:        ctx->flags |= TS_VFY_SIGNATURE;
                   1157:
                   1158:        /* Initialising the X509_STORE object. */
1.21      inoguchi 1159:        if ((ctx->store = create_cert_store(ca_path, ca_file)) == NULL)
1.1       jsing    1160:                goto err;
                   1161:
                   1162:        /* Loading untrusted certificates. */
1.21      inoguchi 1163:        if (untrusted != NULL &&
                   1164:            (ctx->certs = TS_CONF_load_certs(untrusted)) == NULL)
1.1       jsing    1165:                goto err;
                   1166:
                   1167:        ret = 1;
1.15      jsing    1168:  err:
1.1       jsing    1169:        if (!ret) {
                   1170:                TS_VERIFY_CTX_free(ctx);
                   1171:                ctx = NULL;
                   1172:        }
                   1173:        BIO_free_all(input);
                   1174:        TS_REQ_free(request);
                   1175:        return ctx;
                   1176: }
                   1177:
                   1178: static X509_STORE *
                   1179: create_cert_store(char *ca_path, char *ca_file)
                   1180: {
                   1181:        X509_STORE *cert_ctx = NULL;
                   1182:        X509_LOOKUP *lookup = NULL;
                   1183:        int i;
                   1184:
                   1185:        /* Creating the X509_STORE object. */
1.22      inoguchi 1186:        if ((cert_ctx = X509_STORE_new()) == NULL)
                   1187:                goto err;
1.1       jsing    1188:
                   1189:        /* Setting the callback for certificate chain verification. */
                   1190:        X509_STORE_set_verify_cb(cert_ctx, verify_cb);
                   1191:
                   1192:        /* Adding a trusted certificate directory source. */
1.21      inoguchi 1193:        if (ca_path != NULL) {
1.1       jsing    1194:                lookup = X509_STORE_add_lookup(cert_ctx,
                   1195:                    X509_LOOKUP_hash_dir());
                   1196:                if (lookup == NULL) {
                   1197:                        BIO_printf(bio_err, "memory allocation failure\n");
                   1198:                        goto err;
                   1199:                }
                   1200:                i = X509_LOOKUP_add_dir(lookup, ca_path, X509_FILETYPE_PEM);
                   1201:                if (!i) {
                   1202:                        BIO_printf(bio_err, "Error loading directory %s\n",
                   1203:                            ca_path);
                   1204:                        goto err;
                   1205:                }
                   1206:        }
                   1207:        /* Adding a trusted certificate file source. */
1.21      inoguchi 1208:        if (ca_file != NULL) {
1.1       jsing    1209:                lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());
                   1210:                if (lookup == NULL) {
                   1211:                        BIO_printf(bio_err, "memory allocation failure\n");
                   1212:                        goto err;
                   1213:                }
                   1214:                i = X509_LOOKUP_load_file(lookup, ca_file, X509_FILETYPE_PEM);
                   1215:                if (!i) {
                   1216:                        BIO_printf(bio_err, "Error loading file %s\n", ca_file);
                   1217:                        goto err;
                   1218:                }
                   1219:        }
                   1220:        return cert_ctx;
1.15      jsing    1221:  err:
1.1       jsing    1222:        X509_STORE_free(cert_ctx);
                   1223:        return NULL;
                   1224: }
                   1225:
                   1226: static int
1.19      inoguchi 1227: verify_cb(int ok, X509_STORE_CTX *ctx)
1.1       jsing    1228: {
                   1229:        /*
                   1230:        char buf[256];
                   1231:
                   1232:        if (!ok)
                   1233:                {
                   1234:                X509_NAME_oneline(X509_get_subject_name(ctx->current_cert),
                   1235:                                  buf, sizeof(buf));
                   1236:                printf("%s\n", buf);
                   1237:                printf("error %d at %d depth lookup: %s\n",
                   1238:                       ctx->error, ctx->error_depth,
                   1239:                        X509_verify_cert_error_string(ctx->error));
                   1240:                }
                   1241:        */
                   1242:
                   1243:        return ok;
                   1244: }