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