1238384Sjkim/* apps/ts.c */ 2296341Sdelphij/* 3296341Sdelphij * Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL project 4296341Sdelphij * 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 14296341Sdelphij * 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 72296341Sdelphij#define PROG ts_main 73238384Sjkim 74238384Sjkim/* Length of the nonce of the request in bits (must be a multiple of 8). */ 75296341Sdelphij#define NONCE_LENGTH 64 76238384Sjkim 77238384Sjkim/* Macro definitions for the configuration file. */ 78296341Sdelphij#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, 87296341Sdelphij const EVP_MD *md, const char *policy, int no_nonce, 88296341Sdelphij int cert, const char *in, const char *out, int text); 89296341Sdelphijstatic BIO *BIO_open_with_default(const char *file, const char *mode, 90296341Sdelphij FILE *default_fp); 91238384Sjkimstatic TS_REQ *create_query(BIO *data_bio, char *digest, const EVP_MD *md, 92296341Sdelphij const char *policy, int no_nonce, int cert); 93238384Sjkimstatic int create_digest(BIO *input, char *digest, 94296341Sdelphij const EVP_MD *md, unsigned char **md_value); 95238384Sjkimstatic ASN1_INTEGER *create_nonce(int bits); 96238384Sjkim 97238384Sjkim/* Reply related functions. */ 98296341Sdelphijstatic int reply_command(CONF *conf, char *section, char *engine, 99296341Sdelphij char *queryfile, char *passin, char *inkey, 100296341Sdelphij char *signer, char *chain, const char *policy, 101296341Sdelphij char *in, int token_in, char *out, int token_out, 102296341Sdelphij int text); 103238384Sjkimstatic TS_RESP *read_PKCS7(BIO *in_bio); 104238384Sjkimstatic TS_RESP *create_response(CONF *conf, const char *section, char *engine, 105296341Sdelphij char *queryfile, char *passin, char *inkey, 106296341Sdelphij char *signer, char *chain, 107296341Sdelphij const char *policy); 108296341Sdelphijstatic 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, 114296341Sdelphij char *in, int token_in, 115296341Sdelphij char *ca_path, char *ca_file, char *untrusted); 116296341Sdelphijstatic TS_VERIFY_CTX *create_verify_ctx(char *data, char *digest, 117296341Sdelphij char *queryfile, 118296341Sdelphij char *ca_path, char *ca_file, 119296341Sdelphij 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) 127296341Sdelphij{ 128296341Sdelphij int ret = 1; 129296341Sdelphij char *configfile = NULL; 130296341Sdelphij char *section = NULL; 131296341Sdelphij CONF *conf = NULL; 132296341Sdelphij enum mode { 133296341Sdelphij CMD_NONE, CMD_QUERY, CMD_REPLY, CMD_VERIFY 134296341Sdelphij } mode = CMD_NONE; 135296341Sdelphij char *data = NULL; 136296341Sdelphij char *digest = NULL; 137296341Sdelphij const EVP_MD *md = NULL; 138296341Sdelphij char *rnd = NULL; 139296341Sdelphij char *policy = NULL; 140296341Sdelphij int no_nonce = 0; 141296341Sdelphij int cert = 0; 142296341Sdelphij char *in = NULL; 143296341Sdelphij char *out = NULL; 144296341Sdelphij int text = 0; 145296341Sdelphij char *queryfile = NULL; 146296341Sdelphij char *passin = NULL; /* Password source. */ 147296341Sdelphij char *password = NULL; /* Password itself. */ 148296341Sdelphij char *inkey = NULL; 149296341Sdelphij char *signer = NULL; 150296341Sdelphij char *chain = NULL; 151296341Sdelphij char *ca_path = NULL; 152296341Sdelphij char *ca_file = NULL; 153296341Sdelphij char *untrusted = NULL; 154296341Sdelphij char *engine = NULL; 155296341Sdelphij /* Input is ContentInfo instead of TimeStampResp. */ 156296341Sdelphij int token_in = 0; 157296341Sdelphij /* Output is ContentInfo instead of TimeStampResp. */ 158296341Sdelphij int token_out = 0; 159296341Sdelphij int free_bio_err = 0; 160238384Sjkim 161296341Sdelphij ERR_load_crypto_strings(); 162296341Sdelphij apps_startup(); 163238384Sjkim 164296341Sdelphij if (bio_err == NULL && (bio_err = BIO_new(BIO_s_file())) != NULL) { 165296341Sdelphij free_bio_err = 1; 166296341Sdelphij BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT); 167296341Sdelphij } 168238384Sjkim 169296341Sdelphij if (!load_config(bio_err, NULL)) 170296341Sdelphij goto cleanup; 171238384Sjkim 172296341Sdelphij for (argc--, argv++; argc > 0; argc--, argv++) { 173296341Sdelphij if (strcmp(*argv, "-config") == 0) { 174296341Sdelphij if (argc-- < 1) 175296341Sdelphij goto usage; 176296341Sdelphij configfile = *++argv; 177296341Sdelphij } else if (strcmp(*argv, "-section") == 0) { 178296341Sdelphij if (argc-- < 1) 179296341Sdelphij goto usage; 180296341Sdelphij section = *++argv; 181296341Sdelphij } else if (strcmp(*argv, "-query") == 0) { 182296341Sdelphij if (mode != CMD_NONE) 183296341Sdelphij goto usage; 184296341Sdelphij mode = CMD_QUERY; 185296341Sdelphij } else if (strcmp(*argv, "-data") == 0) { 186296341Sdelphij if (argc-- < 1) 187296341Sdelphij goto usage; 188296341Sdelphij data = *++argv; 189296341Sdelphij } else if (strcmp(*argv, "-digest") == 0) { 190296341Sdelphij if (argc-- < 1) 191296341Sdelphij goto usage; 192296341Sdelphij digest = *++argv; 193296341Sdelphij } else if (strcmp(*argv, "-rand") == 0) { 194296341Sdelphij if (argc-- < 1) 195296341Sdelphij goto usage; 196296341Sdelphij rnd = *++argv; 197296341Sdelphij } else if (strcmp(*argv, "-policy") == 0) { 198296341Sdelphij if (argc-- < 1) 199296341Sdelphij goto usage; 200296341Sdelphij policy = *++argv; 201296341Sdelphij } else if (strcmp(*argv, "-no_nonce") == 0) { 202296341Sdelphij no_nonce = 1; 203296341Sdelphij } else if (strcmp(*argv, "-cert") == 0) { 204296341Sdelphij cert = 1; 205296341Sdelphij } else if (strcmp(*argv, "-in") == 0) { 206296341Sdelphij if (argc-- < 1) 207296341Sdelphij goto usage; 208296341Sdelphij in = *++argv; 209296341Sdelphij } else if (strcmp(*argv, "-token_in") == 0) { 210296341Sdelphij token_in = 1; 211296341Sdelphij } else if (strcmp(*argv, "-out") == 0) { 212296341Sdelphij if (argc-- < 1) 213296341Sdelphij goto usage; 214296341Sdelphij out = *++argv; 215296341Sdelphij } else if (strcmp(*argv, "-token_out") == 0) { 216296341Sdelphij token_out = 1; 217296341Sdelphij } else if (strcmp(*argv, "-text") == 0) { 218296341Sdelphij text = 1; 219296341Sdelphij } else if (strcmp(*argv, "-reply") == 0) { 220296341Sdelphij if (mode != CMD_NONE) 221296341Sdelphij goto usage; 222296341Sdelphij mode = CMD_REPLY; 223296341Sdelphij } else if (strcmp(*argv, "-queryfile") == 0) { 224296341Sdelphij if (argc-- < 1) 225296341Sdelphij goto usage; 226296341Sdelphij queryfile = *++argv; 227296341Sdelphij } else if (strcmp(*argv, "-passin") == 0) { 228296341Sdelphij if (argc-- < 1) 229296341Sdelphij goto usage; 230296341Sdelphij passin = *++argv; 231296341Sdelphij } else if (strcmp(*argv, "-inkey") == 0) { 232296341Sdelphij if (argc-- < 1) 233296341Sdelphij goto usage; 234296341Sdelphij inkey = *++argv; 235296341Sdelphij } else if (strcmp(*argv, "-signer") == 0) { 236296341Sdelphij if (argc-- < 1) 237296341Sdelphij goto usage; 238296341Sdelphij signer = *++argv; 239296341Sdelphij } else if (strcmp(*argv, "-chain") == 0) { 240296341Sdelphij if (argc-- < 1) 241296341Sdelphij goto usage; 242296341Sdelphij chain = *++argv; 243296341Sdelphij } else if (strcmp(*argv, "-verify") == 0) { 244296341Sdelphij if (mode != CMD_NONE) 245296341Sdelphij goto usage; 246296341Sdelphij mode = CMD_VERIFY; 247296341Sdelphij } else if (strcmp(*argv, "-CApath") == 0) { 248296341Sdelphij if (argc-- < 1) 249296341Sdelphij goto usage; 250296341Sdelphij ca_path = *++argv; 251296341Sdelphij } else if (strcmp(*argv, "-CAfile") == 0) { 252296341Sdelphij if (argc-- < 1) 253296341Sdelphij goto usage; 254296341Sdelphij ca_file = *++argv; 255296341Sdelphij } else if (strcmp(*argv, "-untrusted") == 0) { 256296341Sdelphij if (argc-- < 1) 257296341Sdelphij goto usage; 258296341Sdelphij untrusted = *++argv; 259296341Sdelphij } else if (strcmp(*argv, "-engine") == 0) { 260296341Sdelphij if (argc-- < 1) 261296341Sdelphij goto usage; 262296341Sdelphij engine = *++argv; 263296341Sdelphij } else if ((md = EVP_get_digestbyname(*argv + 1)) != NULL) { 264296341Sdelphij /* empty. */ 265296341Sdelphij } else 266296341Sdelphij goto usage; 267296341Sdelphij } 268238384Sjkim 269296341Sdelphij /* Seed the random number generator if it is going to be used. */ 270296341Sdelphij if (mode == CMD_QUERY && !no_nonce) { 271296341Sdelphij if (!app_RAND_load_file(NULL, bio_err, 1) && rnd == NULL) 272296341Sdelphij BIO_printf(bio_err, "warning, not much extra random " 273296341Sdelphij "data, consider using the -rand option\n"); 274296341Sdelphij if (rnd != NULL) 275296341Sdelphij BIO_printf(bio_err, "%ld semi-random bytes loaded\n", 276296341Sdelphij app_RAND_load_files(rnd)); 277296341Sdelphij } 278238384Sjkim 279296341Sdelphij /* Get the password if required. */ 280296341Sdelphij if (mode == CMD_REPLY && passin && 281296341Sdelphij !app_passwd(bio_err, passin, NULL, &password, NULL)) { 282296341Sdelphij BIO_printf(bio_err, "Error getting password.\n"); 283296341Sdelphij goto cleanup; 284296341Sdelphij } 285238384Sjkim 286296341Sdelphij /* 287296341Sdelphij * Check consistency of parameters and execute the appropriate function. 288296341Sdelphij */ 289296341Sdelphij switch (mode) { 290296341Sdelphij case CMD_NONE: 291296341Sdelphij goto usage; 292296341Sdelphij case CMD_QUERY: 293296341Sdelphij /* 294296341Sdelphij * Data file and message imprint cannot be specified at the same 295296341Sdelphij * time. 296296341Sdelphij */ 297296341Sdelphij ret = data != NULL && digest != NULL; 298296341Sdelphij if (ret) 299296341Sdelphij goto usage; 300296341Sdelphij /* Load the config file for possible policy OIDs. */ 301296341Sdelphij conf = load_config_file(configfile); 302296341Sdelphij ret = !query_command(data, digest, md, policy, no_nonce, cert, 303296341Sdelphij in, out, text); 304296341Sdelphij break; 305296341Sdelphij case CMD_REPLY: 306296341Sdelphij conf = load_config_file(configfile); 307296341Sdelphij if (in == NULL) { 308296341Sdelphij ret = !(queryfile != NULL && conf != NULL && !token_in); 309296341Sdelphij if (ret) 310296341Sdelphij goto usage; 311296341Sdelphij } else { 312296341Sdelphij /* 'in' and 'queryfile' are exclusive. */ 313296341Sdelphij ret = !(queryfile == NULL); 314296341Sdelphij if (ret) 315296341Sdelphij goto usage; 316296341Sdelphij } 317238384Sjkim 318296341Sdelphij ret = !reply_command(conf, section, engine, queryfile, 319296341Sdelphij password, inkey, signer, chain, policy, 320296341Sdelphij in, token_in, out, token_out, text); 321296341Sdelphij break; 322296341Sdelphij case CMD_VERIFY: 323296341Sdelphij ret = !(((queryfile && !data && !digest) 324296341Sdelphij || (!queryfile && data && !digest) 325296341Sdelphij || (!queryfile && !data && digest)) 326296341Sdelphij && in != NULL); 327296341Sdelphij if (ret) 328296341Sdelphij goto usage; 329238384Sjkim 330296341Sdelphij ret = !verify_command(data, digest, queryfile, in, token_in, 331296341Sdelphij ca_path, ca_file, untrusted); 332296341Sdelphij } 333238384Sjkim 334296341Sdelphij goto cleanup; 335296341Sdelphij 336238384Sjkim usage: 337296341Sdelphij BIO_printf(bio_err, "usage:\n" 338296341Sdelphij "ts -query [-rand file%cfile%c...] [-config configfile] " 339296341Sdelphij "[-data file_to_hash] [-digest digest_bytes]" 340296341Sdelphij "[-md2|-md4|-md5|-sha|-sha1|-mdc2|-ripemd160] " 341296341Sdelphij "[-policy object_id] [-no_nonce] [-cert] " 342296341Sdelphij "[-in request.tsq] [-out request.tsq] [-text]\n", 343296341Sdelphij LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR); 344296341Sdelphij BIO_printf(bio_err, "or\n" 345296341Sdelphij "ts -reply [-config configfile] [-section tsa_section] " 346296341Sdelphij "[-queryfile request.tsq] [-passin password] " 347296341Sdelphij "[-signer tsa_cert.pem] [-inkey private_key.pem] " 348296341Sdelphij "[-chain certs_file.pem] [-policy object_id] " 349296341Sdelphij "[-in response.tsr] [-token_in] " 350296341Sdelphij "[-out response.tsr] [-token_out] [-text] [-engine id]\n"); 351296341Sdelphij BIO_printf(bio_err, "or\n" 352296341Sdelphij "ts -verify [-data file_to_hash] [-digest digest_bytes] " 353296341Sdelphij "[-queryfile request.tsq] " 354296341Sdelphij "-in response.tsr [-token_in] " 355296341Sdelphij "-CApath ca_path -CAfile ca_file.pem " 356296341Sdelphij "-untrusted cert_file.pem\n"); 357238384Sjkim cleanup: 358296341Sdelphij /* Clean up. */ 359296341Sdelphij app_RAND_write_file(NULL, bio_err); 360296341Sdelphij NCONF_free(conf); 361296341Sdelphij OPENSSL_free(password); 362296341Sdelphij OBJ_cleanup(); 363296341Sdelphij if (free_bio_err) { 364296341Sdelphij BIO_free_all(bio_err); 365296341Sdelphij bio_err = NULL; 366296341Sdelphij } 367238384Sjkim 368296341Sdelphij OPENSSL_EXIT(ret); 369296341Sdelphij} 370238384Sjkim 371238384Sjkim/* 372238384Sjkim * Configuration file-related function definitions. 373238384Sjkim */ 374238384Sjkim 375238384Sjkimstatic ASN1_OBJECT *txt2obj(const char *oid) 376296341Sdelphij{ 377296341Sdelphij ASN1_OBJECT *oid_obj = NULL; 378238384Sjkim 379296341Sdelphij if (!(oid_obj = OBJ_txt2obj(oid, 0))) 380296341Sdelphij BIO_printf(bio_err, "cannot convert %s to OID\n", oid); 381238384Sjkim 382296341Sdelphij return oid_obj; 383296341Sdelphij} 384238384Sjkim 385238384Sjkimstatic CONF *load_config_file(const char *configfile) 386296341Sdelphij{ 387296341Sdelphij CONF *conf = NULL; 388296341Sdelphij long errorline = -1; 389238384Sjkim 390296341Sdelphij if (!configfile) 391296341Sdelphij configfile = getenv("OPENSSL_CONF"); 392296341Sdelphij if (!configfile) 393296341Sdelphij configfile = getenv("SSLEAY_CONF"); 394238384Sjkim 395296341Sdelphij if (configfile && 396296341Sdelphij (!(conf = NCONF_new(NULL)) || 397296341Sdelphij NCONF_load(conf, configfile, &errorline) <= 0)) { 398296341Sdelphij if (errorline <= 0) 399296341Sdelphij BIO_printf(bio_err, "error loading the config file " 400296341Sdelphij "'%s'\n", configfile); 401296341Sdelphij else 402296341Sdelphij BIO_printf(bio_err, "error on line %ld of config file " 403296341Sdelphij "'%s'\n", errorline, configfile); 404296341Sdelphij } 405238384Sjkim 406296341Sdelphij if (conf != NULL) { 407296341Sdelphij const char *p; 408238384Sjkim 409296341Sdelphij BIO_printf(bio_err, "Using configuration from %s\n", configfile); 410296341Sdelphij p = NCONF_get_string(conf, NULL, ENV_OID_FILE); 411296341Sdelphij if (p != NULL) { 412296341Sdelphij BIO *oid_bio = BIO_new_file(p, "r"); 413296341Sdelphij if (!oid_bio) 414296341Sdelphij ERR_print_errors(bio_err); 415296341Sdelphij else { 416296341Sdelphij OBJ_create_objects(oid_bio); 417296341Sdelphij BIO_free_all(oid_bio); 418296341Sdelphij } 419296341Sdelphij } else 420296341Sdelphij ERR_clear_error(); 421296341Sdelphij if (!add_oid_section(bio_err, conf)) 422296341Sdelphij ERR_print_errors(bio_err); 423296341Sdelphij } 424296341Sdelphij return conf; 425296341Sdelphij} 426238384Sjkim 427238384Sjkim/* 428238384Sjkim * Query-related method definitions. 429238384Sjkim */ 430238384Sjkim 431238384Sjkimstatic int query_command(const char *data, char *digest, const EVP_MD *md, 432296341Sdelphij const char *policy, int no_nonce, 433296341Sdelphij int cert, const char *in, const char *out, int text) 434296341Sdelphij{ 435296341Sdelphij int ret = 0; 436296341Sdelphij TS_REQ *query = NULL; 437296341Sdelphij BIO *in_bio = NULL; 438296341Sdelphij BIO *data_bio = NULL; 439296341Sdelphij BIO *out_bio = NULL; 440238384Sjkim 441296341Sdelphij /* Build query object either from file or from scratch. */ 442296341Sdelphij if (in != NULL) { 443296341Sdelphij if ((in_bio = BIO_new_file(in, "rb")) == NULL) 444296341Sdelphij goto end; 445296341Sdelphij query = d2i_TS_REQ_bio(in_bio, NULL); 446296341Sdelphij } else { 447296341Sdelphij /* 448296341Sdelphij * Open the file if no explicit digest bytes were specified. 449296341Sdelphij */ 450296341Sdelphij if (!digest && !(data_bio = BIO_open_with_default(data, "rb", stdin))) 451296341Sdelphij goto end; 452296341Sdelphij /* Creating the query object. */ 453296341Sdelphij query = create_query(data_bio, digest, md, policy, no_nonce, cert); 454296341Sdelphij /* Saving the random number generator state. */ 455296341Sdelphij } 456296341Sdelphij if (query == NULL) 457296341Sdelphij goto end; 458238384Sjkim 459296341Sdelphij /* Write query either in ASN.1 or in text format. */ 460296341Sdelphij if ((out_bio = BIO_open_with_default(out, "wb", stdout)) == NULL) 461296341Sdelphij goto end; 462296341Sdelphij if (text) { 463296341Sdelphij /* Text output. */ 464296341Sdelphij if (!TS_REQ_print_bio(out_bio, query)) 465296341Sdelphij goto end; 466296341Sdelphij } else { 467296341Sdelphij /* ASN.1 output. */ 468296341Sdelphij if (!i2d_TS_REQ_bio(out_bio, query)) 469296341Sdelphij goto end; 470296341Sdelphij } 471238384Sjkim 472296341Sdelphij ret = 1; 473238384Sjkim 474238384Sjkim end: 475296341Sdelphij ERR_print_errors(bio_err); 476238384Sjkim 477296341Sdelphij /* Clean up. */ 478296341Sdelphij BIO_free_all(in_bio); 479296341Sdelphij BIO_free_all(data_bio); 480296341Sdelphij BIO_free_all(out_bio); 481296341Sdelphij TS_REQ_free(query); 482238384Sjkim 483296341Sdelphij return ret; 484296341Sdelphij} 485238384Sjkim 486296341Sdelphijstatic BIO *BIO_open_with_default(const char *file, const char *mode, 487296341Sdelphij FILE *default_fp) 488296341Sdelphij{ 489296341Sdelphij return file == NULL ? BIO_new_fp(default_fp, BIO_NOCLOSE) 490296341Sdelphij : BIO_new_file(file, mode); 491296341Sdelphij} 492238384Sjkim 493238384Sjkimstatic TS_REQ *create_query(BIO *data_bio, char *digest, const EVP_MD *md, 494296341Sdelphij const char *policy, int no_nonce, int cert) 495296341Sdelphij{ 496296341Sdelphij int ret = 0; 497296341Sdelphij TS_REQ *ts_req = NULL; 498296341Sdelphij int len; 499296341Sdelphij TS_MSG_IMPRINT *msg_imprint = NULL; 500296341Sdelphij X509_ALGOR *algo = NULL; 501296341Sdelphij unsigned char *data = NULL; 502296341Sdelphij ASN1_OBJECT *policy_obj = NULL; 503296341Sdelphij ASN1_INTEGER *nonce_asn1 = NULL; 504238384Sjkim 505296341Sdelphij /* Setting default message digest. */ 506296341Sdelphij if (!md && !(md = EVP_get_digestbyname("sha1"))) 507296341Sdelphij goto err; 508238384Sjkim 509296341Sdelphij /* Creating request object. */ 510296341Sdelphij if (!(ts_req = TS_REQ_new())) 511296341Sdelphij goto err; 512238384Sjkim 513296341Sdelphij /* Setting version. */ 514296341Sdelphij if (!TS_REQ_set_version(ts_req, 1)) 515296341Sdelphij goto err; 516238384Sjkim 517296341Sdelphij /* Creating and adding MSG_IMPRINT object. */ 518296341Sdelphij if (!(msg_imprint = TS_MSG_IMPRINT_new())) 519296341Sdelphij goto err; 520238384Sjkim 521296341Sdelphij /* Adding algorithm. */ 522296341Sdelphij if (!(algo = X509_ALGOR_new())) 523296341Sdelphij goto err; 524296341Sdelphij if (!(algo->algorithm = OBJ_nid2obj(EVP_MD_type(md)))) 525296341Sdelphij goto err; 526296341Sdelphij if (!(algo->parameter = ASN1_TYPE_new())) 527296341Sdelphij goto err; 528296341Sdelphij algo->parameter->type = V_ASN1_NULL; 529296341Sdelphij if (!TS_MSG_IMPRINT_set_algo(msg_imprint, algo)) 530296341Sdelphij goto err; 531238384Sjkim 532296341Sdelphij /* Adding message digest. */ 533296341Sdelphij if ((len = create_digest(data_bio, digest, md, &data)) == 0) 534296341Sdelphij goto err; 535296341Sdelphij if (!TS_MSG_IMPRINT_set_msg(msg_imprint, data, len)) 536296341Sdelphij goto err; 537238384Sjkim 538296341Sdelphij if (!TS_REQ_set_msg_imprint(ts_req, msg_imprint)) 539296341Sdelphij goto err; 540238384Sjkim 541296341Sdelphij /* Setting policy if requested. */ 542296341Sdelphij if (policy && !(policy_obj = txt2obj(policy))) 543296341Sdelphij goto err; 544296341Sdelphij if (policy_obj && !TS_REQ_set_policy_id(ts_req, policy_obj)) 545296341Sdelphij goto err; 546238384Sjkim 547296341Sdelphij /* Setting nonce if requested. */ 548296341Sdelphij if (!no_nonce && !(nonce_asn1 = create_nonce(NONCE_LENGTH))) 549296341Sdelphij goto err; 550296341Sdelphij if (nonce_asn1 && !TS_REQ_set_nonce(ts_req, nonce_asn1)) 551296341Sdelphij goto err; 552238384Sjkim 553296341Sdelphij /* Setting certificate request flag if requested. */ 554296341Sdelphij if (!TS_REQ_set_cert_req(ts_req, cert)) 555296341Sdelphij goto err; 556296341Sdelphij 557296341Sdelphij ret = 1; 558238384Sjkim err: 559296341Sdelphij if (!ret) { 560296341Sdelphij TS_REQ_free(ts_req); 561296341Sdelphij ts_req = NULL; 562296341Sdelphij BIO_printf(bio_err, "could not create query\n"); 563296341Sdelphij } 564296341Sdelphij TS_MSG_IMPRINT_free(msg_imprint); 565296341Sdelphij X509_ALGOR_free(algo); 566296341Sdelphij OPENSSL_free(data); 567296341Sdelphij ASN1_OBJECT_free(policy_obj); 568296341Sdelphij ASN1_INTEGER_free(nonce_asn1); 569296341Sdelphij return ts_req; 570296341Sdelphij} 571238384Sjkim 572238384Sjkimstatic int create_digest(BIO *input, char *digest, const EVP_MD *md, 573296341Sdelphij unsigned char **md_value) 574296341Sdelphij{ 575296341Sdelphij int md_value_len; 576238384Sjkim 577296341Sdelphij md_value_len = EVP_MD_size(md); 578296341Sdelphij if (md_value_len < 0) 579296341Sdelphij goto err; 580296341Sdelphij if (input) { 581296341Sdelphij /* Digest must be computed from an input file. */ 582296341Sdelphij EVP_MD_CTX md_ctx; 583296341Sdelphij unsigned char buffer[4096]; 584296341Sdelphij int length; 585238384Sjkim 586296341Sdelphij *md_value = OPENSSL_malloc(md_value_len); 587296341Sdelphij if (*md_value == 0) 588296341Sdelphij goto err; 589238384Sjkim 590296341Sdelphij EVP_DigestInit(&md_ctx, md); 591296341Sdelphij while ((length = BIO_read(input, buffer, sizeof(buffer))) > 0) { 592296341Sdelphij EVP_DigestUpdate(&md_ctx, buffer, length); 593296341Sdelphij } 594296341Sdelphij EVP_DigestFinal(&md_ctx, *md_value, NULL); 595296341Sdelphij } else { 596296341Sdelphij /* Digest bytes are specified with digest. */ 597296341Sdelphij long digest_len; 598296341Sdelphij *md_value = string_to_hex(digest, &digest_len); 599296341Sdelphij if (!*md_value || md_value_len != digest_len) { 600296341Sdelphij OPENSSL_free(*md_value); 601296341Sdelphij *md_value = NULL; 602296341Sdelphij BIO_printf(bio_err, "bad digest, %d bytes " 603296341Sdelphij "must be specified\n", md_value_len); 604296341Sdelphij goto err; 605296341Sdelphij } 606296341Sdelphij } 607238384Sjkim 608296341Sdelphij return md_value_len; 609238384Sjkim err: 610296341Sdelphij return 0; 611296341Sdelphij} 612238384Sjkim 613238384Sjkimstatic ASN1_INTEGER *create_nonce(int bits) 614296341Sdelphij{ 615296341Sdelphij unsigned char buf[20]; 616296341Sdelphij ASN1_INTEGER *nonce = NULL; 617296341Sdelphij int len = (bits - 1) / 8 + 1; 618296341Sdelphij int i; 619238384Sjkim 620296341Sdelphij /* Generating random byte sequence. */ 621296341Sdelphij if (len > (int)sizeof(buf)) 622296341Sdelphij goto err; 623296341Sdelphij if (RAND_bytes(buf, len) <= 0) 624296341Sdelphij goto err; 625238384Sjkim 626296341Sdelphij /* Find the first non-zero byte and creating ASN1_INTEGER object. */ 627296341Sdelphij for (i = 0; i < len && !buf[i]; ++i) ; 628296341Sdelphij if (!(nonce = ASN1_INTEGER_new())) 629296341Sdelphij goto err; 630296341Sdelphij OPENSSL_free(nonce->data); 631296341Sdelphij /* Allocate at least one byte. */ 632296341Sdelphij nonce->length = len - i; 633296341Sdelphij if (!(nonce->data = OPENSSL_malloc(nonce->length + 1))) 634296341Sdelphij goto err; 635296341Sdelphij memcpy(nonce->data, buf + i, nonce->length); 636238384Sjkim 637296341Sdelphij return nonce; 638238384Sjkim err: 639296341Sdelphij BIO_printf(bio_err, "could not create nonce\n"); 640296341Sdelphij ASN1_INTEGER_free(nonce); 641296341Sdelphij return NULL; 642296341Sdelphij} 643296341Sdelphij 644238384Sjkim/* 645238384Sjkim * Reply-related method definitions. 646238384Sjkim */ 647238384Sjkim 648296341Sdelphijstatic int reply_command(CONF *conf, char *section, char *engine, 649296341Sdelphij char *queryfile, char *passin, char *inkey, 650296341Sdelphij char *signer, char *chain, const char *policy, 651296341Sdelphij char *in, int token_in, 652296341Sdelphij char *out, int token_out, int text) 653296341Sdelphij{ 654296341Sdelphij int ret = 0; 655296341Sdelphij TS_RESP *response = NULL; 656296341Sdelphij BIO *in_bio = NULL; 657296341Sdelphij BIO *query_bio = NULL; 658296341Sdelphij BIO *inkey_bio = NULL; 659296341Sdelphij BIO *signer_bio = NULL; 660296341Sdelphij BIO *out_bio = NULL; 661238384Sjkim 662296341Sdelphij /* Build response object either from response or query. */ 663296341Sdelphij if (in != NULL) { 664296341Sdelphij if ((in_bio = BIO_new_file(in, "rb")) == NULL) 665296341Sdelphij goto end; 666296341Sdelphij if (token_in) { 667296341Sdelphij /* 668296341Sdelphij * We have a ContentInfo (PKCS7) object, add 'granted' status 669296341Sdelphij * info around it. 670296341Sdelphij */ 671296341Sdelphij response = read_PKCS7(in_bio); 672296341Sdelphij } else { 673296341Sdelphij /* We have a ready-made TS_RESP object. */ 674296341Sdelphij response = d2i_TS_RESP_bio(in_bio, NULL); 675296341Sdelphij } 676296341Sdelphij } else { 677296341Sdelphij response = create_response(conf, section, engine, queryfile, 678296341Sdelphij passin, inkey, signer, chain, policy); 679296341Sdelphij if (response) 680296341Sdelphij BIO_printf(bio_err, "Response has been generated.\n"); 681296341Sdelphij else 682296341Sdelphij BIO_printf(bio_err, "Response is not generated.\n"); 683296341Sdelphij } 684296341Sdelphij if (response == NULL) 685296341Sdelphij goto end; 686238384Sjkim 687296341Sdelphij /* Write response either in ASN.1 or text format. */ 688296341Sdelphij if ((out_bio = BIO_open_with_default(out, "wb", stdout)) == NULL) 689296341Sdelphij goto end; 690296341Sdelphij if (text) { 691296341Sdelphij /* Text output. */ 692296341Sdelphij if (token_out) { 693296341Sdelphij TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response); 694296341Sdelphij if (!TS_TST_INFO_print_bio(out_bio, tst_info)) 695296341Sdelphij goto end; 696296341Sdelphij } else { 697296341Sdelphij if (!TS_RESP_print_bio(out_bio, response)) 698296341Sdelphij goto end; 699296341Sdelphij } 700296341Sdelphij } else { 701296341Sdelphij /* ASN.1 DER output. */ 702296341Sdelphij if (token_out) { 703296341Sdelphij PKCS7 *token = TS_RESP_get_token(response); 704296341Sdelphij if (!i2d_PKCS7_bio(out_bio, token)) 705296341Sdelphij goto end; 706296341Sdelphij } else { 707296341Sdelphij if (!i2d_TS_RESP_bio(out_bio, response)) 708296341Sdelphij goto end; 709296341Sdelphij } 710296341Sdelphij } 711238384Sjkim 712296341Sdelphij ret = 1; 713238384Sjkim 714238384Sjkim end: 715296341Sdelphij ERR_print_errors(bio_err); 716238384Sjkim 717296341Sdelphij /* Clean up. */ 718296341Sdelphij BIO_free_all(in_bio); 719296341Sdelphij BIO_free_all(query_bio); 720296341Sdelphij BIO_free_all(inkey_bio); 721296341Sdelphij BIO_free_all(signer_bio); 722296341Sdelphij BIO_free_all(out_bio); 723296341Sdelphij TS_RESP_free(response); 724238384Sjkim 725296341Sdelphij return ret; 726296341Sdelphij} 727238384Sjkim 728238384Sjkim/* Reads a PKCS7 token and adds default 'granted' status info to it. */ 729238384Sjkimstatic TS_RESP *read_PKCS7(BIO *in_bio) 730296341Sdelphij{ 731296341Sdelphij int ret = 0; 732296341Sdelphij PKCS7 *token = NULL; 733296341Sdelphij TS_TST_INFO *tst_info = NULL; 734296341Sdelphij TS_RESP *resp = NULL; 735296341Sdelphij TS_STATUS_INFO *si = NULL; 736238384Sjkim 737296341Sdelphij /* Read PKCS7 object and extract the signed time stamp info. */ 738296341Sdelphij if (!(token = d2i_PKCS7_bio(in_bio, NULL))) 739296341Sdelphij goto end; 740296341Sdelphij if (!(tst_info = PKCS7_to_TS_TST_INFO(token))) 741296341Sdelphij goto end; 742238384Sjkim 743296341Sdelphij /* Creating response object. */ 744296341Sdelphij if (!(resp = TS_RESP_new())) 745296341Sdelphij goto end; 746238384Sjkim 747296341Sdelphij /* Create granted status info. */ 748296341Sdelphij if (!(si = TS_STATUS_INFO_new())) 749296341Sdelphij goto end; 750296341Sdelphij if (!(ASN1_INTEGER_set(si->status, TS_STATUS_GRANTED))) 751296341Sdelphij goto end; 752296341Sdelphij if (!TS_RESP_set_status_info(resp, si)) 753296341Sdelphij goto end; 754238384Sjkim 755296341Sdelphij /* Setting encapsulated token. */ 756296341Sdelphij TS_RESP_set_tst_info(resp, token, tst_info); 757296341Sdelphij token = NULL; /* Ownership is lost. */ 758296341Sdelphij tst_info = NULL; /* Ownership is lost. */ 759238384Sjkim 760296341Sdelphij ret = 1; 761238384Sjkim end: 762296341Sdelphij PKCS7_free(token); 763296341Sdelphij TS_TST_INFO_free(tst_info); 764296341Sdelphij if (!ret) { 765296341Sdelphij TS_RESP_free(resp); 766296341Sdelphij resp = NULL; 767296341Sdelphij } 768296341Sdelphij TS_STATUS_INFO_free(si); 769296341Sdelphij return resp; 770296341Sdelphij} 771238384Sjkim 772296341Sdelphijstatic TS_RESP *create_response(CONF *conf, const char *section, char *engine, 773296341Sdelphij char *queryfile, char *passin, char *inkey, 774296341Sdelphij char *signer, char *chain, const char *policy) 775296341Sdelphij{ 776296341Sdelphij int ret = 0; 777296341Sdelphij TS_RESP *response = NULL; 778296341Sdelphij BIO *query_bio = NULL; 779296341Sdelphij TS_RESP_CTX *resp_ctx = NULL; 780238384Sjkim 781296341Sdelphij if (!(query_bio = BIO_new_file(queryfile, "rb"))) 782296341Sdelphij goto end; 783238384Sjkim 784296341Sdelphij /* Getting TSA configuration section. */ 785296341Sdelphij if (!(section = TS_CONF_get_tsa_section(conf, section))) 786296341Sdelphij goto end; 787238384Sjkim 788296341Sdelphij /* Setting up response generation context. */ 789296341Sdelphij if (!(resp_ctx = TS_RESP_CTX_new())) 790296341Sdelphij goto end; 791238384Sjkim 792296341Sdelphij /* Setting serial number provider callback. */ 793296341Sdelphij if (!TS_CONF_set_serial(conf, section, serial_cb, resp_ctx)) 794296341Sdelphij goto end; 795238384Sjkim#ifndef OPENSSL_NO_ENGINE 796296341Sdelphij /* Setting default OpenSSL engine. */ 797296341Sdelphij if (!TS_CONF_set_crypto_device(conf, section, engine)) 798296341Sdelphij goto end; 799238384Sjkim#endif 800238384Sjkim 801296341Sdelphij /* Setting TSA signer certificate. */ 802296341Sdelphij if (!TS_CONF_set_signer_cert(conf, section, signer, resp_ctx)) 803296341Sdelphij goto end; 804238384Sjkim 805296341Sdelphij /* Setting TSA signer certificate chain. */ 806296341Sdelphij if (!TS_CONF_set_certs(conf, section, chain, resp_ctx)) 807296341Sdelphij goto end; 808238384Sjkim 809296341Sdelphij /* Setting TSA signer private key. */ 810296341Sdelphij if (!TS_CONF_set_signer_key(conf, section, inkey, passin, resp_ctx)) 811296341Sdelphij goto end; 812238384Sjkim 813296341Sdelphij /* Setting default policy OID. */ 814296341Sdelphij if (!TS_CONF_set_def_policy(conf, section, policy, resp_ctx)) 815296341Sdelphij goto end; 816238384Sjkim 817296341Sdelphij /* Setting acceptable policy OIDs. */ 818296341Sdelphij if (!TS_CONF_set_policies(conf, section, resp_ctx)) 819296341Sdelphij goto end; 820238384Sjkim 821296341Sdelphij /* Setting the acceptable one-way hash algorithms. */ 822296341Sdelphij if (!TS_CONF_set_digests(conf, section, resp_ctx)) 823296341Sdelphij goto end; 824238384Sjkim 825296341Sdelphij /* Setting guaranteed time stamp accuracy. */ 826296341Sdelphij if (!TS_CONF_set_accuracy(conf, section, resp_ctx)) 827296341Sdelphij goto end; 828238384Sjkim 829296341Sdelphij /* Setting the precision of the time. */ 830296341Sdelphij if (!TS_CONF_set_clock_precision_digits(conf, section, resp_ctx)) 831296341Sdelphij goto end; 832238384Sjkim 833296341Sdelphij /* Setting the ordering flaf if requested. */ 834296341Sdelphij if (!TS_CONF_set_ordering(conf, section, resp_ctx)) 835296341Sdelphij goto end; 836238384Sjkim 837296341Sdelphij /* Setting the TSA name required flag if requested. */ 838296341Sdelphij if (!TS_CONF_set_tsa_name(conf, section, resp_ctx)) 839296341Sdelphij goto end; 840238384Sjkim 841296341Sdelphij /* Setting the ESS cert id chain flag if requested. */ 842296341Sdelphij if (!TS_CONF_set_ess_cert_id_chain(conf, section, resp_ctx)) 843296341Sdelphij goto end; 844238384Sjkim 845296341Sdelphij /* Creating the response. */ 846296341Sdelphij if (!(response = TS_RESP_create_response(resp_ctx, query_bio))) 847296341Sdelphij goto end; 848238384Sjkim 849296341Sdelphij ret = 1; 850238384Sjkim end: 851296341Sdelphij if (!ret) { 852296341Sdelphij TS_RESP_free(response); 853296341Sdelphij response = NULL; 854296341Sdelphij } 855296341Sdelphij TS_RESP_CTX_free(resp_ctx); 856296341Sdelphij BIO_free_all(query_bio); 857238384Sjkim 858296341Sdelphij return response; 859296341Sdelphij} 860238384Sjkim 861296341Sdelphijstatic ASN1_INTEGER *MS_CALLBACK serial_cb(TS_RESP_CTX *ctx, void *data) 862296341Sdelphij{ 863296341Sdelphij const char *serial_file = (const char *)data; 864296341Sdelphij ASN1_INTEGER *serial = next_serial(serial_file); 865238384Sjkim 866296341Sdelphij if (!serial) { 867296341Sdelphij TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION, 868296341Sdelphij "Error during serial number " 869296341Sdelphij "generation."); 870296341Sdelphij TS_RESP_CTX_add_failure_info(ctx, TS_INFO_ADD_INFO_NOT_AVAILABLE); 871296341Sdelphij } else 872296341Sdelphij save_ts_serial(serial_file, serial); 873238384Sjkim 874296341Sdelphij return serial; 875296341Sdelphij} 876238384Sjkim 877238384Sjkimstatic ASN1_INTEGER *next_serial(const char *serialfile) 878296341Sdelphij{ 879296341Sdelphij int ret = 0; 880296341Sdelphij BIO *in = NULL; 881296341Sdelphij ASN1_INTEGER *serial = NULL; 882296341Sdelphij BIGNUM *bn = NULL; 883238384Sjkim 884296341Sdelphij if (!(serial = ASN1_INTEGER_new())) 885296341Sdelphij goto err; 886238384Sjkim 887296341Sdelphij if (!(in = BIO_new_file(serialfile, "r"))) { 888296341Sdelphij ERR_clear_error(); 889296341Sdelphij BIO_printf(bio_err, "Warning: could not open file %s for " 890296341Sdelphij "reading, using serial number: 1\n", serialfile); 891296341Sdelphij if (!ASN1_INTEGER_set(serial, 1)) 892296341Sdelphij goto err; 893296341Sdelphij } else { 894296341Sdelphij char buf[1024]; 895296341Sdelphij if (!a2i_ASN1_INTEGER(in, serial, buf, sizeof(buf))) { 896296341Sdelphij BIO_printf(bio_err, "unable to load number from %s\n", 897296341Sdelphij serialfile); 898296341Sdelphij goto err; 899296341Sdelphij } 900296341Sdelphij if (!(bn = ASN1_INTEGER_to_BN(serial, NULL))) 901296341Sdelphij goto err; 902296341Sdelphij ASN1_INTEGER_free(serial); 903296341Sdelphij serial = NULL; 904296341Sdelphij if (!BN_add_word(bn, 1)) 905296341Sdelphij goto err; 906296341Sdelphij if (!(serial = BN_to_ASN1_INTEGER(bn, NULL))) 907296341Sdelphij goto err; 908296341Sdelphij } 909296341Sdelphij ret = 1; 910238384Sjkim err: 911296341Sdelphij if (!ret) { 912296341Sdelphij ASN1_INTEGER_free(serial); 913296341Sdelphij serial = NULL; 914296341Sdelphij } 915296341Sdelphij BIO_free_all(in); 916296341Sdelphij BN_free(bn); 917296341Sdelphij return serial; 918296341Sdelphij} 919238384Sjkim 920238384Sjkimstatic int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial) 921296341Sdelphij{ 922296341Sdelphij int ret = 0; 923296341Sdelphij BIO *out = NULL; 924238384Sjkim 925296341Sdelphij if (!(out = BIO_new_file(serialfile, "w"))) 926296341Sdelphij goto err; 927296341Sdelphij if (i2a_ASN1_INTEGER(out, serial) <= 0) 928296341Sdelphij goto err; 929296341Sdelphij if (BIO_puts(out, "\n") <= 0) 930296341Sdelphij goto err; 931296341Sdelphij ret = 1; 932238384Sjkim err: 933296341Sdelphij if (!ret) 934296341Sdelphij BIO_printf(bio_err, "could not save serial number to %s\n", 935296341Sdelphij serialfile); 936296341Sdelphij BIO_free_all(out); 937296341Sdelphij return ret; 938296341Sdelphij} 939238384Sjkim 940238384Sjkim/* 941238384Sjkim * Verify-related method definitions. 942238384Sjkim */ 943238384Sjkim 944238384Sjkimstatic int verify_command(char *data, char *digest, char *queryfile, 945296341Sdelphij char *in, int token_in, 946296341Sdelphij char *ca_path, char *ca_file, char *untrusted) 947296341Sdelphij{ 948296341Sdelphij BIO *in_bio = NULL; 949296341Sdelphij PKCS7 *token = NULL; 950296341Sdelphij TS_RESP *response = NULL; 951296341Sdelphij TS_VERIFY_CTX *verify_ctx = NULL; 952296341Sdelphij int ret = 0; 953238384Sjkim 954296341Sdelphij /* Decode the token (PKCS7) or response (TS_RESP) files. */ 955296341Sdelphij if (!(in_bio = BIO_new_file(in, "rb"))) 956296341Sdelphij goto end; 957296341Sdelphij if (token_in) { 958296341Sdelphij if (!(token = d2i_PKCS7_bio(in_bio, NULL))) 959296341Sdelphij goto end; 960296341Sdelphij } else { 961296341Sdelphij if (!(response = d2i_TS_RESP_bio(in_bio, NULL))) 962296341Sdelphij goto end; 963296341Sdelphij } 964238384Sjkim 965296341Sdelphij if (!(verify_ctx = create_verify_ctx(data, digest, queryfile, 966296341Sdelphij ca_path, ca_file, untrusted))) 967296341Sdelphij goto end; 968238384Sjkim 969296341Sdelphij /* Checking the token or response against the request. */ 970296341Sdelphij ret = token_in ? 971296341Sdelphij TS_RESP_verify_token(verify_ctx, token) : 972296341Sdelphij TS_RESP_verify_response(verify_ctx, response); 973238384Sjkim 974238384Sjkim end: 975296341Sdelphij printf("Verification: "); 976296341Sdelphij if (ret) 977296341Sdelphij printf("OK\n"); 978296341Sdelphij else { 979296341Sdelphij printf("FAILED\n"); 980296341Sdelphij /* Print errors, if there are any. */ 981296341Sdelphij ERR_print_errors(bio_err); 982296341Sdelphij } 983238384Sjkim 984296341Sdelphij /* Clean up. */ 985296341Sdelphij BIO_free_all(in_bio); 986296341Sdelphij PKCS7_free(token); 987296341Sdelphij TS_RESP_free(response); 988296341Sdelphij TS_VERIFY_CTX_free(verify_ctx); 989296341Sdelphij return ret; 990296341Sdelphij} 991238384Sjkim 992296341Sdelphijstatic TS_VERIFY_CTX *create_verify_ctx(char *data, char *digest, 993296341Sdelphij char *queryfile, 994296341Sdelphij char *ca_path, char *ca_file, 995296341Sdelphij char *untrusted) 996296341Sdelphij{ 997296341Sdelphij TS_VERIFY_CTX *ctx = NULL; 998296341Sdelphij BIO *input = NULL; 999296341Sdelphij TS_REQ *request = NULL; 1000296341Sdelphij int ret = 0; 1001238384Sjkim 1002296341Sdelphij if (data != NULL || digest != NULL) { 1003296341Sdelphij if (!(ctx = TS_VERIFY_CTX_new())) 1004296341Sdelphij goto err; 1005296341Sdelphij ctx->flags = TS_VFY_VERSION | TS_VFY_SIGNER; 1006296341Sdelphij if (data != NULL) { 1007296341Sdelphij ctx->flags |= TS_VFY_DATA; 1008296341Sdelphij if (!(ctx->data = BIO_new_file(data, "rb"))) 1009296341Sdelphij goto err; 1010296341Sdelphij } else if (digest != NULL) { 1011296341Sdelphij long imprint_len; 1012296341Sdelphij ctx->flags |= TS_VFY_IMPRINT; 1013296341Sdelphij if (!(ctx->imprint = string_to_hex(digest, &imprint_len))) { 1014296341Sdelphij BIO_printf(bio_err, "invalid digest string\n"); 1015296341Sdelphij goto err; 1016296341Sdelphij } 1017296341Sdelphij ctx->imprint_len = imprint_len; 1018296341Sdelphij } 1019238384Sjkim 1020296341Sdelphij } else if (queryfile != NULL) { 1021296341Sdelphij /* 1022296341Sdelphij * The request has just to be read, decoded and converted to a verify 1023296341Sdelphij * context object. 1024296341Sdelphij */ 1025296341Sdelphij if (!(input = BIO_new_file(queryfile, "rb"))) 1026296341Sdelphij goto err; 1027296341Sdelphij if (!(request = d2i_TS_REQ_bio(input, NULL))) 1028296341Sdelphij goto err; 1029296341Sdelphij if (!(ctx = TS_REQ_to_TS_VERIFY_CTX(request, NULL))) 1030296341Sdelphij goto err; 1031296341Sdelphij } else 1032296341Sdelphij return NULL; 1033238384Sjkim 1034296341Sdelphij /* Add the signature verification flag and arguments. */ 1035296341Sdelphij ctx->flags |= TS_VFY_SIGNATURE; 1036238384Sjkim 1037296341Sdelphij /* Initialising the X509_STORE object. */ 1038296341Sdelphij if (!(ctx->store = create_cert_store(ca_path, ca_file))) 1039296341Sdelphij goto err; 1040296341Sdelphij 1041296341Sdelphij /* Loading untrusted certificates. */ 1042296341Sdelphij if (untrusted && !(ctx->certs = TS_CONF_load_certs(untrusted))) 1043296341Sdelphij goto err; 1044296341Sdelphij 1045296341Sdelphij ret = 1; 1046238384Sjkim err: 1047296341Sdelphij if (!ret) { 1048296341Sdelphij TS_VERIFY_CTX_free(ctx); 1049296341Sdelphij ctx = NULL; 1050296341Sdelphij } 1051296341Sdelphij BIO_free_all(input); 1052296341Sdelphij TS_REQ_free(request); 1053296341Sdelphij return ctx; 1054296341Sdelphij} 1055238384Sjkim 1056238384Sjkimstatic X509_STORE *create_cert_store(char *ca_path, char *ca_file) 1057296341Sdelphij{ 1058296341Sdelphij X509_STORE *cert_ctx = NULL; 1059296341Sdelphij X509_LOOKUP *lookup = NULL; 1060296341Sdelphij int i; 1061238384Sjkim 1062296341Sdelphij /* Creating the X509_STORE object. */ 1063296341Sdelphij cert_ctx = X509_STORE_new(); 1064238384Sjkim 1065296341Sdelphij /* Setting the callback for certificate chain verification. */ 1066296341Sdelphij X509_STORE_set_verify_cb(cert_ctx, verify_cb); 1067238384Sjkim 1068296341Sdelphij /* Adding a trusted certificate directory source. */ 1069296341Sdelphij if (ca_path) { 1070296341Sdelphij lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir()); 1071296341Sdelphij if (lookup == NULL) { 1072296341Sdelphij BIO_printf(bio_err, "memory allocation failure\n"); 1073296341Sdelphij goto err; 1074296341Sdelphij } 1075296341Sdelphij i = X509_LOOKUP_add_dir(lookup, ca_path, X509_FILETYPE_PEM); 1076296341Sdelphij if (!i) { 1077296341Sdelphij BIO_printf(bio_err, "Error loading directory %s\n", ca_path); 1078296341Sdelphij goto err; 1079296341Sdelphij } 1080296341Sdelphij } 1081238384Sjkim 1082296341Sdelphij /* Adding a trusted certificate file source. */ 1083296341Sdelphij if (ca_file) { 1084296341Sdelphij lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file()); 1085296341Sdelphij if (lookup == NULL) { 1086296341Sdelphij BIO_printf(bio_err, "memory allocation failure\n"); 1087296341Sdelphij goto err; 1088296341Sdelphij } 1089296341Sdelphij i = X509_LOOKUP_load_file(lookup, ca_file, X509_FILETYPE_PEM); 1090296341Sdelphij if (!i) { 1091296341Sdelphij BIO_printf(bio_err, "Error loading file %s\n", ca_file); 1092296341Sdelphij goto err; 1093296341Sdelphij } 1094296341Sdelphij } 1095238384Sjkim 1096296341Sdelphij return cert_ctx; 1097238384Sjkim err: 1098296341Sdelphij X509_STORE_free(cert_ctx); 1099296341Sdelphij return NULL; 1100296341Sdelphij} 1101238384Sjkim 1102238384Sjkimstatic int MS_CALLBACK verify_cb(int ok, X509_STORE_CTX *ctx) 1103296341Sdelphij{ 1104296341Sdelphij /*- 1105296341Sdelphij char buf[256]; 1106238384Sjkim 1107296341Sdelphij if (!ok) 1108296341Sdelphij { 1109296341Sdelphij X509_NAME_oneline(X509_get_subject_name(ctx->current_cert), 1110296341Sdelphij buf, sizeof(buf)); 1111296341Sdelphij printf("%s\n", buf); 1112296341Sdelphij printf("error %d at %d depth lookup: %s\n", 1113296341Sdelphij ctx->error, ctx->error_depth, 1114296341Sdelphij X509_verify_cert_error_string(ctx->error)); 1115296341Sdelphij } 1116296341Sdelphij */ 1117238384Sjkim 1118296341Sdelphij return ok; 1119296341Sdelphij} 1120