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