"Fossies" - the Fresh Open Source Software Archive

Member "openssl-1.1.1g/apps/ts.c" (21 Apr 2020, 30916 Bytes) of package /linux/misc/openssl-1.1.1g.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ts.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.1.1f_vs_1.1.1g.

    1 /*
    2  * Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved.
    3  *
    4  * Licensed under the OpenSSL license (the "License").  You may not use
    5  * this file except in compliance with the License.  You can obtain a copy
    6  * in the file LICENSE in the source distribution or at
    7  * https://www.openssl.org/source/license.html
    8  */
    9 
   10 #include <openssl/opensslconf.h>
   11 #include <stdio.h>
   12 #include <stdlib.h>
   13 #include <string.h>
   14 #include "apps.h"
   15 #include "progs.h"
   16 #include <openssl/bio.h>
   17 #include <openssl/err.h>
   18 #include <openssl/pem.h>
   19 #include <openssl/rand.h>
   20 #include <openssl/ts.h>
   21 #include <openssl/bn.h>
   22 
   23 /* Request nonce length, in bits (must be a multiple of 8). */
   24 #define NONCE_LENGTH            64
   25 
   26 /* Name of config entry that defines the OID file. */
   27 #define ENV_OID_FILE            "oid_file"
   28 
   29 /* Is |EXACTLY_ONE| of three pointers set? */
   30 #define EXACTLY_ONE(a, b, c) \
   31         (( a && !b && !c) || \
   32          ( b && !a && !c) || \
   33          ( c && !a && !b))
   34 
   35 static ASN1_OBJECT *txt2obj(const char *oid);
   36 static CONF *load_config_file(const char *configfile);
   37 
   38 /* Query related functions. */
   39 static int query_command(const char *data, const char *digest,
   40                          const EVP_MD *md, const char *policy, int no_nonce,
   41                          int cert, const char *in, const char *out, int text);
   42 static TS_REQ *create_query(BIO *data_bio, const char *digest, const EVP_MD *md,
   43                             const char *policy, int no_nonce, int cert);
   44 static int create_digest(BIO *input, const char *digest,
   45                          const EVP_MD *md, unsigned char **md_value);
   46 static ASN1_INTEGER *create_nonce(int bits);
   47 
   48 /* Reply related functions. */
   49 static int reply_command(CONF *conf, const char *section, const char *engine,
   50                          const char *queryfile, const char *passin, const char *inkey,
   51                          const EVP_MD *md, const char *signer, const char *chain,
   52                          const char *policy, const char *in, int token_in,
   53                          const char *out, int token_out, int text);
   54 static TS_RESP *read_PKCS7(BIO *in_bio);
   55 static TS_RESP *create_response(CONF *conf, const char *section, const char *engine,
   56                                 const char *queryfile, const char *passin,
   57                                 const char *inkey, const EVP_MD *md, const char *signer,
   58                                 const char *chain, const char *policy);
   59 static ASN1_INTEGER *serial_cb(TS_RESP_CTX *ctx, void *data);
   60 static ASN1_INTEGER *next_serial(const char *serialfile);
   61 static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial);
   62 
   63 /* Verify related functions. */
   64 static int verify_command(const char *data, const char *digest, const char *queryfile,
   65                           const char *in, int token_in,
   66                           const char *CApath, const char *CAfile, const char *untrusted,
   67                           X509_VERIFY_PARAM *vpm);
   68 static TS_VERIFY_CTX *create_verify_ctx(const char *data, const char *digest,
   69                                         const char *queryfile,
   70                                         const char *CApath, const char *CAfile,
   71                                         const char *untrusted,
   72                                         X509_VERIFY_PARAM *vpm);
   73 static X509_STORE *create_cert_store(const char *CApath, const char *CAfile,
   74                                      X509_VERIFY_PARAM *vpm);
   75 static int verify_cb(int ok, X509_STORE_CTX *ctx);
   76 
   77 typedef enum OPTION_choice {
   78     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
   79     OPT_ENGINE, OPT_CONFIG, OPT_SECTION, OPT_QUERY, OPT_DATA,
   80     OPT_DIGEST, OPT_TSPOLICY, OPT_NO_NONCE, OPT_CERT,
   81     OPT_IN, OPT_TOKEN_IN, OPT_OUT, OPT_TOKEN_OUT, OPT_TEXT,
   82     OPT_REPLY, OPT_QUERYFILE, OPT_PASSIN, OPT_INKEY, OPT_SIGNER,
   83     OPT_CHAIN, OPT_VERIFY, OPT_CAPATH, OPT_CAFILE, OPT_UNTRUSTED,
   84     OPT_MD, OPT_V_ENUM, OPT_R_ENUM
   85 } OPTION_CHOICE;
   86 
   87 const OPTIONS ts_options[] = {
   88     {"help", OPT_HELP, '-', "Display this summary"},
   89     {"config", OPT_CONFIG, '<', "Configuration file"},
   90     {"section", OPT_SECTION, 's', "Section to use within config file"},
   91     {"query", OPT_QUERY, '-', "Generate a TS query"},
   92     {"data", OPT_DATA, '<', "File to hash"},
   93     {"digest", OPT_DIGEST, 's', "Digest (as a hex string)"},
   94     OPT_R_OPTIONS,
   95     {"tspolicy", OPT_TSPOLICY, 's', "Policy OID to use"},
   96     {"no_nonce", OPT_NO_NONCE, '-', "Do not include a nonce"},
   97     {"cert", OPT_CERT, '-', "Put cert request into query"},
   98     {"in", OPT_IN, '<', "Input file"},
   99     {"token_in", OPT_TOKEN_IN, '-', "Input is a PKCS#7 file"},
  100     {"out", OPT_OUT, '>', "Output file"},
  101     {"token_out", OPT_TOKEN_OUT, '-', "Output is a PKCS#7 file"},
  102     {"text", OPT_TEXT, '-', "Output text (not DER)"},
  103     {"reply", OPT_REPLY, '-', "Generate a TS reply"},
  104     {"queryfile", OPT_QUERYFILE, '<', "File containing a TS query"},
  105     {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
  106     {"inkey", OPT_INKEY, 's', "File with private key for reply"},
  107     {"signer", OPT_SIGNER, 's', "Signer certificate file"},
  108     {"chain", OPT_CHAIN, '<', "File with signer CA chain"},
  109     {"verify", OPT_VERIFY, '-', "Verify a TS response"},
  110     {"CApath", OPT_CAPATH, '/', "Path to trusted CA files"},
  111     {"CAfile", OPT_CAFILE, '<', "File with trusted CA certs"},
  112     {"untrusted", OPT_UNTRUSTED, '<', "File with untrusted certs"},
  113     {"", OPT_MD, '-', "Any supported digest"},
  114 #ifndef OPENSSL_NO_ENGINE
  115     {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
  116 #endif
  117     {OPT_HELP_STR, 1, '-', "\nOptions specific to 'ts -verify': \n"},
  118     OPT_V_OPTIONS,
  119     {OPT_HELP_STR, 1, '-', "\n"},
  120     {NULL}
  121 };
  122 
  123 /*
  124  * This command is so complex, special help is needed.
  125  */
  126 static char* opt_helplist[] = {
  127     "Typical uses:",
  128     "ts -query [-rand file...] [-config file] [-data file]",
  129     "          [-digest hexstring] [-tspolicy oid] [-no_nonce] [-cert]",
  130     "          [-in file] [-out file] [-text]",
  131     "  or",
  132     "ts -reply [-config file] [-section tsa_section]",
  133     "          [-queryfile file] [-passin password]",
  134     "          [-signer tsa_cert.pem] [-inkey private_key.pem]",
  135     "          [-chain certs_file.pem] [-tspolicy oid]",
  136     "          [-in file] [-token_in] [-out file] [-token_out]",
  137 #ifndef OPENSSL_NO_ENGINE
  138     "          [-text] [-engine id]",
  139 #else
  140     "          [-text]",
  141 #endif
  142     "  or",
  143     "ts -verify -CApath dir -CAfile file.pem -untrusted file.pem",
  144     "           [-data file] [-digest hexstring]",
  145     "           [-queryfile file] -in file [-token_in]",
  146     "           [[options specific to 'ts -verify']]",
  147     NULL,
  148 };
  149 
  150 int ts_main(int argc, char **argv)
  151 {
  152     CONF *conf = NULL;
  153     const char *CAfile = NULL, *untrusted = NULL, *prog;
  154     const char *configfile = default_config_file, *engine = NULL;
  155     const char *section = NULL;
  156     char **helpp;
  157     char *password = NULL;
  158     char *data = NULL, *digest = NULL, *policy = NULL;
  159     char *in = NULL, *out = NULL, *queryfile = NULL, *passin = NULL;
  160     char *inkey = NULL, *signer = NULL, *chain = NULL, *CApath = NULL;
  161     const EVP_MD *md = NULL;
  162     OPTION_CHOICE o, mode = OPT_ERR;
  163     int ret = 1, no_nonce = 0, cert = 0, text = 0;
  164     int vpmtouched = 0;
  165     X509_VERIFY_PARAM *vpm = NULL;
  166     /* Input is ContentInfo instead of TimeStampResp. */
  167     int token_in = 0;
  168     /* Output is ContentInfo instead of TimeStampResp. */
  169     int token_out = 0;
  170 
  171     if ((vpm = X509_VERIFY_PARAM_new()) == NULL)
  172         goto end;
  173 
  174     prog = opt_init(argc, argv, ts_options);
  175     while ((o = opt_next()) != OPT_EOF) {
  176         switch (o) {
  177         case OPT_EOF:
  178         case OPT_ERR:
  179  opthelp:
  180             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
  181             goto end;
  182         case OPT_HELP:
  183             opt_help(ts_options);
  184             for (helpp = opt_helplist; *helpp; ++helpp)
  185                 BIO_printf(bio_err, "%s\n", *helpp);
  186             ret = 0;
  187             goto end;
  188         case OPT_CONFIG:
  189             configfile = opt_arg();
  190             break;
  191         case OPT_SECTION:
  192             section = opt_arg();
  193             break;
  194         case OPT_QUERY:
  195         case OPT_REPLY:
  196         case OPT_VERIFY:
  197             if (mode != OPT_ERR)
  198                 goto opthelp;
  199             mode = o;
  200             break;
  201         case OPT_DATA:
  202             data = opt_arg();
  203             break;
  204         case OPT_DIGEST:
  205             digest = opt_arg();
  206             break;
  207         case OPT_R_CASES:
  208             if (!opt_rand(o))
  209                 goto end;
  210             break;
  211         case OPT_TSPOLICY:
  212             policy = opt_arg();
  213             break;
  214         case OPT_NO_NONCE:
  215             no_nonce = 1;
  216             break;
  217         case OPT_CERT:
  218             cert = 1;
  219             break;
  220         case OPT_IN:
  221             in = opt_arg();
  222             break;
  223         case OPT_TOKEN_IN:
  224             token_in = 1;
  225             break;
  226         case OPT_OUT:
  227             out = opt_arg();
  228             break;
  229         case OPT_TOKEN_OUT:
  230             token_out = 1;
  231             break;
  232         case OPT_TEXT:
  233             text = 1;
  234             break;
  235         case OPT_QUERYFILE:
  236             queryfile = opt_arg();
  237             break;
  238         case OPT_PASSIN:
  239             passin = opt_arg();
  240             break;
  241         case OPT_INKEY:
  242             inkey = opt_arg();
  243             break;
  244         case OPT_SIGNER:
  245             signer = opt_arg();
  246             break;
  247         case OPT_CHAIN:
  248             chain = opt_arg();
  249             break;
  250         case OPT_CAPATH:
  251             CApath = opt_arg();
  252             break;
  253         case OPT_CAFILE:
  254             CAfile = opt_arg();
  255             break;
  256         case OPT_UNTRUSTED:
  257             untrusted = opt_arg();
  258             break;
  259         case OPT_ENGINE:
  260             engine = opt_arg();
  261             break;
  262         case OPT_MD:
  263             if (!opt_md(opt_unknown(), &md))
  264                 goto opthelp;
  265             break;
  266         case OPT_V_CASES:
  267             if (!opt_verify(o, vpm))
  268                 goto end;
  269             vpmtouched++;
  270             break;
  271         }
  272     }
  273     if (mode == OPT_ERR || opt_num_rest() != 0)
  274         goto opthelp;
  275 
  276     if (mode == OPT_REPLY && passin &&
  277         !app_passwd(passin, NULL, &password, NULL)) {
  278         BIO_printf(bio_err, "Error getting password.\n");
  279         goto end;
  280     }
  281 
  282     if ((conf = load_config_file(configfile)) == NULL)
  283         goto end;
  284     if (configfile != default_config_file && !app_load_modules(conf))
  285         goto end;
  286 
  287     /* Check parameter consistency and execute the appropriate function. */
  288     if (mode == OPT_QUERY) {
  289         if (vpmtouched)
  290             goto opthelp;
  291         if ((data != NULL) && (digest != NULL))
  292             goto opthelp;
  293         ret = !query_command(data, digest, md, policy, no_nonce, cert,
  294                              in, out, text);
  295     } else if (mode == OPT_REPLY) {
  296         if (vpmtouched)
  297             goto opthelp;
  298         if ((in != NULL) && (queryfile != NULL))
  299             goto opthelp;
  300         if (in == NULL) {
  301             if ((conf == NULL) || (token_in != 0))
  302                 goto opthelp;
  303         }
  304         ret = !reply_command(conf, section, engine, queryfile,
  305                              password, inkey, md, signer, chain, policy,
  306                              in, token_in, out, token_out, text);
  307 
  308     } else if (mode == OPT_VERIFY) {
  309         if ((in == NULL) || !EXACTLY_ONE(queryfile, data, digest))
  310             goto opthelp;
  311         ret = !verify_command(data, digest, queryfile, in, token_in,
  312                               CApath, CAfile, untrusted,
  313                               vpmtouched ? vpm : NULL);
  314     } else {
  315         goto opthelp;
  316     }
  317 
  318  end:
  319     X509_VERIFY_PARAM_free(vpm);
  320     NCONF_free(conf);
  321     OPENSSL_free(password);
  322     return ret;
  323 }
  324 
  325 /*
  326  * Configuration file-related function definitions.
  327  */
  328 
  329 static ASN1_OBJECT *txt2obj(const char *oid)
  330 {
  331     ASN1_OBJECT *oid_obj = NULL;
  332 
  333     if ((oid_obj = OBJ_txt2obj(oid, 0)) == NULL)
  334         BIO_printf(bio_err, "cannot convert %s to OID\n", oid);
  335 
  336     return oid_obj;
  337 }
  338 
  339 static CONF *load_config_file(const char *configfile)
  340 {
  341     CONF *conf = app_load_config(configfile);
  342 
  343     if (conf != NULL) {
  344         const char *p;
  345 
  346         BIO_printf(bio_err, "Using configuration from %s\n", configfile);
  347         p = NCONF_get_string(conf, NULL, ENV_OID_FILE);
  348         if (p != NULL) {
  349             BIO *oid_bio = BIO_new_file(p, "r");
  350             if (!oid_bio)
  351                 ERR_print_errors(bio_err);
  352             else {
  353                 OBJ_create_objects(oid_bio);
  354                 BIO_free_all(oid_bio);
  355             }
  356         } else
  357             ERR_clear_error();
  358         if (!add_oid_section(conf))
  359             ERR_print_errors(bio_err);
  360     }
  361     return conf;
  362 }
  363 
  364 /*
  365  * Query-related method definitions.
  366  */
  367 static int query_command(const char *data, const char *digest, const EVP_MD *md,
  368                          const char *policy, int no_nonce,
  369                          int cert, const char *in, const char *out, int text)
  370 {
  371     int ret = 0;
  372     TS_REQ *query = NULL;
  373     BIO *in_bio = NULL;
  374     BIO *data_bio = NULL;
  375     BIO *out_bio = NULL;
  376 
  377     /* Build query object. */
  378     if (in != NULL) {
  379         if ((in_bio = bio_open_default(in, 'r', FORMAT_ASN1)) == NULL)
  380             goto end;
  381         query = d2i_TS_REQ_bio(in_bio, NULL);
  382     } else {
  383         if (digest == NULL
  384             && (data_bio = bio_open_default(data, 'r', FORMAT_ASN1)) == NULL)
  385             goto end;
  386         query = create_query(data_bio, digest, md, policy, no_nonce, cert);
  387     }
  388     if (query == NULL)
  389         goto end;
  390 
  391     if (text) {
  392         if ((out_bio = bio_open_default(out, 'w', FORMAT_TEXT)) == NULL)
  393             goto end;
  394         if (!TS_REQ_print_bio(out_bio, query))
  395             goto end;
  396     } else {
  397         if ((out_bio = bio_open_default(out, 'w', FORMAT_ASN1)) == NULL)
  398             goto end;
  399         if (!i2d_TS_REQ_bio(out_bio, query))
  400             goto end;
  401     }
  402 
  403     ret = 1;
  404 
  405  end:
  406     ERR_print_errors(bio_err);
  407     BIO_free_all(in_bio);
  408     BIO_free_all(data_bio);
  409     BIO_free_all(out_bio);
  410     TS_REQ_free(query);
  411     return ret;
  412 }
  413 
  414 static TS_REQ *create_query(BIO *data_bio, const char *digest, const EVP_MD *md,
  415                             const char *policy, int no_nonce, int cert)
  416 {
  417     int ret = 0;
  418     TS_REQ *ts_req = NULL;
  419     int len;
  420     TS_MSG_IMPRINT *msg_imprint = NULL;
  421     X509_ALGOR *algo = NULL;
  422     unsigned char *data = NULL;
  423     ASN1_OBJECT *policy_obj = NULL;
  424     ASN1_INTEGER *nonce_asn1 = NULL;
  425 
  426     if (md == NULL && (md = EVP_get_digestbyname("sha1")) == NULL)
  427         goto err;
  428     if ((ts_req = TS_REQ_new()) == NULL)
  429         goto err;
  430     if (!TS_REQ_set_version(ts_req, 1))
  431         goto err;
  432     if ((msg_imprint = TS_MSG_IMPRINT_new()) == NULL)
  433         goto err;
  434     if ((algo = X509_ALGOR_new()) == NULL)
  435         goto err;
  436     if ((algo->algorithm = OBJ_nid2obj(EVP_MD_type(md))) == NULL)
  437         goto err;
  438     if ((algo->parameter = ASN1_TYPE_new()) == NULL)
  439         goto err;
  440     algo->parameter->type = V_ASN1_NULL;
  441     if (!TS_MSG_IMPRINT_set_algo(msg_imprint, algo))
  442         goto err;
  443     if ((len = create_digest(data_bio, digest, md, &data)) == 0)
  444         goto err;
  445     if (!TS_MSG_IMPRINT_set_msg(msg_imprint, data, len))
  446         goto err;
  447     if (!TS_REQ_set_msg_imprint(ts_req, msg_imprint))
  448         goto err;
  449     if (policy && (policy_obj = txt2obj(policy)) == NULL)
  450         goto err;
  451     if (policy_obj && !TS_REQ_set_policy_id(ts_req, policy_obj))
  452         goto err;
  453 
  454     /* Setting nonce if requested. */
  455     if (!no_nonce && (nonce_asn1 = create_nonce(NONCE_LENGTH)) == NULL)
  456         goto err;
  457     if (nonce_asn1 && !TS_REQ_set_nonce(ts_req, nonce_asn1))
  458         goto err;
  459     if (!TS_REQ_set_cert_req(ts_req, cert))
  460         goto err;
  461 
  462     ret = 1;
  463  err:
  464     if (!ret) {
  465         TS_REQ_free(ts_req);
  466         ts_req = NULL;
  467         BIO_printf(bio_err, "could not create query\n");
  468         ERR_print_errors(bio_err);
  469     }
  470     TS_MSG_IMPRINT_free(msg_imprint);
  471     X509_ALGOR_free(algo);
  472     OPENSSL_free(data);
  473     ASN1_OBJECT_free(policy_obj);
  474     ASN1_INTEGER_free(nonce_asn1);
  475     return ts_req;
  476 }
  477 
  478 static int create_digest(BIO *input, const char *digest, const EVP_MD *md,
  479                          unsigned char **md_value)
  480 {
  481     int md_value_len;
  482     int rv = 0;
  483     EVP_MD_CTX *md_ctx = NULL;
  484 
  485     md_value_len = EVP_MD_size(md);
  486     if (md_value_len < 0)
  487         return 0;
  488 
  489     if (input != NULL) {
  490         unsigned char buffer[4096];
  491         int length;
  492 
  493         md_ctx = EVP_MD_CTX_new();
  494         if (md_ctx == NULL)
  495             return 0;
  496         *md_value = app_malloc(md_value_len, "digest buffer");
  497         if (!EVP_DigestInit(md_ctx, md))
  498             goto err;
  499         while ((length = BIO_read(input, buffer, sizeof(buffer))) > 0) {
  500             if (!EVP_DigestUpdate(md_ctx, buffer, length))
  501                 goto err;
  502         }
  503         if (!EVP_DigestFinal(md_ctx, *md_value, NULL))
  504             goto err;
  505         md_value_len = EVP_MD_size(md);
  506     } else {
  507         long digest_len;
  508         *md_value = OPENSSL_hexstr2buf(digest, &digest_len);
  509         if (!*md_value || md_value_len != digest_len) {
  510             OPENSSL_free(*md_value);
  511             *md_value = NULL;
  512             BIO_printf(bio_err, "bad digest, %d bytes "
  513                        "must be specified\n", md_value_len);
  514             return 0;
  515         }
  516     }
  517     rv = md_value_len;
  518  err:
  519     EVP_MD_CTX_free(md_ctx);
  520     return rv;
  521 }
  522 
  523 static ASN1_INTEGER *create_nonce(int bits)
  524 {
  525     unsigned char buf[20];
  526     ASN1_INTEGER *nonce = NULL;
  527     int len = (bits - 1) / 8 + 1;
  528     int i;
  529 
  530     if (len > (int)sizeof(buf))
  531         goto err;
  532     if (RAND_bytes(buf, len) <= 0)
  533         goto err;
  534 
  535     /* Find the first non-zero byte and creating ASN1_INTEGER object. */
  536     for (i = 0; i < len && !buf[i]; ++i)
  537         continue;
  538     if ((nonce = ASN1_INTEGER_new()) == NULL)
  539         goto err;
  540     OPENSSL_free(nonce->data);
  541     nonce->length = len - i;
  542     nonce->data = app_malloc(nonce->length + 1, "nonce buffer");
  543     memcpy(nonce->data, buf + i, nonce->length);
  544     return nonce;
  545 
  546  err:
  547     BIO_printf(bio_err, "could not create nonce\n");
  548     ASN1_INTEGER_free(nonce);
  549     return NULL;
  550 }
  551 
  552 /*
  553  * Reply-related method definitions.
  554  */
  555 
  556 static int reply_command(CONF *conf, const char *section, const char *engine,
  557                          const char *queryfile, const char *passin, const char *inkey,
  558                          const EVP_MD *md, const char *signer, const char *chain,
  559                          const char *policy, const char *in, int token_in,
  560                          const char *out, int token_out, int text)
  561 {
  562     int ret = 0;
  563     TS_RESP *response = NULL;
  564     BIO *in_bio = NULL;
  565     BIO *query_bio = NULL;
  566     BIO *inkey_bio = NULL;
  567     BIO *signer_bio = NULL;
  568     BIO *out_bio = NULL;
  569 
  570     if (in != NULL) {
  571         if ((in_bio = BIO_new_file(in, "rb")) == NULL)
  572             goto end;
  573         if (token_in) {
  574             response = read_PKCS7(in_bio);
  575         } else {
  576             response = d2i_TS_RESP_bio(in_bio, NULL);
  577         }
  578     } else {
  579         response = create_response(conf, section, engine, queryfile,
  580                                    passin, inkey, md, signer, chain, policy);
  581         if (response != NULL)
  582             BIO_printf(bio_err, "Response has been generated.\n");
  583         else
  584             BIO_printf(bio_err, "Response is not generated.\n");
  585     }
  586     if (response == NULL)
  587         goto end;
  588 
  589     /* Write response. */
  590     if (text) {
  591         if ((out_bio = bio_open_default(out, 'w', FORMAT_TEXT)) == NULL)
  592         goto end;
  593         if (token_out) {
  594             TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response);
  595             if (!TS_TST_INFO_print_bio(out_bio, tst_info))
  596                 goto end;
  597         } else {
  598             if (!TS_RESP_print_bio(out_bio, response))
  599                 goto end;
  600         }
  601     } else {
  602         if ((out_bio = bio_open_default(out, 'w', FORMAT_ASN1)) == NULL)
  603             goto end;
  604         if (token_out) {
  605             PKCS7 *token = TS_RESP_get_token(response);
  606             if (!i2d_PKCS7_bio(out_bio, token))
  607                 goto end;
  608         } else {
  609             if (!i2d_TS_RESP_bio(out_bio, response))
  610                 goto end;
  611         }
  612     }
  613 
  614     ret = 1;
  615 
  616  end:
  617     ERR_print_errors(bio_err);
  618     BIO_free_all(in_bio);
  619     BIO_free_all(query_bio);
  620     BIO_free_all(inkey_bio);
  621     BIO_free_all(signer_bio);
  622     BIO_free_all(out_bio);
  623     TS_RESP_free(response);
  624     return ret;
  625 }
  626 
  627 /* Reads a PKCS7 token and adds default 'granted' status info to it. */
  628 static TS_RESP *read_PKCS7(BIO *in_bio)
  629 {
  630     int ret = 0;
  631     PKCS7 *token = NULL;
  632     TS_TST_INFO *tst_info = NULL;
  633     TS_RESP *resp = NULL;
  634     TS_STATUS_INFO *si = NULL;
  635 
  636     if ((token = d2i_PKCS7_bio(in_bio, NULL)) == NULL)
  637         goto end;
  638     if ((tst_info = PKCS7_to_TS_TST_INFO(token)) == NULL)
  639         goto end;
  640     if ((resp = TS_RESP_new()) == NULL)
  641         goto end;
  642     if ((si = TS_STATUS_INFO_new()) == NULL)
  643         goto end;
  644     if (!TS_STATUS_INFO_set_status(si, TS_STATUS_GRANTED))
  645         goto end;
  646     if (!TS_RESP_set_status_info(resp, si))
  647         goto end;
  648     TS_RESP_set_tst_info(resp, token, tst_info);
  649     token = NULL;               /* Ownership is lost. */
  650     tst_info = NULL;            /* Ownership is lost. */
  651     ret = 1;
  652 
  653  end:
  654     PKCS7_free(token);
  655     TS_TST_INFO_free(tst_info);
  656     if (!ret) {
  657         TS_RESP_free(resp);
  658         resp = NULL;
  659     }
  660     TS_STATUS_INFO_free(si);
  661     return resp;
  662 }
  663 
  664 static TS_RESP *create_response(CONF *conf, const char *section, const char *engine,
  665                                 const char *queryfile, const char *passin,
  666                                 const char *inkey, const EVP_MD *md, const char *signer,
  667                                 const char *chain, const char *policy)
  668 {
  669     int ret = 0;
  670     TS_RESP *response = NULL;
  671     BIO *query_bio = NULL;
  672     TS_RESP_CTX *resp_ctx = NULL;
  673 
  674     if ((query_bio = BIO_new_file(queryfile, "rb")) == NULL)
  675         goto end;
  676     if ((section = TS_CONF_get_tsa_section(conf, section)) == NULL)
  677         goto end;
  678     if ((resp_ctx = TS_RESP_CTX_new()) == NULL)
  679         goto end;
  680     if (!TS_CONF_set_serial(conf, section, serial_cb, resp_ctx))
  681         goto end;
  682 #ifndef OPENSSL_NO_ENGINE
  683     if (!TS_CONF_set_crypto_device(conf, section, engine))
  684         goto end;
  685 #endif
  686     if (!TS_CONF_set_signer_cert(conf, section, signer, resp_ctx))
  687         goto end;
  688     if (!TS_CONF_set_certs(conf, section, chain, resp_ctx))
  689         goto end;
  690     if (!TS_CONF_set_signer_key(conf, section, inkey, passin, resp_ctx))
  691         goto end;
  692 
  693     if (md) {
  694         if (!TS_RESP_CTX_set_signer_digest(resp_ctx, md))
  695             goto end;
  696     } else if (!TS_CONF_set_signer_digest(conf, section, NULL, resp_ctx)) {
  697             goto end;
  698     }
  699 
  700     if (!TS_CONF_set_ess_cert_id_digest(conf, section, resp_ctx))
  701         goto end;
  702     if (!TS_CONF_set_def_policy(conf, section, policy, resp_ctx))
  703         goto end;
  704     if (!TS_CONF_set_policies(conf, section, resp_ctx))
  705         goto end;
  706     if (!TS_CONF_set_digests(conf, section, resp_ctx))
  707         goto end;
  708     if (!TS_CONF_set_accuracy(conf, section, resp_ctx))
  709         goto end;
  710     if (!TS_CONF_set_clock_precision_digits(conf, section, resp_ctx))
  711         goto end;
  712     if (!TS_CONF_set_ordering(conf, section, resp_ctx))
  713         goto end;
  714     if (!TS_CONF_set_tsa_name(conf, section, resp_ctx))
  715         goto end;
  716     if (!TS_CONF_set_ess_cert_id_chain(conf, section, resp_ctx))
  717         goto end;
  718     if ((response = TS_RESP_create_response(resp_ctx, query_bio)) == NULL)
  719         goto end;
  720     ret = 1;
  721 
  722  end:
  723     if (!ret) {
  724         TS_RESP_free(response);
  725         response = NULL;
  726     }
  727     TS_RESP_CTX_free(resp_ctx);
  728     BIO_free_all(query_bio);
  729     return response;
  730 }
  731 
  732 static ASN1_INTEGER *serial_cb(TS_RESP_CTX *ctx, void *data)
  733 {
  734     const char *serial_file = (const char *)data;
  735     ASN1_INTEGER *serial = next_serial(serial_file);
  736 
  737     if (serial == NULL) {
  738         TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
  739                                     "Error during serial number "
  740                                     "generation.");
  741         TS_RESP_CTX_add_failure_info(ctx, TS_INFO_ADD_INFO_NOT_AVAILABLE);
  742     } else {
  743         save_ts_serial(serial_file, serial);
  744     }
  745 
  746     return serial;
  747 }
  748 
  749 static ASN1_INTEGER *next_serial(const char *serialfile)
  750 {
  751     int ret = 0;
  752     BIO *in = NULL;
  753     ASN1_INTEGER *serial = NULL;
  754     BIGNUM *bn = NULL;
  755 
  756     if ((serial = ASN1_INTEGER_new()) == NULL)
  757         goto err;
  758 
  759     if ((in = BIO_new_file(serialfile, "r")) == NULL) {
  760         ERR_clear_error();
  761         BIO_printf(bio_err, "Warning: could not open file %s for "
  762                    "reading, using serial number: 1\n", serialfile);
  763         if (!ASN1_INTEGER_set(serial, 1))
  764             goto err;
  765     } else {
  766         char buf[1024];
  767         if (!a2i_ASN1_INTEGER(in, serial, buf, sizeof(buf))) {
  768             BIO_printf(bio_err, "unable to load number from %s\n",
  769                        serialfile);
  770             goto err;
  771         }
  772         if ((bn = ASN1_INTEGER_to_BN(serial, NULL)) == NULL)
  773             goto err;
  774         ASN1_INTEGER_free(serial);
  775         serial = NULL;
  776         if (!BN_add_word(bn, 1))
  777             goto err;
  778         if ((serial = BN_to_ASN1_INTEGER(bn, NULL)) == NULL)
  779             goto err;
  780     }
  781     ret = 1;
  782 
  783  err:
  784     if (!ret) {
  785         ASN1_INTEGER_free(serial);
  786         serial = NULL;
  787     }
  788     BIO_free_all(in);
  789     BN_free(bn);
  790     return serial;
  791 }
  792 
  793 static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial)
  794 {
  795     int ret = 0;
  796     BIO *out = NULL;
  797 
  798     if ((out = BIO_new_file(serialfile, "w")) == NULL)
  799         goto err;
  800     if (i2a_ASN1_INTEGER(out, serial) <= 0)
  801         goto err;
  802     if (BIO_puts(out, "\n") <= 0)
  803         goto err;
  804     ret = 1;
  805  err:
  806     if (!ret)
  807         BIO_printf(bio_err, "could not save serial number to %s\n",
  808                    serialfile);
  809     BIO_free_all(out);
  810     return ret;
  811 }
  812 
  813 
  814 /*
  815  * Verify-related method definitions.
  816  */
  817 
  818 static int verify_command(const char *data, const char *digest, const char *queryfile,
  819                           const char *in, int token_in,
  820                           const char *CApath, const char *CAfile, const char *untrusted,
  821                           X509_VERIFY_PARAM *vpm)
  822 {
  823     BIO *in_bio = NULL;
  824     PKCS7 *token = NULL;
  825     TS_RESP *response = NULL;
  826     TS_VERIFY_CTX *verify_ctx = NULL;
  827     int ret = 0;
  828 
  829     if ((in_bio = BIO_new_file(in, "rb")) == NULL)
  830         goto end;
  831     if (token_in) {
  832         if ((token = d2i_PKCS7_bio(in_bio, NULL)) == NULL)
  833             goto end;
  834     } else {
  835         if ((response = d2i_TS_RESP_bio(in_bio, NULL)) == NULL)
  836             goto end;
  837     }
  838 
  839     if ((verify_ctx = create_verify_ctx(data, digest, queryfile,
  840                                         CApath, CAfile, untrusted,
  841                                         vpm)) == NULL)
  842         goto end;
  843 
  844     ret = token_in
  845         ? TS_RESP_verify_token(verify_ctx, token)
  846         : TS_RESP_verify_response(verify_ctx, response);
  847 
  848  end:
  849     printf("Verification: ");
  850     if (ret)
  851         printf("OK\n");
  852     else {
  853         printf("FAILED\n");
  854         ERR_print_errors(bio_err);
  855     }
  856 
  857     BIO_free_all(in_bio);
  858     PKCS7_free(token);
  859     TS_RESP_free(response);
  860     TS_VERIFY_CTX_free(verify_ctx);
  861     return ret;
  862 }
  863 
  864 static TS_VERIFY_CTX *create_verify_ctx(const char *data, const char *digest,
  865                                         const char *queryfile,
  866                                         const char *CApath, const char *CAfile,
  867                                         const char *untrusted,
  868                                         X509_VERIFY_PARAM *vpm)
  869 {
  870     TS_VERIFY_CTX *ctx = NULL;
  871     BIO *input = NULL;
  872     TS_REQ *request = NULL;
  873     int ret = 0;
  874     int f = 0;
  875 
  876     if (data != NULL || digest != NULL) {
  877         if ((ctx = TS_VERIFY_CTX_new()) == NULL)
  878             goto err;
  879         f = TS_VFY_VERSION | TS_VFY_SIGNER;
  880         if (data != NULL) {
  881             BIO *out = NULL;
  882 
  883             f |= TS_VFY_DATA;
  884             if ((out = BIO_new_file(data, "rb")) == NULL)
  885                 goto err;
  886             if (TS_VERIFY_CTX_set_data(ctx, out) == NULL) {
  887                 BIO_free_all(out);
  888                 goto err;
  889             }
  890         } else if (digest != NULL) {
  891             long imprint_len;
  892             unsigned char *hexstr = OPENSSL_hexstr2buf(digest, &imprint_len);
  893             f |= TS_VFY_IMPRINT;
  894             if (TS_VERIFY_CTX_set_imprint(ctx, hexstr, imprint_len) == NULL) {
  895                 BIO_printf(bio_err, "invalid digest string\n");
  896                 goto err;
  897             }
  898         }
  899 
  900     } else if (queryfile != NULL) {
  901         if ((input = BIO_new_file(queryfile, "rb")) == NULL)
  902             goto err;
  903         if ((request = d2i_TS_REQ_bio(input, NULL)) == NULL)
  904             goto err;
  905         if ((ctx = TS_REQ_to_TS_VERIFY_CTX(request, NULL)) == NULL)
  906             goto err;
  907     } else {
  908         return NULL;
  909     }
  910 
  911     /* Add the signature verification flag and arguments. */
  912     TS_VERIFY_CTX_add_flags(ctx, f | TS_VFY_SIGNATURE);
  913 
  914     /* Initialising the X509_STORE object. */
  915     if (TS_VERIFY_CTX_set_store(ctx, create_cert_store(CApath, CAfile, vpm))
  916             == NULL)
  917         goto err;
  918 
  919     /* Loading untrusted certificates. */
  920     if (untrusted
  921         && TS_VERIFY_CTS_set_certs(ctx, TS_CONF_load_certs(untrusted)) == NULL)
  922         goto err;
  923     ret = 1;
  924 
  925  err:
  926     if (!ret) {
  927         TS_VERIFY_CTX_free(ctx);
  928         ctx = NULL;
  929     }
  930     BIO_free_all(input);
  931     TS_REQ_free(request);
  932     return ctx;
  933 }
  934 
  935 static X509_STORE *create_cert_store(const char *CApath, const char *CAfile,
  936                                      X509_VERIFY_PARAM *vpm)
  937 {
  938     X509_STORE *cert_ctx = NULL;
  939     X509_LOOKUP *lookup = NULL;
  940     int i;
  941 
  942     cert_ctx = X509_STORE_new();
  943     X509_STORE_set_verify_cb(cert_ctx, verify_cb);
  944     if (CApath != NULL) {
  945         lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir());
  946         if (lookup == NULL) {
  947             BIO_printf(bio_err, "memory allocation failure\n");
  948             goto err;
  949         }
  950         i = X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM);
  951         if (!i) {
  952             BIO_printf(bio_err, "Error loading directory %s\n", CApath);
  953             goto err;
  954         }
  955     }
  956 
  957     if (CAfile != NULL) {
  958         lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());
  959         if (lookup == NULL) {
  960             BIO_printf(bio_err, "memory allocation failure\n");
  961             goto err;
  962         }
  963         i = X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM);
  964         if (!i) {
  965             BIO_printf(bio_err, "Error loading file %s\n", CAfile);
  966             goto err;
  967         }
  968     }
  969 
  970     if (vpm != NULL)
  971         X509_STORE_set1_param(cert_ctx, vpm);
  972 
  973     return cert_ctx;
  974 
  975  err:
  976     X509_STORE_free(cert_ctx);
  977     return NULL;
  978 }
  979 
  980 static int verify_cb(int ok, X509_STORE_CTX *ctx)
  981 {
  982     return ok;
  983 }