1238384Sjkim/* apps/ts.c */ 2280304Sjkim/* 3280304Sjkim * Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL project 4280304Sjkim * 2002. 5238384Sjkim */ 6238384Sjkim/* ==================================================================== 7238384Sjkim * Copyright (c) 2001 The OpenSSL Project. All rights reserved. 8238384Sjkim * 9238384Sjkim * Redistribution and use in source and binary forms, with or without 10238384Sjkim * modification, are permitted provided that the following conditions 11238384Sjkim * are met: 12238384Sjkim * 13238384Sjkim * 1. Redistributions of source code must retain the above copyright 14280304Sjkim * notice, this list of conditions and the following disclaimer. 15238384Sjkim * 16238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright 17238384Sjkim * notice, this list of conditions and the following disclaimer in 18238384Sjkim * the documentation and/or other materials provided with the 19238384Sjkim * distribution. 20238384Sjkim * 21238384Sjkim * 3. All advertising materials mentioning features or use of this 22238384Sjkim * software must display the following acknowledgment: 23238384Sjkim * "This product includes software developed by the OpenSSL Project 24238384Sjkim * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25238384Sjkim * 26238384Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27238384Sjkim * endorse or promote products derived from this software without 28238384Sjkim * prior written permission. For written permission, please contact 29238384Sjkim * licensing@OpenSSL.org. 30238384Sjkim * 31238384Sjkim * 5. Products derived from this software may not be called "OpenSSL" 32238384Sjkim * nor may "OpenSSL" appear in their names without prior written 33238384Sjkim * permission of the OpenSSL Project. 34238384Sjkim * 35238384Sjkim * 6. Redistributions of any form whatsoever must retain the following 36238384Sjkim * acknowledgment: 37238384Sjkim * "This product includes software developed by the OpenSSL Project 38238384Sjkim * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39238384Sjkim * 40238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41238384Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43238384Sjkim * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44238384Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45238384Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46238384Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47238384Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49238384Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51238384Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE. 52238384Sjkim * ==================================================================== 53238384Sjkim * 54238384Sjkim * This product includes cryptographic software written by Eric Young 55238384Sjkim * (eay@cryptsoft.com). This product includes software written by Tim 56238384Sjkim * Hudson (tjh@cryptsoft.com). 57238384Sjkim * 58238384Sjkim */ 59238384Sjkim 60238384Sjkim#include <stdio.h> 61238384Sjkim#include <stdlib.h> 62238384Sjkim#include <string.h> 63238384Sjkim#include "apps.h" 64238384Sjkim#include <openssl/bio.h> 65238384Sjkim#include <openssl/err.h> 66238384Sjkim#include <openssl/pem.h> 67238384Sjkim#include <openssl/rand.h> 68238384Sjkim#include <openssl/ts.h> 69238384Sjkim#include <openssl/bn.h> 70238384Sjkim 71238384Sjkim#undef PROG 72280304Sjkim#define PROG ts_main 73238384Sjkim 74238384Sjkim/* Length of the nonce of the request in bits (must be a multiple of 8). */ 75280304Sjkim#define NONCE_LENGTH 64 76238384Sjkim 77238384Sjkim/* Macro definitions for the configuration file. */ 78280304Sjkim#define ENV_OID_FILE "oid_file" 79238384Sjkim 80238384Sjkim/* Local function declarations. */ 81238384Sjkim 82238384Sjkimstatic ASN1_OBJECT *txt2obj(const char *oid); 83238384Sjkimstatic CONF *load_config_file(const char *configfile); 84238384Sjkim 85238384Sjkim/* Query related functions. */ 86238384Sjkimstatic int query_command(const char *data, char *digest, 87280304Sjkim const EVP_MD *md, const char *policy, int no_nonce, 88280304Sjkim int cert, const char *in, const char *out, int text); 89280304Sjkimstatic BIO *BIO_open_with_default(const char *file, const char *mode, 90280304Sjkim FILE *default_fp); 91238384Sjkimstatic TS_REQ *create_query(BIO *data_bio, char *digest, const EVP_MD *md, 92280304Sjkim const char *policy, int no_nonce, int cert); 93238384Sjkimstatic int create_digest(BIO *input, char *digest, 94280304Sjkim const EVP_MD *md, unsigned char **md_value); 95238384Sjkimstatic ASN1_INTEGER *create_nonce(int bits); 96238384Sjkim 97238384Sjkim/* Reply related functions. */ 98280304Sjkimstatic int reply_command(CONF *conf, char *section, char *engine, 99280304Sjkim char *queryfile, char *passin, char *inkey, 100280304Sjkim char *signer, char *chain, const char *policy, 101280304Sjkim char *in, int token_in, char *out, int token_out, 102280304Sjkim int text); 103238384Sjkimstatic TS_RESP *read_PKCS7(BIO *in_bio); 104238384Sjkimstatic TS_RESP *create_response(CONF *conf, const char *section, char *engine, 105280304Sjkim char *queryfile, char *passin, char *inkey, 106280304Sjkim char *signer, char *chain, 107280304Sjkim const char *policy); 108280304Sjkimstatic ASN1_INTEGER *MS_CALLBACK serial_cb(TS_RESP_CTX *ctx, void *data); 109238384Sjkimstatic ASN1_INTEGER *next_serial(const char *serialfile); 110238384Sjkimstatic int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial); 111238384Sjkim 112238384Sjkim/* Verify related functions. */ 113238384Sjkimstatic int verify_command(char *data, char *digest, char *queryfile, 114280304Sjkim char *in, int token_in, 115280304Sjkim char *ca_path, char *ca_file, char *untrusted); 116280304Sjkimstatic TS_VERIFY_CTX *create_verify_ctx(char *data, char *digest, 117280304Sjkim char *queryfile, 118280304Sjkim char *ca_path, char *ca_file, 119280304Sjkim char *untrusted); 120238384Sjkimstatic X509_STORE *create_cert_store(char *ca_path, char *ca_file); 121238384Sjkimstatic int MS_CALLBACK verify_cb(int ok, X509_STORE_CTX *ctx); 122238384Sjkim 123238384Sjkim/* Main function definition. */ 124238384Sjkimint MAIN(int, char **); 125238384Sjkim 126238384Sjkimint MAIN(int argc, char **argv) 127280304Sjkim{ 128280304Sjkim int ret = 1; 129280304Sjkim char *configfile = NULL; 130280304Sjkim char *section = NULL; 131280304Sjkim CONF *conf = NULL; 132280304Sjkim enum mode { 133280304Sjkim CMD_NONE, CMD_QUERY, CMD_REPLY, CMD_VERIFY 134280304Sjkim } mode = CMD_NONE; 135280304Sjkim char *data = NULL; 136280304Sjkim char *digest = NULL; 137280304Sjkim const EVP_MD *md = NULL; 138280304Sjkim char *rnd = NULL; 139280304Sjkim char *policy = NULL; 140280304Sjkim int no_nonce = 0; 141280304Sjkim int cert = 0; 142280304Sjkim char *in = NULL; 143280304Sjkim char *out = NULL; 144280304Sjkim int text = 0; 145280304Sjkim char *queryfile = NULL; 146280304Sjkim char *passin = NULL; /* Password source. */ 147280304Sjkim char *password = NULL; /* Password itself. */ 148280304Sjkim char *inkey = NULL; 149280304Sjkim char *signer = NULL; 150280304Sjkim char *chain = NULL; 151280304Sjkim char *ca_path = NULL; 152280304Sjkim char *ca_file = NULL; 153280304Sjkim char *untrusted = NULL; 154280304Sjkim char *engine = NULL; 155280304Sjkim /* Input is ContentInfo instead of TimeStampResp. */ 156280304Sjkim int token_in = 0; 157280304Sjkim /* Output is ContentInfo instead of TimeStampResp. */ 158280304Sjkim int token_out = 0; 159280304Sjkim int free_bio_err = 0; 160238384Sjkim 161280304Sjkim ERR_load_crypto_strings(); 162280304Sjkim apps_startup(); 163238384Sjkim 164280304Sjkim if (bio_err == NULL && (bio_err = BIO_new(BIO_s_file())) != NULL) { 165280304Sjkim free_bio_err = 1; 166280304Sjkim BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT); 167280304Sjkim } 168238384Sjkim 169280304Sjkim if (!load_config(bio_err, NULL)) 170280304Sjkim goto cleanup; 171238384Sjkim 172280304Sjkim for (argc--, argv++; argc > 0; argc--, argv++) { 173280304Sjkim if (strcmp(*argv, "-config") == 0) { 174280304Sjkim if (argc-- < 1) 175280304Sjkim goto usage; 176280304Sjkim configfile = *++argv; 177280304Sjkim } else if (strcmp(*argv, "-section") == 0) { 178280304Sjkim if (argc-- < 1) 179280304Sjkim goto usage; 180280304Sjkim section = *++argv; 181280304Sjkim } else if (strcmp(*argv, "-query") == 0) { 182280304Sjkim if (mode != CMD_NONE) 183280304Sjkim goto usage; 184280304Sjkim mode = CMD_QUERY; 185280304Sjkim } else if (strcmp(*argv, "-data") == 0) { 186280304Sjkim if (argc-- < 1) 187280304Sjkim goto usage; 188280304Sjkim data = *++argv; 189280304Sjkim } else if (strcmp(*argv, "-digest") == 0) { 190280304Sjkim if (argc-- < 1) 191280304Sjkim goto usage; 192280304Sjkim digest = *++argv; 193280304Sjkim } else if (strcmp(*argv, "-rand") == 0) { 194280304Sjkim if (argc-- < 1) 195280304Sjkim goto usage; 196280304Sjkim rnd = *++argv; 197280304Sjkim } else if (strcmp(*argv, "-policy") == 0) { 198280304Sjkim if (argc-- < 1) 199280304Sjkim goto usage; 200280304Sjkim policy = *++argv; 201280304Sjkim } else if (strcmp(*argv, "-no_nonce") == 0) { 202280304Sjkim no_nonce = 1; 203280304Sjkim } else if (strcmp(*argv, "-cert") == 0) { 204280304Sjkim cert = 1; 205280304Sjkim } else if (strcmp(*argv, "-in") == 0) { 206280304Sjkim if (argc-- < 1) 207280304Sjkim goto usage; 208280304Sjkim in = *++argv; 209280304Sjkim } else if (strcmp(*argv, "-token_in") == 0) { 210280304Sjkim token_in = 1; 211280304Sjkim } else if (strcmp(*argv, "-out") == 0) { 212280304Sjkim if (argc-- < 1) 213280304Sjkim goto usage; 214280304Sjkim out = *++argv; 215280304Sjkim } else if (strcmp(*argv, "-token_out") == 0) { 216280304Sjkim token_out = 1; 217280304Sjkim } else if (strcmp(*argv, "-text") == 0) { 218280304Sjkim text = 1; 219280304Sjkim } else if (strcmp(*argv, "-reply") == 0) { 220280304Sjkim if (mode != CMD_NONE) 221280304Sjkim goto usage; 222280304Sjkim mode = CMD_REPLY; 223280304Sjkim } else if (strcmp(*argv, "-queryfile") == 0) { 224280304Sjkim if (argc-- < 1) 225280304Sjkim goto usage; 226280304Sjkim queryfile = *++argv; 227280304Sjkim } else if (strcmp(*argv, "-passin") == 0) { 228280304Sjkim if (argc-- < 1) 229280304Sjkim goto usage; 230280304Sjkim passin = *++argv; 231280304Sjkim } else if (strcmp(*argv, "-inkey") == 0) { 232280304Sjkim if (argc-- < 1) 233280304Sjkim goto usage; 234280304Sjkim inkey = *++argv; 235280304Sjkim } else if (strcmp(*argv, "-signer") == 0) { 236280304Sjkim if (argc-- < 1) 237280304Sjkim goto usage; 238280304Sjkim signer = *++argv; 239280304Sjkim } else if (strcmp(*argv, "-chain") == 0) { 240280304Sjkim if (argc-- < 1) 241280304Sjkim goto usage; 242280304Sjkim chain = *++argv; 243280304Sjkim } else if (strcmp(*argv, "-verify") == 0) { 244280304Sjkim if (mode != CMD_NONE) 245280304Sjkim goto usage; 246280304Sjkim mode = CMD_VERIFY; 247280304Sjkim } else if (strcmp(*argv, "-CApath") == 0) { 248280304Sjkim if (argc-- < 1) 249280304Sjkim goto usage; 250280304Sjkim ca_path = *++argv; 251280304Sjkim } else if (strcmp(*argv, "-CAfile") == 0) { 252280304Sjkim if (argc-- < 1) 253280304Sjkim goto usage; 254280304Sjkim ca_file = *++argv; 255280304Sjkim } else if (strcmp(*argv, "-untrusted") == 0) { 256280304Sjkim if (argc-- < 1) 257280304Sjkim goto usage; 258280304Sjkim untrusted = *++argv; 259280304Sjkim } else if (strcmp(*argv, "-engine") == 0) { 260280304Sjkim if (argc-- < 1) 261280304Sjkim goto usage; 262280304Sjkim engine = *++argv; 263280304Sjkim } else if ((md = EVP_get_digestbyname(*argv + 1)) != NULL) { 264280304Sjkim /* empty. */ 265280304Sjkim } else 266280304Sjkim goto usage; 267280304Sjkim } 268238384Sjkim 269280304Sjkim /* Seed the random number generator if it is going to be used. */ 270280304Sjkim if (mode == CMD_QUERY && !no_nonce) { 271280304Sjkim if (!app_RAND_load_file(NULL, bio_err, 1) && rnd == NULL) 272280304Sjkim BIO_printf(bio_err, "warning, not much extra random " 273280304Sjkim "data, consider using the -rand option\n"); 274280304Sjkim if (rnd != NULL) 275280304Sjkim BIO_printf(bio_err, "%ld semi-random bytes loaded\n", 276280304Sjkim app_RAND_load_files(rnd)); 277280304Sjkim } 278238384Sjkim 279280304Sjkim /* Get the password if required. */ 280280304Sjkim if (mode == CMD_REPLY && passin && 281280304Sjkim !app_passwd(bio_err, passin, NULL, &password, NULL)) { 282280304Sjkim BIO_printf(bio_err, "Error getting password.\n"); 283280304Sjkim goto cleanup; 284280304Sjkim } 285238384Sjkim 286280304Sjkim /* 287280304Sjkim * Check consistency of parameters and execute the appropriate function. 288280304Sjkim */ 289280304Sjkim switch (mode) { 290280304Sjkim case CMD_NONE: 291280304Sjkim goto usage; 292280304Sjkim case CMD_QUERY: 293280304Sjkim /* 294280304Sjkim * Data file and message imprint cannot be specified at the same 295280304Sjkim * time. 296280304Sjkim */ 297280304Sjkim ret = data != NULL && digest != NULL; 298280304Sjkim if (ret) 299280304Sjkim goto usage; 300280304Sjkim /* Load the config file for possible policy OIDs. */ 301280304Sjkim conf = load_config_file(configfile); 302280304Sjkim ret = !query_command(data, digest, md, policy, no_nonce, cert, 303280304Sjkim in, out, text); 304280304Sjkim break; 305280304Sjkim case CMD_REPLY: 306280304Sjkim conf = load_config_file(configfile); 307280304Sjkim if (in == NULL) { 308280304Sjkim ret = !(queryfile != NULL && conf != NULL && !token_in); 309280304Sjkim if (ret) 310280304Sjkim goto usage; 311280304Sjkim } else { 312280304Sjkim /* 'in' and 'queryfile' are exclusive. */ 313280304Sjkim ret = !(queryfile == NULL); 314280304Sjkim if (ret) 315280304Sjkim goto usage; 316280304Sjkim } 317238384Sjkim 318280304Sjkim ret = !reply_command(conf, section, engine, queryfile, 319280304Sjkim password, inkey, signer, chain, policy, 320280304Sjkim in, token_in, out, token_out, text); 321280304Sjkim break; 322280304Sjkim case CMD_VERIFY: 323280304Sjkim ret = !(((queryfile && !data && !digest) 324280304Sjkim || (!queryfile && data && !digest) 325280304Sjkim || (!queryfile && !data && digest)) 326280304Sjkim && in != NULL); 327280304Sjkim if (ret) 328280304Sjkim goto usage; 329238384Sjkim 330280304Sjkim ret = !verify_command(data, digest, queryfile, in, token_in, 331280304Sjkim ca_path, ca_file, untrusted); 332280304Sjkim } 333238384Sjkim 334280304Sjkim goto cleanup; 335280304Sjkim 336238384Sjkim usage: 337280304Sjkim BIO_printf(bio_err, "usage:\n" 338280304Sjkim "ts -query [-rand file%cfile%c...] [-config configfile] " 339280304Sjkim "[-data file_to_hash] [-digest digest_bytes]" 340280304Sjkim "[-md2|-md4|-md5|-sha|-sha1|-mdc2|-ripemd160] " 341280304Sjkim "[-policy object_id] [-no_nonce] [-cert] " 342280304Sjkim "[-in request.tsq] [-out request.tsq] [-text]\n", 343280304Sjkim LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR); 344280304Sjkim BIO_printf(bio_err, "or\n" 345280304Sjkim "ts -reply [-config configfile] [-section tsa_section] " 346280304Sjkim "[-queryfile request.tsq] [-passin password] " 347280304Sjkim "[-signer tsa_cert.pem] [-inkey private_key.pem] " 348280304Sjkim "[-chain certs_file.pem] [-policy object_id] " 349280304Sjkim "[-in response.tsr] [-token_in] " 350280304Sjkim "[-out response.tsr] [-token_out] [-text] [-engine id]\n"); 351280304Sjkim BIO_printf(bio_err, "or\n" 352280304Sjkim "ts -verify [-data file_to_hash] [-digest digest_bytes] " 353280304Sjkim "[-queryfile request.tsq] " 354280304Sjkim "-in response.tsr [-token_in] " 355280304Sjkim "-CApath ca_path -CAfile ca_file.pem " 356280304Sjkim "-untrusted cert_file.pem\n"); 357238384Sjkim cleanup: 358280304Sjkim /* Clean up. */ 359280304Sjkim app_RAND_write_file(NULL, bio_err); 360280304Sjkim NCONF_free(conf); 361280304Sjkim OPENSSL_free(password); 362280304Sjkim OBJ_cleanup(); 363280304Sjkim if (free_bio_err) { 364280304Sjkim BIO_free_all(bio_err); 365280304Sjkim bio_err = NULL; 366280304Sjkim } 367238384Sjkim 368280304Sjkim OPENSSL_EXIT(ret); 369280304Sjkim} 370238384Sjkim 371238384Sjkim/* 372238384Sjkim * Configuration file-related function definitions. 373238384Sjkim */ 374238384Sjkim 375238384Sjkimstatic ASN1_OBJECT *txt2obj(const char *oid) 376280304Sjkim{ 377280304Sjkim ASN1_OBJECT *oid_obj = NULL; 378238384Sjkim 379280304Sjkim if (!(oid_obj = OBJ_txt2obj(oid, 0))) 380280304Sjkim BIO_printf(bio_err, "cannot convert %s to OID\n", oid); 381238384Sjkim 382280304Sjkim return oid_obj; 383280304Sjkim} 384238384Sjkim 385238384Sjkimstatic CONF *load_config_file(const char *configfile) 386280304Sjkim{ 387280304Sjkim CONF *conf = NULL; 388280304Sjkim long errorline = -1; 389238384Sjkim 390280304Sjkim if (!configfile) 391280304Sjkim configfile = getenv("OPENSSL_CONF"); 392280304Sjkim if (!configfile) 393280304Sjkim configfile = getenv("SSLEAY_CONF"); 394238384Sjkim 395280304Sjkim if (configfile && 396280304Sjkim (!(conf = NCONF_new(NULL)) || 397280304Sjkim NCONF_load(conf, configfile, &errorline) <= 0)) { 398280304Sjkim if (errorline <= 0) 399280304Sjkim BIO_printf(bio_err, "error loading the config file " 400280304Sjkim "'%s'\n", configfile); 401280304Sjkim else 402280304Sjkim BIO_printf(bio_err, "error on line %ld of config file " 403280304Sjkim "'%s'\n", errorline, configfile); 404280304Sjkim } 405238384Sjkim 406280304Sjkim if (conf != NULL) { 407280304Sjkim const char *p; 408238384Sjkim 409280304Sjkim BIO_printf(bio_err, "Using configuration from %s\n", configfile); 410280304Sjkim p = NCONF_get_string(conf, NULL, ENV_OID_FILE); 411280304Sjkim if (p != NULL) { 412280304Sjkim BIO *oid_bio = BIO_new_file(p, "r"); 413280304Sjkim if (!oid_bio) 414280304Sjkim ERR_print_errors(bio_err); 415280304Sjkim else { 416280304Sjkim OBJ_create_objects(oid_bio); 417280304Sjkim BIO_free_all(oid_bio); 418280304Sjkim } 419280304Sjkim } else 420280304Sjkim ERR_clear_error(); 421280304Sjkim if (!add_oid_section(bio_err, conf)) 422280304Sjkim ERR_print_errors(bio_err); 423280304Sjkim } 424280304Sjkim return conf; 425280304Sjkim} 426238384Sjkim 427238384Sjkim/* 428238384Sjkim * Query-related method definitions. 429238384Sjkim */ 430238384Sjkim 431238384Sjkimstatic int query_command(const char *data, char *digest, const EVP_MD *md, 432280304Sjkim const char *policy, int no_nonce, 433280304Sjkim int cert, const char *in, const char *out, int text) 434280304Sjkim{ 435280304Sjkim int ret = 0; 436280304Sjkim TS_REQ *query = NULL; 437280304Sjkim BIO *in_bio = NULL; 438280304Sjkim BIO *data_bio = NULL; 439280304Sjkim BIO *out_bio = NULL; 440238384Sjkim 441280304Sjkim /* Build query object either from file or from scratch. */ 442280304Sjkim if (in != NULL) { 443280304Sjkim if ((in_bio = BIO_new_file(in, "rb")) == NULL) 444280304Sjkim goto end; 445280304Sjkim query = d2i_TS_REQ_bio(in_bio, NULL); 446280304Sjkim } else { 447280304Sjkim /* 448280304Sjkim * Open the file if no explicit digest bytes were specified. 449280304Sjkim */ 450280304Sjkim if (!digest && !(data_bio = BIO_open_with_default(data, "rb", stdin))) 451280304Sjkim goto end; 452280304Sjkim /* Creating the query object. */ 453280304Sjkim query = create_query(data_bio, digest, md, policy, no_nonce, cert); 454280304Sjkim /* Saving the random number generator state. */ 455280304Sjkim } 456280304Sjkim if (query == NULL) 457280304Sjkim goto end; 458238384Sjkim 459280304Sjkim /* Write query either in ASN.1 or in text format. */ 460280304Sjkim if ((out_bio = BIO_open_with_default(out, "wb", stdout)) == NULL) 461280304Sjkim goto end; 462280304Sjkim if (text) { 463280304Sjkim /* Text output. */ 464280304Sjkim if (!TS_REQ_print_bio(out_bio, query)) 465280304Sjkim goto end; 466280304Sjkim } else { 467280304Sjkim /* ASN.1 output. */ 468280304Sjkim if (!i2d_TS_REQ_bio(out_bio, query)) 469280304Sjkim goto end; 470280304Sjkim } 471238384Sjkim 472280304Sjkim ret = 1; 473238384Sjkim 474238384Sjkim end: 475280304Sjkim ERR_print_errors(bio_err); 476238384Sjkim 477280304Sjkim /* Clean up. */ 478280304Sjkim BIO_free_all(in_bio); 479280304Sjkim BIO_free_all(data_bio); 480280304Sjkim BIO_free_all(out_bio); 481280304Sjkim TS_REQ_free(query); 482238384Sjkim 483280304Sjkim return ret; 484280304Sjkim} 485238384Sjkim 486280304Sjkimstatic BIO *BIO_open_with_default(const char *file, const char *mode, 487280304Sjkim FILE *default_fp) 488280304Sjkim{ 489280304Sjkim return file == NULL ? BIO_new_fp(default_fp, BIO_NOCLOSE) 490280304Sjkim : BIO_new_file(file, mode); 491280304Sjkim} 492238384Sjkim 493238384Sjkimstatic TS_REQ *create_query(BIO *data_bio, char *digest, const EVP_MD *md, 494280304Sjkim const char *policy, int no_nonce, int cert) 495280304Sjkim{ 496280304Sjkim int ret = 0; 497280304Sjkim TS_REQ *ts_req = NULL; 498280304Sjkim int len; 499280304Sjkim TS_MSG_IMPRINT *msg_imprint = NULL; 500280304Sjkim X509_ALGOR *algo = NULL; 501280304Sjkim unsigned char *data = NULL; 502280304Sjkim ASN1_OBJECT *policy_obj = NULL; 503280304Sjkim ASN1_INTEGER *nonce_asn1 = NULL; 504238384Sjkim 505280304Sjkim /* Setting default message digest. */ 506280304Sjkim if (!md && !(md = EVP_get_digestbyname("sha1"))) 507280304Sjkim goto err; 508238384Sjkim 509280304Sjkim /* Creating request object. */ 510280304Sjkim if (!(ts_req = TS_REQ_new())) 511280304Sjkim goto err; 512238384Sjkim 513280304Sjkim /* Setting version. */ 514280304Sjkim if (!TS_REQ_set_version(ts_req, 1)) 515280304Sjkim goto err; 516238384Sjkim 517280304Sjkim /* Creating and adding MSG_IMPRINT object. */ 518280304Sjkim if (!(msg_imprint = TS_MSG_IMPRINT_new())) 519280304Sjkim goto err; 520238384Sjkim 521280304Sjkim /* Adding algorithm. */ 522280304Sjkim if (!(algo = X509_ALGOR_new())) 523280304Sjkim goto err; 524280304Sjkim if (!(algo->algorithm = OBJ_nid2obj(EVP_MD_type(md)))) 525280304Sjkim goto err; 526280304Sjkim if (!(algo->parameter = ASN1_TYPE_new())) 527280304Sjkim goto err; 528280304Sjkim algo->parameter->type = V_ASN1_NULL; 529280304Sjkim if (!TS_MSG_IMPRINT_set_algo(msg_imprint, algo)) 530280304Sjkim goto err; 531238384Sjkim 532280304Sjkim /* Adding message digest. */ 533280304Sjkim if ((len = create_digest(data_bio, digest, md, &data)) == 0) 534280304Sjkim goto err; 535280304Sjkim if (!TS_MSG_IMPRINT_set_msg(msg_imprint, data, len)) 536280304Sjkim goto err; 537238384Sjkim 538280304Sjkim if (!TS_REQ_set_msg_imprint(ts_req, msg_imprint)) 539280304Sjkim goto err; 540238384Sjkim 541280304Sjkim /* Setting policy if requested. */ 542280304Sjkim if (policy && !(policy_obj = txt2obj(policy))) 543280304Sjkim goto err; 544280304Sjkim if (policy_obj && !TS_REQ_set_policy_id(ts_req, policy_obj)) 545280304Sjkim goto err; 546238384Sjkim 547280304Sjkim /* Setting nonce if requested. */ 548280304Sjkim if (!no_nonce && !(nonce_asn1 = create_nonce(NONCE_LENGTH))) 549280304Sjkim goto err; 550280304Sjkim if (nonce_asn1 && !TS_REQ_set_nonce(ts_req, nonce_asn1)) 551280304Sjkim goto err; 552238384Sjkim 553280304Sjkim /* Setting certificate request flag if requested. */ 554280304Sjkim if (!TS_REQ_set_cert_req(ts_req, cert)) 555280304Sjkim goto err; 556280304Sjkim 557280304Sjkim ret = 1; 558238384Sjkim err: 559280304Sjkim if (!ret) { 560280304Sjkim TS_REQ_free(ts_req); 561280304Sjkim ts_req = NULL; 562280304Sjkim BIO_printf(bio_err, "could not create query\n"); 563280304Sjkim } 564280304Sjkim TS_MSG_IMPRINT_free(msg_imprint); 565280304Sjkim X509_ALGOR_free(algo); 566280304Sjkim OPENSSL_free(data); 567280304Sjkim ASN1_OBJECT_free(policy_obj); 568280304Sjkim ASN1_INTEGER_free(nonce_asn1); 569280304Sjkim return ts_req; 570280304Sjkim} 571238384Sjkim 572238384Sjkimstatic int create_digest(BIO *input, char *digest, const EVP_MD *md, 573280304Sjkim unsigned char **md_value) 574280304Sjkim{ 575280304Sjkim int md_value_len; 576238384Sjkim 577280304Sjkim md_value_len = EVP_MD_size(md); 578280304Sjkim if (md_value_len < 0) 579280304Sjkim goto err; 580280304Sjkim if (input) { 581280304Sjkim /* Digest must be computed from an input file. */ 582280304Sjkim EVP_MD_CTX md_ctx; 583280304Sjkim unsigned char buffer[4096]; 584280304Sjkim int length; 585238384Sjkim 586280304Sjkim *md_value = OPENSSL_malloc(md_value_len); 587280304Sjkim if (*md_value == 0) 588280304Sjkim goto err; 589238384Sjkim 590280304Sjkim EVP_DigestInit(&md_ctx, md); 591280304Sjkim while ((length = BIO_read(input, buffer, sizeof(buffer))) > 0) { 592280304Sjkim EVP_DigestUpdate(&md_ctx, buffer, length); 593280304Sjkim } 594280304Sjkim EVP_DigestFinal(&md_ctx, *md_value, NULL); 595280304Sjkim } else { 596280304Sjkim /* Digest bytes are specified with digest. */ 597280304Sjkim long digest_len; 598280304Sjkim *md_value = string_to_hex(digest, &digest_len); 599280304Sjkim if (!*md_value || md_value_len != digest_len) { 600280304Sjkim OPENSSL_free(*md_value); 601280304Sjkim *md_value = NULL; 602280304Sjkim BIO_printf(bio_err, "bad digest, %d bytes " 603280304Sjkim "must be specified\n", md_value_len); 604280304Sjkim goto err; 605280304Sjkim } 606280304Sjkim } 607238384Sjkim 608280304Sjkim return md_value_len; 609238384Sjkim err: 610280304Sjkim return 0; 611280304Sjkim} 612238384Sjkim 613238384Sjkimstatic ASN1_INTEGER *create_nonce(int bits) 614280304Sjkim{ 615280304Sjkim unsigned char buf[20]; 616280304Sjkim ASN1_INTEGER *nonce = NULL; 617280304Sjkim int len = (bits - 1) / 8 + 1; 618280304Sjkim int i; 619238384Sjkim 620280304Sjkim /* Generating random byte sequence. */ 621280304Sjkim if (len > (int)sizeof(buf)) 622280304Sjkim goto err; 623280304Sjkim if (RAND_bytes(buf, len) <= 0) 624280304Sjkim goto err; 625238384Sjkim 626280304Sjkim /* Find the first non-zero byte and creating ASN1_INTEGER object. */ 627280304Sjkim for (i = 0; i < len && !buf[i]; ++i) ; 628280304Sjkim if (!(nonce = ASN1_INTEGER_new())) 629280304Sjkim goto err; 630280304Sjkim OPENSSL_free(nonce->data); 631280304Sjkim /* Allocate at least one byte. */ 632280304Sjkim nonce->length = len - i; 633280304Sjkim if (!(nonce->data = OPENSSL_malloc(nonce->length + 1))) 634280304Sjkim goto err; 635280304Sjkim memcpy(nonce->data, buf + i, nonce->length); 636238384Sjkim 637280304Sjkim return nonce; 638238384Sjkim err: 639280304Sjkim BIO_printf(bio_err, "could not create nonce\n"); 640280304Sjkim ASN1_INTEGER_free(nonce); 641280304Sjkim return NULL; 642280304Sjkim} 643280304Sjkim 644238384Sjkim/* 645238384Sjkim * Reply-related method definitions. 646238384Sjkim */ 647238384Sjkim 648280304Sjkimstatic int reply_command(CONF *conf, char *section, char *engine, 649280304Sjkim char *queryfile, char *passin, char *inkey, 650280304Sjkim char *signer, char *chain, const char *policy, 651280304Sjkim char *in, int token_in, 652280304Sjkim char *out, int token_out, int text) 653280304Sjkim{ 654280304Sjkim int ret = 0; 655280304Sjkim TS_RESP *response = NULL; 656280304Sjkim BIO *in_bio = NULL; 657280304Sjkim BIO *query_bio = NULL; 658280304Sjkim BIO *inkey_bio = NULL; 659280304Sjkim BIO *signer_bio = NULL; 660280304Sjkim BIO *out_bio = NULL; 661238384Sjkim 662280304Sjkim /* Build response object either from response or query. */ 663280304Sjkim if (in != NULL) { 664280304Sjkim if ((in_bio = BIO_new_file(in, "rb")) == NULL) 665280304Sjkim goto end; 666280304Sjkim if (token_in) { 667280304Sjkim /* 668280304Sjkim * We have a ContentInfo (PKCS7) object, add 'granted' status 669280304Sjkim * info around it. 670280304Sjkim */ 671280304Sjkim response = read_PKCS7(in_bio); 672280304Sjkim } else { 673280304Sjkim /* We have a ready-made TS_RESP object. */ 674280304Sjkim response = d2i_TS_RESP_bio(in_bio, NULL); 675280304Sjkim } 676280304Sjkim } else { 677280304Sjkim response = create_response(conf, section, engine, queryfile, 678280304Sjkim passin, inkey, signer, chain, policy); 679280304Sjkim if (response) 680280304Sjkim BIO_printf(bio_err, "Response has been generated.\n"); 681280304Sjkim else 682280304Sjkim BIO_printf(bio_err, "Response is not generated.\n"); 683280304Sjkim } 684280304Sjkim if (response == NULL) 685280304Sjkim goto end; 686238384Sjkim 687280304Sjkim /* Write response either in ASN.1 or text format. */ 688280304Sjkim if ((out_bio = BIO_open_with_default(out, "wb", stdout)) == NULL) 689280304Sjkim goto end; 690280304Sjkim if (text) { 691280304Sjkim /* Text output. */ 692280304Sjkim if (token_out) { 693280304Sjkim TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response); 694280304Sjkim if (!TS_TST_INFO_print_bio(out_bio, tst_info)) 695280304Sjkim goto end; 696280304Sjkim } else { 697280304Sjkim if (!TS_RESP_print_bio(out_bio, response)) 698280304Sjkim goto end; 699280304Sjkim } 700280304Sjkim } else { 701280304Sjkim /* ASN.1 DER output. */ 702280304Sjkim if (token_out) { 703280304Sjkim PKCS7 *token = TS_RESP_get_token(response); 704280304Sjkim if (!i2d_PKCS7_bio(out_bio, token)) 705280304Sjkim goto end; 706280304Sjkim } else { 707280304Sjkim if (!i2d_TS_RESP_bio(out_bio, response)) 708280304Sjkim goto end; 709280304Sjkim } 710280304Sjkim } 711238384Sjkim 712280304Sjkim ret = 1; 713238384Sjkim 714238384Sjkim end: 715280304Sjkim ERR_print_errors(bio_err); 716238384Sjkim 717280304Sjkim /* Clean up. */ 718280304Sjkim BIO_free_all(in_bio); 719280304Sjkim BIO_free_all(query_bio); 720280304Sjkim BIO_free_all(inkey_bio); 721280304Sjkim BIO_free_all(signer_bio); 722280304Sjkim BIO_free_all(out_bio); 723280304Sjkim TS_RESP_free(response); 724238384Sjkim 725280304Sjkim return ret; 726280304Sjkim} 727238384Sjkim 728238384Sjkim/* Reads a PKCS7 token and adds default 'granted' status info to it. */ 729238384Sjkimstatic TS_RESP *read_PKCS7(BIO *in_bio) 730280304Sjkim{ 731280304Sjkim int ret = 0; 732280304Sjkim PKCS7 *token = NULL; 733280304Sjkim TS_TST_INFO *tst_info = NULL; 734280304Sjkim TS_RESP *resp = NULL; 735280304Sjkim TS_STATUS_INFO *si = NULL; 736238384Sjkim 737280304Sjkim /* Read PKCS7 object and extract the signed time stamp info. */ 738280304Sjkim if (!(token = d2i_PKCS7_bio(in_bio, NULL))) 739280304Sjkim goto end; 740280304Sjkim if (!(tst_info = PKCS7_to_TS_TST_INFO(token))) 741280304Sjkim goto end; 742238384Sjkim 743280304Sjkim /* Creating response object. */ 744280304Sjkim if (!(resp = TS_RESP_new())) 745280304Sjkim goto end; 746238384Sjkim 747280304Sjkim /* Create granted status info. */ 748280304Sjkim if (!(si = TS_STATUS_INFO_new())) 749280304Sjkim goto end; 750280304Sjkim if (!(ASN1_INTEGER_set(si->status, TS_STATUS_GRANTED))) 751280304Sjkim goto end; 752280304Sjkim if (!TS_RESP_set_status_info(resp, si)) 753280304Sjkim goto end; 754238384Sjkim 755280304Sjkim /* Setting encapsulated token. */ 756280304Sjkim TS_RESP_set_tst_info(resp, token, tst_info); 757280304Sjkim token = NULL; /* Ownership is lost. */ 758280304Sjkim tst_info = NULL; /* Ownership is lost. */ 759238384Sjkim 760280304Sjkim ret = 1; 761238384Sjkim end: 762280304Sjkim PKCS7_free(token); 763280304Sjkim TS_TST_INFO_free(tst_info); 764280304Sjkim if (!ret) { 765280304Sjkim TS_RESP_free(resp); 766280304Sjkim resp = NULL; 767280304Sjkim } 768280304Sjkim TS_STATUS_INFO_free(si); 769280304Sjkim return resp; 770280304Sjkim} 771238384Sjkim 772280304Sjkimstatic TS_RESP *create_response(CONF *conf, const char *section, char *engine, 773280304Sjkim char *queryfile, char *passin, char *inkey, 774280304Sjkim char *signer, char *chain, const char *policy) 775280304Sjkim{ 776280304Sjkim int ret = 0; 777280304Sjkim TS_RESP *response = NULL; 778280304Sjkim BIO *query_bio = NULL; 779280304Sjkim TS_RESP_CTX *resp_ctx = NULL; 780238384Sjkim 781280304Sjkim if (!(query_bio = BIO_new_file(queryfile, "rb"))) 782280304Sjkim goto end; 783238384Sjkim 784280304Sjkim /* Getting TSA configuration section. */ 785280304Sjkim if (!(section = TS_CONF_get_tsa_section(conf, section))) 786280304Sjkim goto end; 787238384Sjkim 788280304Sjkim /* Setting up response generation context. */ 789280304Sjkim if (!(resp_ctx = TS_RESP_CTX_new())) 790280304Sjkim goto end; 791238384Sjkim 792280304Sjkim /* Setting serial number provider callback. */ 793280304Sjkim if (!TS_CONF_set_serial(conf, section, serial_cb, resp_ctx)) 794280304Sjkim goto end; 795238384Sjkim#ifndef OPENSSL_NO_ENGINE 796280304Sjkim /* Setting default OpenSSL engine. */ 797280304Sjkim if (!TS_CONF_set_crypto_device(conf, section, engine)) 798280304Sjkim goto end; 799238384Sjkim#endif 800238384Sjkim 801280304Sjkim /* Setting TSA signer certificate. */ 802280304Sjkim if (!TS_CONF_set_signer_cert(conf, section, signer, resp_ctx)) 803280304Sjkim goto end; 804238384Sjkim 805280304Sjkim /* Setting TSA signer certificate chain. */ 806280304Sjkim if (!TS_CONF_set_certs(conf, section, chain, resp_ctx)) 807280304Sjkim goto end; 808238384Sjkim 809280304Sjkim /* Setting TSA signer private key. */ 810280304Sjkim if (!TS_CONF_set_signer_key(conf, section, inkey, passin, resp_ctx)) 811280304Sjkim goto end; 812238384Sjkim 813280304Sjkim /* Setting default policy OID. */ 814280304Sjkim if (!TS_CONF_set_def_policy(conf, section, policy, resp_ctx)) 815280304Sjkim goto end; 816238384Sjkim 817280304Sjkim /* Setting acceptable policy OIDs. */ 818280304Sjkim if (!TS_CONF_set_policies(conf, section, resp_ctx)) 819280304Sjkim goto end; 820238384Sjkim 821280304Sjkim /* Setting the acceptable one-way hash algorithms. */ 822280304Sjkim if (!TS_CONF_set_digests(conf, section, resp_ctx)) 823280304Sjkim goto end; 824238384Sjkim 825280304Sjkim /* Setting guaranteed time stamp accuracy. */ 826280304Sjkim if (!TS_CONF_set_accuracy(conf, section, resp_ctx)) 827280304Sjkim goto end; 828238384Sjkim 829280304Sjkim /* Setting the precision of the time. */ 830280304Sjkim if (!TS_CONF_set_clock_precision_digits(conf, section, resp_ctx)) 831280304Sjkim goto end; 832238384Sjkim 833280304Sjkim /* Setting the ordering flaf if requested. */ 834280304Sjkim if (!TS_CONF_set_ordering(conf, section, resp_ctx)) 835280304Sjkim goto end; 836238384Sjkim 837280304Sjkim /* Setting the TSA name required flag if requested. */ 838280304Sjkim if (!TS_CONF_set_tsa_name(conf, section, resp_ctx)) 839280304Sjkim goto end; 840238384Sjkim 841280304Sjkim /* Setting the ESS cert id chain flag if requested. */ 842280304Sjkim if (!TS_CONF_set_ess_cert_id_chain(conf, section, resp_ctx)) 843280304Sjkim goto end; 844238384Sjkim 845280304Sjkim /* Creating the response. */ 846280304Sjkim if (!(response = TS_RESP_create_response(resp_ctx, query_bio))) 847280304Sjkim goto end; 848238384Sjkim 849280304Sjkim ret = 1; 850238384Sjkim end: 851280304Sjkim if (!ret) { 852280304Sjkim TS_RESP_free(response); 853280304Sjkim response = NULL; 854280304Sjkim } 855280304Sjkim TS_RESP_CTX_free(resp_ctx); 856280304Sjkim BIO_free_all(query_bio); 857238384Sjkim 858280304Sjkim return response; 859280304Sjkim} 860238384Sjkim 861280304Sjkimstatic ASN1_INTEGER *MS_CALLBACK serial_cb(TS_RESP_CTX *ctx, void *data) 862280304Sjkim{ 863280304Sjkim const char *serial_file = (const char *)data; 864280304Sjkim ASN1_INTEGER *serial = next_serial(serial_file); 865238384Sjkim 866280304Sjkim if (!serial) { 867280304Sjkim TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION, 868280304Sjkim "Error during serial number " 869280304Sjkim "generation."); 870280304Sjkim TS_RESP_CTX_add_failure_info(ctx, TS_INFO_ADD_INFO_NOT_AVAILABLE); 871280304Sjkim } else 872280304Sjkim save_ts_serial(serial_file, serial); 873238384Sjkim 874280304Sjkim return serial; 875280304Sjkim} 876238384Sjkim 877238384Sjkimstatic ASN1_INTEGER *next_serial(const char *serialfile) 878280304Sjkim{ 879280304Sjkim int ret = 0; 880280304Sjkim BIO *in = NULL; 881280304Sjkim ASN1_INTEGER *serial = NULL; 882280304Sjkim BIGNUM *bn = NULL; 883238384Sjkim 884280304Sjkim if (!(serial = ASN1_INTEGER_new())) 885280304Sjkim goto err; 886238384Sjkim 887280304Sjkim if (!(in = BIO_new_file(serialfile, "r"))) { 888280304Sjkim ERR_clear_error(); 889280304Sjkim BIO_printf(bio_err, "Warning: could not open file %s for " 890280304Sjkim "reading, using serial number: 1\n", serialfile); 891280304Sjkim if (!ASN1_INTEGER_set(serial, 1)) 892280304Sjkim goto err; 893280304Sjkim } else { 894280304Sjkim char buf[1024]; 895280304Sjkim if (!a2i_ASN1_INTEGER(in, serial, buf, sizeof(buf))) { 896280304Sjkim BIO_printf(bio_err, "unable to load number from %s\n", 897280304Sjkim serialfile); 898280304Sjkim goto err; 899280304Sjkim } 900280304Sjkim if (!(bn = ASN1_INTEGER_to_BN(serial, NULL))) 901280304Sjkim goto err; 902280304Sjkim ASN1_INTEGER_free(serial); 903280304Sjkim serial = NULL; 904280304Sjkim if (!BN_add_word(bn, 1)) 905280304Sjkim goto err; 906280304Sjkim if (!(serial = BN_to_ASN1_INTEGER(bn, NULL))) 907280304Sjkim goto err; 908280304Sjkim } 909280304Sjkim ret = 1; 910238384Sjkim err: 911280304Sjkim if (!ret) { 912280304Sjkim ASN1_INTEGER_free(serial); 913280304Sjkim serial = NULL; 914280304Sjkim } 915280304Sjkim BIO_free_all(in); 916280304Sjkim BN_free(bn); 917280304Sjkim return serial; 918280304Sjkim} 919238384Sjkim 920238384Sjkimstatic int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial) 921280304Sjkim{ 922280304Sjkim int ret = 0; 923280304Sjkim BIO *out = NULL; 924238384Sjkim 925280304Sjkim if (!(out = BIO_new_file(serialfile, "w"))) 926280304Sjkim goto err; 927280304Sjkim if (i2a_ASN1_INTEGER(out, serial) <= 0) 928280304Sjkim goto err; 929280304Sjkim if (BIO_puts(out, "\n") <= 0) 930280304Sjkim goto err; 931280304Sjkim ret = 1; 932238384Sjkim err: 933280304Sjkim if (!ret) 934280304Sjkim BIO_printf(bio_err, "could not save serial number to %s\n", 935280304Sjkim serialfile); 936280304Sjkim BIO_free_all(out); 937280304Sjkim return ret; 938280304Sjkim} 939238384Sjkim 940238384Sjkim/* 941238384Sjkim * Verify-related method definitions. 942238384Sjkim */ 943238384Sjkim 944238384Sjkimstatic int verify_command(char *data, char *digest, char *queryfile, 945280304Sjkim char *in, int token_in, 946280304Sjkim char *ca_path, char *ca_file, char *untrusted) 947280304Sjkim{ 948280304Sjkim BIO *in_bio = NULL; 949280304Sjkim PKCS7 *token = NULL; 950280304Sjkim TS_RESP *response = NULL; 951280304Sjkim TS_VERIFY_CTX *verify_ctx = NULL; 952280304Sjkim int ret = 0; 953238384Sjkim 954280304Sjkim /* Decode the token (PKCS7) or response (TS_RESP) files. */ 955280304Sjkim if (!(in_bio = BIO_new_file(in, "rb"))) 956280304Sjkim goto end; 957280304Sjkim if (token_in) { 958280304Sjkim if (!(token = d2i_PKCS7_bio(in_bio, NULL))) 959280304Sjkim goto end; 960280304Sjkim } else { 961280304Sjkim if (!(response = d2i_TS_RESP_bio(in_bio, NULL))) 962280304Sjkim goto end; 963280304Sjkim } 964238384Sjkim 965280304Sjkim if (!(verify_ctx = create_verify_ctx(data, digest, queryfile, 966280304Sjkim ca_path, ca_file, untrusted))) 967280304Sjkim goto end; 968238384Sjkim 969280304Sjkim /* Checking the token or response against the request. */ 970280304Sjkim ret = token_in ? 971280304Sjkim TS_RESP_verify_token(verify_ctx, token) : 972280304Sjkim TS_RESP_verify_response(verify_ctx, response); 973238384Sjkim 974238384Sjkim end: 975280304Sjkim printf("Verification: "); 976280304Sjkim if (ret) 977280304Sjkim printf("OK\n"); 978280304Sjkim else { 979280304Sjkim printf("FAILED\n"); 980280304Sjkim /* Print errors, if there are any. */ 981280304Sjkim ERR_print_errors(bio_err); 982280304Sjkim } 983238384Sjkim 984280304Sjkim /* Clean up. */ 985280304Sjkim BIO_free_all(in_bio); 986280304Sjkim PKCS7_free(token); 987280304Sjkim TS_RESP_free(response); 988280304Sjkim TS_VERIFY_CTX_free(verify_ctx); 989280304Sjkim return ret; 990280304Sjkim} 991238384Sjkim 992280304Sjkimstatic TS_VERIFY_CTX *create_verify_ctx(char *data, char *digest, 993280304Sjkim char *queryfile, 994280304Sjkim char *ca_path, char *ca_file, 995280304Sjkim char *untrusted) 996280304Sjkim{ 997280304Sjkim TS_VERIFY_CTX *ctx = NULL; 998280304Sjkim BIO *input = NULL; 999280304Sjkim TS_REQ *request = NULL; 1000280304Sjkim int ret = 0; 1001238384Sjkim 1002280304Sjkim if (data != NULL || digest != NULL) { 1003280304Sjkim if (!(ctx = TS_VERIFY_CTX_new())) 1004280304Sjkim goto err; 1005280304Sjkim ctx->flags = TS_VFY_VERSION | TS_VFY_SIGNER; 1006280304Sjkim if (data != NULL) { 1007280304Sjkim ctx->flags |= TS_VFY_DATA; 1008280304Sjkim if (!(ctx->data = BIO_new_file(data, "rb"))) 1009280304Sjkim goto err; 1010280304Sjkim } else if (digest != NULL) { 1011280304Sjkim long imprint_len; 1012280304Sjkim ctx->flags |= TS_VFY_IMPRINT; 1013280304Sjkim if (!(ctx->imprint = string_to_hex(digest, &imprint_len))) { 1014280304Sjkim BIO_printf(bio_err, "invalid digest string\n"); 1015280304Sjkim goto err; 1016280304Sjkim } 1017280304Sjkim ctx->imprint_len = imprint_len; 1018280304Sjkim } 1019238384Sjkim 1020280304Sjkim } else if (queryfile != NULL) { 1021280304Sjkim /* 1022280304Sjkim * The request has just to be read, decoded and converted to a verify 1023280304Sjkim * context object. 1024280304Sjkim */ 1025280304Sjkim if (!(input = BIO_new_file(queryfile, "rb"))) 1026280304Sjkim goto err; 1027280304Sjkim if (!(request = d2i_TS_REQ_bio(input, NULL))) 1028280304Sjkim goto err; 1029280304Sjkim if (!(ctx = TS_REQ_to_TS_VERIFY_CTX(request, NULL))) 1030280304Sjkim goto err; 1031280304Sjkim } else 1032280304Sjkim return NULL; 1033238384Sjkim 1034280304Sjkim /* Add the signature verification flag and arguments. */ 1035280304Sjkim ctx->flags |= TS_VFY_SIGNATURE; 1036238384Sjkim 1037280304Sjkim /* Initialising the X509_STORE object. */ 1038280304Sjkim if (!(ctx->store = create_cert_store(ca_path, ca_file))) 1039280304Sjkim goto err; 1040280304Sjkim 1041280304Sjkim /* Loading untrusted certificates. */ 1042280304Sjkim if (untrusted && !(ctx->certs = TS_CONF_load_certs(untrusted))) 1043280304Sjkim goto err; 1044280304Sjkim 1045280304Sjkim ret = 1; 1046238384Sjkim err: 1047280304Sjkim if (!ret) { 1048280304Sjkim TS_VERIFY_CTX_free(ctx); 1049280304Sjkim ctx = NULL; 1050280304Sjkim } 1051280304Sjkim BIO_free_all(input); 1052280304Sjkim TS_REQ_free(request); 1053280304Sjkim return ctx; 1054280304Sjkim} 1055238384Sjkim 1056238384Sjkimstatic X509_STORE *create_cert_store(char *ca_path, char *ca_file) 1057280304Sjkim{ 1058280304Sjkim X509_STORE *cert_ctx = NULL; 1059280304Sjkim X509_LOOKUP *lookup = NULL; 1060280304Sjkim int i; 1061238384Sjkim 1062280304Sjkim /* Creating the X509_STORE object. */ 1063280304Sjkim cert_ctx = X509_STORE_new(); 1064238384Sjkim 1065280304Sjkim /* Setting the callback for certificate chain verification. */ 1066280304Sjkim X509_STORE_set_verify_cb(cert_ctx, verify_cb); 1067238384Sjkim 1068280304Sjkim /* Adding a trusted certificate directory source. */ 1069280304Sjkim if (ca_path) { 1070280304Sjkim lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir()); 1071280304Sjkim if (lookup == NULL) { 1072280304Sjkim BIO_printf(bio_err, "memory allocation failure\n"); 1073280304Sjkim goto err; 1074280304Sjkim } 1075280304Sjkim i = X509_LOOKUP_add_dir(lookup, ca_path, X509_FILETYPE_PEM); 1076280304Sjkim if (!i) { 1077280304Sjkim BIO_printf(bio_err, "Error loading directory %s\n", ca_path); 1078280304Sjkim goto err; 1079280304Sjkim } 1080280304Sjkim } 1081238384Sjkim 1082280304Sjkim /* Adding a trusted certificate file source. */ 1083280304Sjkim if (ca_file) { 1084280304Sjkim lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file()); 1085280304Sjkim if (lookup == NULL) { 1086280304Sjkim BIO_printf(bio_err, "memory allocation failure\n"); 1087280304Sjkim goto err; 1088280304Sjkim } 1089280304Sjkim i = X509_LOOKUP_load_file(lookup, ca_file, X509_FILETYPE_PEM); 1090280304Sjkim if (!i) { 1091280304Sjkim BIO_printf(bio_err, "Error loading file %s\n", ca_file); 1092280304Sjkim goto err; 1093280304Sjkim } 1094280304Sjkim } 1095238384Sjkim 1096280304Sjkim return cert_ctx; 1097238384Sjkim err: 1098280304Sjkim X509_STORE_free(cert_ctx); 1099280304Sjkim return NULL; 1100280304Sjkim} 1101238384Sjkim 1102238384Sjkimstatic int MS_CALLBACK verify_cb(int ok, X509_STORE_CTX *ctx) 1103280304Sjkim{ 1104280304Sjkim /*- 1105280304Sjkim char buf[256]; 1106238384Sjkim 1107280304Sjkim if (!ok) 1108280304Sjkim { 1109280304Sjkim X509_NAME_oneline(X509_get_subject_name(ctx->current_cert), 1110280304Sjkim buf, sizeof(buf)); 1111280304Sjkim printf("%s\n", buf); 1112280304Sjkim printf("error %d at %d depth lookup: %s\n", 1113280304Sjkim ctx->error, ctx->error_depth, 1114280304Sjkim X509_verify_cert_error_string(ctx->error)); 1115280304Sjkim } 1116280304Sjkim */ 1117238384Sjkim 1118280304Sjkim return ok; 1119280304Sjkim} 1120