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

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