~ubuntu-branches/ubuntu/lucid/openssl/lucid-proposed

« back to all changes in this revision

Viewing changes to apps/ts.c

  • Committer: Bazaar Package Importer
  • Author(s): Nicolas Valcárcel Scerpella (Canonical)
  • Date: 2009-12-06 20:16:24 UTC
  • mfrom: (11.1.9 sid)
  • Revision ID: james.westby@ubuntu.com-20091206201624-u126qjpqm2n2uuhu
Tags: 0.9.8k-7ubuntu1
* Merge from debian unstable, remaining changes (LP: #493392):
  - Link using -Bsymbolic-functions
  - Add support for lpia
  - Disable SSLv2 during compile
  - Ship documentation in openssl-doc, suggested by the package.
  - Use a different priority for libssl0.9.8/restart-services
    depending on whether a desktop, or server dist-upgrade is being
    performed.
  - Display a system restart required notification bubble on libssl0.9.8
    upgrade.
  - Replace duplicate files in the doc directory with symlinks.
  - Move runtime libraries to /lib, for the benefit of wpasupplicant
* Strip the patches out of the source into quilt patches
* Disable CVE-2009-3555.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* apps/ts.c */
 
2
/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
 
3
 * project 2002.
 
4
 */
 
5
/* ====================================================================
 
6
 * Copyright (c) 2001 The OpenSSL Project.  All rights reserved.
 
7
 *
 
8
 * Redistribution and use in source and binary forms, with or without
 
9
 * modification, are permitted provided that the following conditions
 
10
 * are met:
 
11
 *
 
12
 * 1. Redistributions of source code must retain the above copyright
 
13
 *    notice, this list of conditions and the following disclaimer. 
 
14
 *
 
15
 * 2. Redistributions in binary form must reproduce the above copyright
 
16
 *    notice, this list of conditions and the following disclaimer in
 
17
 *    the documentation and/or other materials provided with the
 
18
 *    distribution.
 
19
 *
 
20
 * 3. All advertising materials mentioning features or use of this
 
21
 *    software must display the following acknowledgment:
 
22
 *    "This product includes software developed by the OpenSSL Project
 
23
 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
 
24
 *
 
25
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 
26
 *    endorse or promote products derived from this software without
 
27
 *    prior written permission. For written permission, please contact
 
28
 *    licensing@OpenSSL.org.
 
29
 *
 
30
 * 5. Products derived from this software may not be called "OpenSSL"
 
31
 *    nor may "OpenSSL" appear in their names without prior written
 
32
 *    permission of the OpenSSL Project.
 
33
 *
 
34
 * 6. Redistributions of any form whatsoever must retain the following
 
35
 *    acknowledgment:
 
36
 *    "This product includes software developed by the OpenSSL Project
 
37
 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
 
38
 *
 
39
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 
40
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
41
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
42
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 
43
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
44
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
45
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
46
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
47
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 
48
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
49
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 
50
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 
51
 * ====================================================================
 
52
 *
 
53
 * This product includes cryptographic software written by Eric Young
 
54
 * (eay@cryptsoft.com).  This product includes software written by Tim
 
55
 * Hudson (tjh@cryptsoft.com).
 
56
 *
 
57
 */
 
58
 
 
59
#include <stdio.h>
 
60
#include <stdlib.h>
 
61
#include <string.h>
 
62
#include "apps.h"
 
63
#include <openssl/bio.h>
 
64
#include <openssl/err.h>
 
65
#include <openssl/pem.h>
 
66
#include <openssl/rand.h>
 
67
#include <openssl/ts.h>
 
68
#include <openssl/bn.h>
 
69
 
 
70
#undef PROG
 
71
#define PROG    ts_main
 
72
 
 
73
/* Length of the nonce of the request in bits (must be a multiple of 8). */
 
74
#define NONCE_LENGTH            64
 
75
 
 
76
/* Macro definitions for the configuration file. */
 
77
#define ENV_OID_FILE            "oid_file"
 
78
 
 
79
/* Local function declarations. */
 
80
 
 
81
static ASN1_OBJECT *txt2obj(const char *oid);
 
82
static CONF *load_config_file(const char *configfile);
 
83
 
 
84
/* Query related functions. */
 
85
static int query_command(const char *data, char *digest,
 
86
                         const EVP_MD *md, const char *policy, int no_nonce, 
 
87
                         int cert, const char *in, const char *out, int text);
 
88
static BIO *BIO_open_with_default(const char *file, const char *mode, 
 
89
                                  FILE *default_fp);
 
90
static TS_REQ *create_query(BIO *data_bio, char *digest, const EVP_MD *md,
 
91
                            const char *policy, int no_nonce, int cert);
 
92
static int create_digest(BIO *input, char *digest,
 
93
                         const EVP_MD *md, unsigned char **md_value);
 
94
static ASN1_INTEGER *create_nonce(int bits);
 
95
 
 
96
/* Reply related functions. */
 
97
static int reply_command(CONF *conf, char *section, char *engine, 
 
98
                         char *queryfile, char *passin, char *inkey, 
 
99
                         char *signer, char *chain, const char *policy, 
 
100
                         char *in, int token_in, char *out, int token_out,
 
101
                         int text);
 
102
static TS_RESP *read_PKCS7(BIO *in_bio);
 
103
static TS_RESP *create_response(CONF *conf, const char *section, char *engine,
 
104
                                char *queryfile, char *passin, char *inkey,
 
105
                                char *signer, char *chain, const char *policy);
 
106
static ASN1_INTEGER * MS_CALLBACK serial_cb(TS_RESP_CTX *ctx, void *data);
 
107
static ASN1_INTEGER *next_serial(const char *serialfile);
 
108
static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial);
 
109
 
 
110
/* Verify related functions. */
 
111
static int verify_command(char *data, char *digest, char *queryfile,
 
112
                          char *in, int token_in,
 
113
                          char *ca_path, char *ca_file, char *untrusted);
 
114
static TS_VERIFY_CTX *create_verify_ctx(char *data, char *digest, 
 
115
                                        char *queryfile, 
 
116
                                        char *ca_path, char *ca_file,
 
117
                                        char *untrusted);
 
118
static X509_STORE *create_cert_store(char *ca_path, char *ca_file);
 
119
static int MS_CALLBACK verify_cb(int ok, X509_STORE_CTX *ctx);
 
120
 
 
121
/* Main function definition. */
 
122
int MAIN(int, char **);
 
123
 
 
124
int MAIN(int argc, char **argv)
 
125
        {
 
126
        int ret = 1;
 
127
        char *configfile = NULL;
 
128
        char *section = NULL;
 
129
        CONF *conf = NULL;
 
130
        enum mode {
 
131
        CMD_NONE, CMD_QUERY, CMD_REPLY, CMD_VERIFY 
 
132
        } mode = CMD_NONE;
 
133
        char *data = NULL;
 
134
        char *digest = NULL;
 
135
        const EVP_MD *md = NULL;
 
136
        char *rnd = NULL;
 
137
        char *policy = NULL;
 
138
        int no_nonce = 0;
 
139
        int cert = 0;
 
140
        char *in = NULL;
 
141
        char *out = NULL;
 
142
        int text = 0;
 
143
        char *queryfile = NULL;
 
144
        char *passin = NULL;    /* Password source. */
 
145
        char *password =NULL;   /* Password itself. */
 
146
        char *inkey = NULL;
 
147
        char *signer = NULL;
 
148
        char *chain = NULL;
 
149
        char *ca_path = NULL;
 
150
        char *ca_file = NULL;
 
151
        char *untrusted = NULL;
 
152
        char *engine = NULL;
 
153
        /* Input is ContentInfo instead of TimeStampResp. */
 
154
        int token_in = 0;       
 
155
        /* Output is ContentInfo instead of TimeStampResp. */
 
156
        int token_out = 0;
 
157
        int free_bio_err = 0;
 
158
 
 
159
        ERR_load_crypto_strings();
 
160
        apps_startup();
 
161
 
 
162
        if (bio_err == NULL && (bio_err = BIO_new(BIO_s_file())) != NULL)
 
163
                {
 
164
                free_bio_err = 1;
 
165
                BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
 
166
                }
 
167
 
 
168
        for (argc--, argv++; argc > 0; argc--, argv++)
 
169
                {
 
170
                if (strcmp(*argv, "-config") == 0)
 
171
                        {
 
172
                        if (argc-- < 1) goto usage;
 
173
                        configfile = *++argv;
 
174
                        }
 
175
                else if (strcmp(*argv, "-section") == 0)
 
176
                        {
 
177
                        if (argc-- < 1) goto usage;
 
178
                        section = *++argv;
 
179
                        }
 
180
                else if (strcmp(*argv, "-query") == 0)
 
181
                        {
 
182
                        if (mode != CMD_NONE) goto usage;
 
183
                        mode = CMD_QUERY;
 
184
                        }
 
185
                else if (strcmp(*argv, "-data") == 0)
 
186
                        {
 
187
                        if (argc-- < 1) goto usage;
 
188
                        data = *++argv;
 
189
                        }
 
190
                else if (strcmp(*argv, "-digest") == 0)
 
191
                        {
 
192
                        if (argc-- < 1) goto usage;
 
193
                        digest = *++argv;
 
194
                        }
 
195
                else if (strcmp(*argv, "-rand") == 0)
 
196
                        {
 
197
                        if (argc-- < 1) goto usage;
 
198
                        rnd = *++argv;
 
199
                        }
 
200
                else if (strcmp(*argv, "-policy") == 0)
 
201
                        {
 
202
                        if (argc-- < 1) goto usage;
 
203
                        policy = *++argv;
 
204
                        }
 
205
                else if (strcmp(*argv, "-no_nonce") == 0)
 
206
                        {
 
207
                        no_nonce = 1;
 
208
                        }
 
209
                else if (strcmp(*argv, "-cert") == 0)
 
210
                        {
 
211
                        cert = 1;
 
212
                        }
 
213
                else if (strcmp(*argv, "-in") == 0)
 
214
                        {
 
215
                        if (argc-- < 1) goto usage;
 
216
                        in = *++argv;
 
217
                        }
 
218
                else if (strcmp(*argv, "-token_in") == 0)
 
219
                        {
 
220
                        token_in = 1;
 
221
                        }
 
222
                else if (strcmp(*argv, "-out") == 0)
 
223
                        {
 
224
                        if (argc-- < 1) goto usage;
 
225
                        out = *++argv;
 
226
                        }
 
227
                else if (strcmp(*argv, "-token_out") == 0)
 
228
                        {
 
229
                        token_out = 1;
 
230
                        }
 
231
                else if (strcmp(*argv, "-text") == 0)
 
232
                        {
 
233
                        text = 1;
 
234
                        }
 
235
                else if (strcmp(*argv, "-reply") == 0)
 
236
                        {
 
237
                        if (mode != CMD_NONE) goto usage;
 
238
                        mode = CMD_REPLY;
 
239
                        }
 
240
                else if (strcmp(*argv, "-queryfile") == 0)
 
241
                        {
 
242
                        if (argc-- < 1) goto usage;
 
243
                        queryfile = *++argv;
 
244
                        }
 
245
                else if (strcmp(*argv, "-passin") == 0)
 
246
                        {
 
247
                        if (argc-- < 1) goto usage;
 
248
                        passin = *++argv;
 
249
                        }
 
250
                else if (strcmp(*argv, "-inkey") == 0)
 
251
                        {
 
252
                        if (argc-- < 1) goto usage;
 
253
                        inkey = *++argv;
 
254
                        }
 
255
                else if (strcmp(*argv, "-signer") == 0)
 
256
                        {
 
257
                        if (argc-- < 1) goto usage;
 
258
                        signer = *++argv;
 
259
                        }
 
260
                else if (strcmp(*argv, "-chain") == 0)
 
261
                        {
 
262
                        if (argc-- < 1) goto usage;
 
263
                        chain = *++argv;
 
264
                        }
 
265
                else if (strcmp(*argv, "-verify") == 0)
 
266
                        {
 
267
                        if (mode != CMD_NONE) goto usage;
 
268
                        mode = CMD_VERIFY;
 
269
                        }
 
270
                else if (strcmp(*argv, "-CApath") == 0)
 
271
                        {
 
272
                        if (argc-- < 1) goto usage;
 
273
                        ca_path = *++argv;
 
274
                        }
 
275
                else if (strcmp(*argv, "-CAfile") == 0)
 
276
                        {
 
277
                        if (argc-- < 1) goto usage;
 
278
                        ca_file = *++argv;
 
279
                        }
 
280
                else if (strcmp(*argv, "-untrusted") == 0)
 
281
                        {
 
282
                        if (argc-- < 1) goto usage;
 
283
                        untrusted = *++argv;
 
284
                        }
 
285
                else if (strcmp(*argv, "-engine") == 0)
 
286
                        {
 
287
                        if (argc-- < 1) goto usage;
 
288
                        engine = *++argv;
 
289
                        }
 
290
                else if ((md = EVP_get_digestbyname(*argv + 1)) != NULL)
 
291
                        {
 
292
                        /* empty. */
 
293
                        }
 
294
                else
 
295
                        goto usage;
 
296
                }
 
297
        
 
298
        /* Seed the random number generator if it is going to be used. */
 
299
        if (mode == CMD_QUERY && !no_nonce)
 
300
                {
 
301
                if (!app_RAND_load_file(NULL, bio_err, 1) && rnd == NULL)
 
302
                        BIO_printf(bio_err, "warning, not much extra random "
 
303
                                   "data, consider using the -rand option\n");
 
304
                if (rnd != NULL)
 
305
                        BIO_printf(bio_err,"%ld semi-random bytes loaded\n",
 
306
                                   app_RAND_load_files(rnd));
 
307
                }
 
308
 
 
309
        /* Get the password if required. */
 
310
        if(mode == CMD_REPLY && passin &&
 
311
           !app_passwd(bio_err, passin, NULL, &password, NULL))
 
312
                {
 
313
                BIO_printf(bio_err,"Error getting password.\n");
 
314
                goto cleanup;
 
315
                }
 
316
 
 
317
        /* Check consistency of parameters and execute 
 
318
           the appropriate function. */
 
319
        switch (mode)
 
320
                {
 
321
        case CMD_NONE:
 
322
                goto usage;
 
323
        case CMD_QUERY:
 
324
                /* Data file and message imprint cannot be specified
 
325
                   at the same time. */
 
326
                ret = data != NULL && digest != NULL;
 
327
                if (ret) goto usage;
 
328
                /* Load the config file for possible policy OIDs. */
 
329
                conf = load_config_file(configfile);
 
330
                ret = !query_command(data, digest, md, policy, no_nonce, cert,
 
331
                                     in, out, text);
 
332
                break;
 
333
        case CMD_REPLY:
 
334
                conf = load_config_file(configfile);
 
335
                if (in == NULL)
 
336
                        {
 
337
                        ret = !(queryfile != NULL && conf != NULL && !token_in);
 
338
                        if (ret) goto usage;
 
339
                        }
 
340
                else
 
341
                        {
 
342
                        /* 'in' and 'queryfile' are exclusive. */
 
343
                        ret = !(queryfile == NULL);
 
344
                        if (ret) goto usage;
 
345
                        }
 
346
 
 
347
                ret = !reply_command(conf, section, engine, queryfile, 
 
348
                                     password, inkey, signer, chain, policy, 
 
349
                                     in, token_in, out, token_out, text);
 
350
                break;
 
351
        case CMD_VERIFY:
 
352
                ret = !(((queryfile && !data && !digest)
 
353
                         || (!queryfile && data && !digest)
 
354
                         || (!queryfile && !data && digest))
 
355
                        && in != NULL);
 
356
                if (ret) goto usage;
 
357
 
 
358
                ret = !verify_command(data, digest, queryfile, in, token_in,
 
359
                                      ca_path, ca_file, untrusted);
 
360
                }
 
361
 
 
362
        goto cleanup;
 
363
 
 
364
 usage:
 
365
        BIO_printf(bio_err, "usage:\n"
 
366
                   "ts -query [-rand file%cfile%c...] [-config configfile] "
 
367
                   "[-data file_to_hash] [-digest digest_bytes]"
 
368
                   "[-md2|-md4|-md5|-sha|-sha1|-mdc2|-ripemd160] "
 
369
                   "[-policy object_id] [-no_nonce] [-cert] "
 
370
                   "[-in request.tsq] [-out request.tsq] [-text]\n",
 
371
                   LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR);
 
372
        BIO_printf(bio_err, "or\n"
 
373
                   "ts -reply [-config configfile] [-section tsa_section] "
 
374
                   "[-queryfile request.tsq] [-passin password] "
 
375
                   "[-signer tsa_cert.pem] [-inkey private_key.pem] "
 
376
                   "[-chain certs_file.pem] [-policy object_id] "
 
377
                   "[-in response.tsr] [-token_in] "
 
378
                   "[-out response.tsr] [-token_out] [-text] [-engine id]\n");
 
379
        BIO_printf(bio_err, "or\n"
 
380
                   "ts -verify [-data file_to_hash] [-digest digest_bytes] "
 
381
                   "[-queryfile request.tsq] "
 
382
                   "-in response.tsr [-token_in] "
 
383
                   "-CApath ca_path -CAfile ca_file.pem "
 
384
                   "-untrusted cert_file.pem\n");
 
385
 cleanup:
 
386
        /* Clean up. */
 
387
        app_RAND_write_file(NULL, bio_err);
 
388
        NCONF_free(conf);
 
389
        OPENSSL_free(password);
 
390
        OBJ_cleanup();
 
391
        if (free_bio_err)
 
392
                {
 
393
                BIO_free_all(bio_err);
 
394
                bio_err = NULL;
 
395
                }
 
396
 
 
397
        OPENSSL_EXIT(ret);
 
398
        }
 
399
 
 
400
/*
 
401
 * Configuration file-related function definitions.
 
402
 */
 
403
 
 
404
static ASN1_OBJECT *txt2obj(const char *oid)
 
405
        {
 
406
        ASN1_OBJECT *oid_obj = NULL;
 
407
 
 
408
        if (!(oid_obj = OBJ_txt2obj(oid, 0)))
 
409
                BIO_printf(bio_err, "cannot convert %s to OID\n", oid);
 
410
 
 
411
        return oid_obj;
 
412
        }
 
413
 
 
414
static CONF *load_config_file(const char *configfile)
 
415
        {
 
416
        CONF *conf = NULL;
 
417
        long errorline = -1;
 
418
 
 
419
        if (!configfile) configfile = getenv("OPENSSL_CONF");
 
420
        if (!configfile) configfile = getenv("SSLEAY_CONF");
 
421
 
 
422
        if (configfile &&
 
423
            (!(conf = NCONF_new(NULL)) ||
 
424
             NCONF_load(conf, configfile, &errorline) <= 0))
 
425
                {
 
426
                if (errorline <= 0)
 
427
                        BIO_printf(bio_err, "error loading the config file "
 
428
                                   "'%s'\n", configfile);
 
429
                else
 
430
                        BIO_printf(bio_err, "error on line %ld of config file "
 
431
                                   "'%s'\n", errorline, configfile);
 
432
                }
 
433
 
 
434
        if (conf != NULL)
 
435
                {
 
436
                const char *p;
 
437
 
 
438
                BIO_printf(bio_err,"Using configuration from %s\n", configfile);
 
439
                p = NCONF_get_string(conf, NULL, ENV_OID_FILE);
 
440
                if (p != NULL)
 
441
                        {
 
442
                        BIO *oid_bio = BIO_new_file(p, "r");
 
443
                        if (!oid_bio) 
 
444
                                ERR_print_errors(bio_err);
 
445
                        else
 
446
                                {
 
447
                                OBJ_create_objects(oid_bio);
 
448
                                BIO_free_all(oid_bio);
 
449
                                }
 
450
                        }
 
451
                else
 
452
                        ERR_clear_error();
 
453
                if(!add_oid_section(bio_err, conf)) 
 
454
                        ERR_print_errors(bio_err);
 
455
                }
 
456
        return conf;
 
457
        }
 
458
 
 
459
/*
 
460
 * Query-related method definitions.
 
461
 */
 
462
 
 
463
static int query_command(const char *data, char *digest, const EVP_MD *md,
 
464
                         const char *policy, int no_nonce, 
 
465
                         int cert, const char *in, const char *out, int text)
 
466
        {
 
467
        int ret = 0;
 
468
        TS_REQ *query = NULL;
 
469
        BIO *in_bio = NULL;
 
470
        BIO *data_bio = NULL;
 
471
        BIO *out_bio = NULL;
 
472
 
 
473
        /* Build query object either from file or from scratch. */
 
474
        if (in != NULL)
 
475
                {
 
476
                if ((in_bio = BIO_new_file(in, "rb")) == NULL) goto end;
 
477
                query = d2i_TS_REQ_bio(in_bio, NULL);
 
478
                }
 
479
        else
 
480
                {
 
481
                /* Open the file if no explicit digest bytes were specified. */
 
482
                if (!digest 
 
483
                    && !(data_bio = BIO_open_with_default(data, "rb", stdin)))
 
484
                        goto end;
 
485
                /* Creating the query object. */
 
486
                query = create_query(data_bio, digest, md,
 
487
                                     policy, no_nonce, cert);
 
488
                /* Saving the random number generator state. */
 
489
                }
 
490
        if (query == NULL) goto end;
 
491
 
 
492
        /* Write query either in ASN.1 or in text format. */
 
493
        if ((out_bio = BIO_open_with_default(out, "wb", stdout)) == NULL)
 
494
                goto end;
 
495
        if (text)
 
496
                {
 
497
                /* Text output. */
 
498
                if (!TS_REQ_print_bio(out_bio, query))
 
499
                        goto end;
 
500
                }
 
501
        else
 
502
                {
 
503
                /* ASN.1 output. */
 
504
                if (!i2d_TS_REQ_bio(out_bio, query))
 
505
                        goto end;
 
506
                }
 
507
 
 
508
        ret = 1;
 
509
 
 
510
 end:
 
511
        ERR_print_errors(bio_err);
 
512
 
 
513
        /* Clean up. */
 
514
        BIO_free_all(in_bio);
 
515
        BIO_free_all(data_bio);
 
516
        BIO_free_all(out_bio);
 
517
        TS_REQ_free(query);
 
518
 
 
519
        return ret;
 
520
        }
 
521
 
 
522
static BIO *BIO_open_with_default(const char *file, const char *mode, 
 
523
                                  FILE *default_fp)
 
524
        {
 
525
        return file == NULL ? 
 
526
                BIO_new_fp(default_fp, BIO_NOCLOSE) 
 
527
                : BIO_new_file(file, mode);
 
528
        }
 
529
 
 
530
static TS_REQ *create_query(BIO *data_bio, char *digest, const EVP_MD *md,
 
531
                            const char *policy, int no_nonce, int cert)
 
532
        {
 
533
        int ret = 0;
 
534
        TS_REQ *ts_req = NULL;
 
535
        int len;
 
536
        TS_MSG_IMPRINT *msg_imprint = NULL;
 
537
        X509_ALGOR *algo = NULL;
 
538
        unsigned char *data = NULL;
 
539
        ASN1_OBJECT *policy_obj = NULL;
 
540
        ASN1_INTEGER *nonce_asn1 = NULL;
 
541
 
 
542
        /* Setting default message digest. */
 
543
        if (!md && !(md = EVP_get_digestbyname("sha1"))) goto err;
 
544
 
 
545
        /* Creating request object. */
 
546
        if (!(ts_req = TS_REQ_new())) goto err;
 
547
 
 
548
        /* Setting version. */
 
549
        if (!TS_REQ_set_version(ts_req, 1)) goto err;
 
550
 
 
551
        /* Creating and adding MSG_IMPRINT object. */
 
552
        if (!(msg_imprint = TS_MSG_IMPRINT_new())) goto err;
 
553
 
 
554
        /* Adding algorithm. */
 
555
        if (!(algo = X509_ALGOR_new())) goto err;
 
556
        if (!(algo->algorithm = OBJ_nid2obj(EVP_MD_type(md)))) goto err;
 
557
        if (!(algo->parameter = ASN1_TYPE_new())) goto err;
 
558
        algo->parameter->type = V_ASN1_NULL;
 
559
        if (!TS_MSG_IMPRINT_set_algo(msg_imprint, algo)) goto err;
 
560
 
 
561
        /* Adding message digest. */
 
562
        if ((len = create_digest(data_bio, digest, md, &data)) == 0)
 
563
                goto err;
 
564
        if (!TS_MSG_IMPRINT_set_msg(msg_imprint, data, len)) goto err;
 
565
 
 
566
        if (!TS_REQ_set_msg_imprint(ts_req, msg_imprint)) goto err;
 
567
        
 
568
        /* Setting policy if requested. */
 
569
        if (policy && !(policy_obj = txt2obj(policy))) goto err;
 
570
        if (policy_obj && !TS_REQ_set_policy_id(ts_req, policy_obj)) goto err;
 
571
 
 
572
        /* Setting nonce if requested. */
 
573
        if (!no_nonce && !(nonce_asn1 = create_nonce(NONCE_LENGTH))) goto err;
 
574
        if (nonce_asn1 && !TS_REQ_set_nonce(ts_req, nonce_asn1)) goto err;
 
575
 
 
576
        /* Setting certificate request flag if requested. */
 
577
        if (!TS_REQ_set_cert_req(ts_req, cert)) goto err;
 
578
 
 
579
        ret = 1;
 
580
 err:
 
581
        if (!ret)
 
582
                {
 
583
                TS_REQ_free(ts_req);
 
584
                ts_req = NULL;
 
585
                BIO_printf(bio_err, "could not create query\n");
 
586
                }
 
587
        TS_MSG_IMPRINT_free(msg_imprint);
 
588
        X509_ALGOR_free(algo);
 
589
        OPENSSL_free(data);
 
590
        ASN1_OBJECT_free(policy_obj);
 
591
        ASN1_INTEGER_free(nonce_asn1);
 
592
        return ts_req;
 
593
        }
 
594
 
 
595
static int create_digest(BIO *input, char *digest, const EVP_MD *md,
 
596
                         unsigned char **md_value)
 
597
        {
 
598
        int md_value_len;
 
599
 
 
600
        md_value_len = EVP_MD_size(md);
 
601
        if (md_value_len < 0)
 
602
            goto err;
 
603
        if (input)
 
604
                {
 
605
                /* Digest must be computed from an input file. */
 
606
                EVP_MD_CTX md_ctx;
 
607
                unsigned char buffer[4096];
 
608
                int length;
 
609
 
 
610
                *md_value = OPENSSL_malloc(md_value_len);
 
611
                if (*md_value == 0) goto err;
 
612
 
 
613
                EVP_DigestInit(&md_ctx, md);
 
614
                while ((length = BIO_read(input, buffer, sizeof(buffer))) > 0)
 
615
                        {
 
616
                        EVP_DigestUpdate(&md_ctx, buffer, length);
 
617
                        }
 
618
                EVP_DigestFinal(&md_ctx, *md_value, NULL);
 
619
                }
 
620
        else
 
621
                {
 
622
                /* Digest bytes are specified with digest. */
 
623
                long digest_len;
 
624
                *md_value = string_to_hex(digest, &digest_len);
 
625
                if (!*md_value || md_value_len != digest_len)
 
626
                        {
 
627
                        OPENSSL_free(*md_value);
 
628
                        *md_value = NULL;
 
629
                        BIO_printf(bio_err, "bad digest, %d bytes "
 
630
                                   "must be specified\n", md_value_len);
 
631
                        goto err;
 
632
                        }
 
633
                }
 
634
 
 
635
        return md_value_len;
 
636
 err:
 
637
        return 0;
 
638
        }
 
639
 
 
640
static ASN1_INTEGER *create_nonce(int bits)
 
641
        {
 
642
        unsigned char buf[20];
 
643
        ASN1_INTEGER *nonce = NULL;
 
644
        int len = (bits - 1) / 8 + 1;
 
645
        int i;
 
646
 
 
647
        /* Generating random byte sequence. */
 
648
        if (len > (int)sizeof(buf)) goto err;
 
649
        if (!RAND_bytes(buf, len)) goto err;
 
650
 
 
651
        /* Find the first non-zero byte and creating ASN1_INTEGER object. */
 
652
        for (i = 0; i < len && !buf[i]; ++i);
 
653
        if (!(nonce = ASN1_INTEGER_new())) goto err;
 
654
        OPENSSL_free(nonce->data);
 
655
        /* Allocate at least one byte. */
 
656
        nonce->length = len - i;
 
657
        if (!(nonce->data = OPENSSL_malloc(nonce->length + 1))) goto err;
 
658
        memcpy(nonce->data, buf + i, nonce->length);
 
659
 
 
660
        return nonce;
 
661
 err:
 
662
        BIO_printf(bio_err, "could not create nonce\n");
 
663
        ASN1_INTEGER_free(nonce);
 
664
        return NULL;
 
665
        }
 
666
/*
 
667
 * Reply-related method definitions.
 
668
 */
 
669
 
 
670
static int reply_command(CONF *conf, char *section, char *engine, 
 
671
                         char *queryfile, char *passin, char *inkey,
 
672
                         char *signer, char *chain, const char *policy, 
 
673
                         char *in, int token_in,
 
674
                         char *out, int token_out, int text)
 
675
        {
 
676
        int ret = 0;
 
677
        TS_RESP *response = NULL;
 
678
        BIO *in_bio = NULL;
 
679
        BIO *query_bio = NULL;
 
680
        BIO *inkey_bio = NULL;
 
681
        BIO *signer_bio = NULL;
 
682
        BIO *out_bio = NULL;
 
683
 
 
684
        /* Build response object either from response or query. */
 
685
        if (in != NULL)
 
686
                {
 
687
                if ((in_bio = BIO_new_file(in, "rb")) == NULL) goto end;
 
688
                if (token_in)
 
689
                        {
 
690
                        /* We have a ContentInfo (PKCS7) object, add
 
691
                           'granted' status info around it. */
 
692
                        response = read_PKCS7(in_bio);
 
693
                        }
 
694
                else
 
695
                        {
 
696
                        /* We have a ready-made TS_RESP object. */
 
697
                        response = d2i_TS_RESP_bio(in_bio, NULL);
 
698
                        }
 
699
                }
 
700
        else
 
701
                {
 
702
                response = create_response(conf, section, engine, queryfile,
 
703
                                           passin, inkey, signer, chain,
 
704
                                           policy);
 
705
                if (response)
 
706
                        BIO_printf(bio_err, "Response has been generated.\n");
 
707
                else
 
708
                        BIO_printf(bio_err, "Response is not generated.\n");
 
709
                }
 
710
        if (response == NULL) goto end;
 
711
 
 
712
        /* Write response either in ASN.1 or text format. */
 
713
        if ((out_bio = BIO_open_with_default(out, "wb", stdout)) == NULL)
 
714
                goto end;
 
715
        if (text)
 
716
                {
 
717
                /* Text output. */
 
718
                if (token_out)
 
719
                        {
 
720
                        TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response);
 
721
                        if (!TS_TST_INFO_print_bio(out_bio, tst_info)) goto end;
 
722
                        }
 
723
                else
 
724
                        {
 
725
                        if (!TS_RESP_print_bio(out_bio, response)) goto end;
 
726
                        }
 
727
                }
 
728
        else
 
729
                {
 
730
                /* ASN.1 DER output. */
 
731
                if (token_out)
 
732
                        {
 
733
                        PKCS7 *token = TS_RESP_get_token(response);
 
734
                        if (!i2d_PKCS7_bio(out_bio, token)) goto end;
 
735
                        }
 
736
                else
 
737
                        {
 
738
                        if (!i2d_TS_RESP_bio(out_bio, response)) goto end;
 
739
                        }
 
740
                }
 
741
 
 
742
        ret = 1;
 
743
 
 
744
 end:
 
745
        ERR_print_errors(bio_err);
 
746
 
 
747
        /* Clean up. */
 
748
        BIO_free_all(in_bio);
 
749
        BIO_free_all(query_bio);
 
750
        BIO_free_all(inkey_bio);
 
751
        BIO_free_all(signer_bio);
 
752
        BIO_free_all(out_bio);
 
753
        TS_RESP_free(response);
 
754
 
 
755
        return ret;
 
756
        }
 
757
 
 
758
/* Reads a PKCS7 token and adds default 'granted' status info to it. */
 
759
static TS_RESP *read_PKCS7(BIO *in_bio)
 
760
        {
 
761
        int ret = 0;
 
762
        PKCS7 *token = NULL;
 
763
        TS_TST_INFO *tst_info = NULL;
 
764
        TS_RESP *resp = NULL;
 
765
        TS_STATUS_INFO *si = NULL;
 
766
 
 
767
        /* Read PKCS7 object and extract the signed time stamp info. */
 
768
        if (!(token = d2i_PKCS7_bio(in_bio, NULL))) goto end;
 
769
        if (!(tst_info = PKCS7_to_TS_TST_INFO(token))) goto end;
 
770
 
 
771
        /* Creating response object. */
 
772
        if (!(resp = TS_RESP_new())) goto end;
 
773
 
 
774
        /* Create granted status info. */
 
775
        if (!(si = TS_STATUS_INFO_new())) goto end;
 
776
        if (!(ASN1_INTEGER_set(si->status, TS_STATUS_GRANTED))) goto end;
 
777
        if (!TS_RESP_set_status_info(resp, si)) goto end;
 
778
 
 
779
        /* Setting encapsulated token. */
 
780
        TS_RESP_set_tst_info(resp, token, tst_info);
 
781
        token = NULL;           /* Ownership is lost. */
 
782
        tst_info = NULL;        /* Ownership is lost. */
 
783
 
 
784
        ret = 1;
 
785
 end:
 
786
        PKCS7_free(token);
 
787
        TS_TST_INFO_free(tst_info);
 
788
        if (!ret)
 
789
                {
 
790
                TS_RESP_free(resp);
 
791
                resp = NULL;
 
792
                }
 
793
        TS_STATUS_INFO_free(si);
 
794
        return resp;
 
795
        }
 
796
 
 
797
static TS_RESP *create_response(CONF *conf, const char *section, char *engine, 
 
798
                                char *queryfile, char *passin, char *inkey,
 
799
                                char *signer, char *chain, const char *policy)
 
800
        {
 
801
        int ret = 0;
 
802
        TS_RESP *response = NULL;
 
803
        BIO *query_bio = NULL;
 
804
        TS_RESP_CTX *resp_ctx = NULL;
 
805
 
 
806
        if (!(query_bio = BIO_new_file(queryfile, "rb")))
 
807
                goto end;
 
808
 
 
809
        /* Getting TSA configuration section. */
 
810
        if (!(section = TS_CONF_get_tsa_section(conf, section)))
 
811
                goto end;
 
812
 
 
813
        /* Setting up response generation context. */
 
814
        if (!(resp_ctx = TS_RESP_CTX_new())) goto end;
 
815
 
 
816
        /* Setting serial number provider callback. */
 
817
        if (!TS_CONF_set_serial(conf, section, serial_cb, resp_ctx)) goto end;
 
818
#ifndef OPENSSL_NO_ENGINE
 
819
        /* Setting default OpenSSL engine. */
 
820
        if (!TS_CONF_set_crypto_device(conf, section, engine)) goto end;
 
821
#endif
 
822
 
 
823
        /* Setting TSA signer certificate. */
 
824
        if (!TS_CONF_set_signer_cert(conf, section, signer, resp_ctx)) goto end;
 
825
 
 
826
        /* Setting TSA signer certificate chain. */
 
827
        if (!TS_CONF_set_certs(conf, section, chain, resp_ctx)) goto end;
 
828
 
 
829
        /* Setting TSA signer private key. */
 
830
        if (!TS_CONF_set_signer_key(conf, section, inkey, passin, resp_ctx))
 
831
                goto end;
 
832
 
 
833
        /* Setting default policy OID. */
 
834
        if (!TS_CONF_set_def_policy(conf, section, policy, resp_ctx)) goto end;
 
835
 
 
836
        /* Setting acceptable policy OIDs. */
 
837
        if (!TS_CONF_set_policies(conf, section, resp_ctx)) goto end;
 
838
 
 
839
        /* Setting the acceptable one-way hash algorithms. */
 
840
        if (!TS_CONF_set_digests(conf, section, resp_ctx)) goto end;
 
841
 
 
842
        /* Setting guaranteed time stamp accuracy. */
 
843
        if (!TS_CONF_set_accuracy(conf, section, resp_ctx)) goto end;
 
844
 
 
845
        /* Setting the precision of the time. */
 
846
        if (!TS_CONF_set_clock_precision_digits(conf, section, resp_ctx))
 
847
                goto end;
 
848
 
 
849
        /* Setting the ordering flaf if requested. */
 
850
        if (!TS_CONF_set_ordering(conf, section, resp_ctx)) goto end;
 
851
 
 
852
        /* Setting the TSA name required flag if requested. */
 
853
        if (!TS_CONF_set_tsa_name(conf, section, resp_ctx)) goto end;
 
854
 
 
855
        /* Setting the ESS cert id chain flag if requested. */
 
856
        if (!TS_CONF_set_ess_cert_id_chain(conf, section, resp_ctx)) goto end;
 
857
 
 
858
        /* Creating the response. */
 
859
        if (!(response = TS_RESP_create_response(resp_ctx, query_bio)))
 
860
                goto end;
 
861
 
 
862
        ret = 1;
 
863
 end:
 
864
        if (!ret) 
 
865
                {
 
866
                TS_RESP_free(response);
 
867
                response = NULL;
 
868
                }
 
869
        TS_RESP_CTX_free(resp_ctx);
 
870
        BIO_free_all(query_bio);
 
871
 
 
872
        return response;
 
873
        }
 
874
 
 
875
static ASN1_INTEGER * MS_CALLBACK serial_cb(TS_RESP_CTX *ctx, void *data)
 
876
        {
 
877
        const char *serial_file = (const char *) data;
 
878
        ASN1_INTEGER *serial = next_serial(serial_file);
 
879
 
 
880
        if (!serial)
 
881
                {
 
882
                TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
 
883
                                            "Error during serial number "
 
884
                                            "generation.");
 
885
                TS_RESP_CTX_add_failure_info(ctx,
 
886
                                             TS_INFO_ADD_INFO_NOT_AVAILABLE);
 
887
                }
 
888
        else
 
889
                save_ts_serial(serial_file, serial);
 
890
 
 
891
        return serial;
 
892
        }
 
893
 
 
894
static ASN1_INTEGER *next_serial(const char *serialfile)
 
895
        {
 
896
        int ret = 0;
 
897
        BIO *in = NULL;
 
898
        ASN1_INTEGER *serial = NULL;
 
899
        BIGNUM *bn = NULL;
 
900
 
 
901
        if (!(serial = ASN1_INTEGER_new())) goto err;
 
902
 
 
903
        if (!(in = BIO_new_file(serialfile, "r"))) 
 
904
                {
 
905
                ERR_clear_error();
 
906
                BIO_printf(bio_err, "Warning: could not open file %s for "
 
907
                           "reading, using serial number: 1\n", serialfile);
 
908
                if (!ASN1_INTEGER_set(serial, 1)) goto err;
 
909
                }
 
910
        else
 
911
                {
 
912
                char buf[1024];
 
913
                if (!a2i_ASN1_INTEGER(in, serial, buf, sizeof(buf)))
 
914
                        {
 
915
                        BIO_printf(bio_err, "unable to load number from %s\n",
 
916
                                   serialfile);
 
917
                        goto err;
 
918
                        }
 
919
                if (!(bn = ASN1_INTEGER_to_BN(serial, NULL))) goto err;
 
920
                ASN1_INTEGER_free(serial);
 
921
                serial = NULL;
 
922
                if (!BN_add_word(bn, 1)) goto err;
 
923
                if (!(serial = BN_to_ASN1_INTEGER(bn, NULL))) goto err;
 
924
                }
 
925
        ret = 1;
 
926
 err:
 
927
        if (!ret)
 
928
                {
 
929
                ASN1_INTEGER_free(serial);
 
930
                serial = NULL;
 
931
                }
 
932
        BIO_free_all(in);
 
933
        BN_free(bn);
 
934
        return serial;
 
935
        }
 
936
 
 
937
static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial)
 
938
        {
 
939
        int ret = 0;
 
940
        BIO *out = NULL;
 
941
 
 
942
        if (!(out = BIO_new_file(serialfile, "w"))) goto err;
 
943
        if (i2a_ASN1_INTEGER(out, serial) <= 0) goto err;
 
944
        if (BIO_puts(out, "\n") <= 0) goto err;
 
945
        ret = 1;
 
946
 err:
 
947
        if (!ret)
 
948
                BIO_printf(bio_err, "could not save serial number to %s\n",
 
949
                           serialfile);
 
950
        BIO_free_all(out);
 
951
        return ret;
 
952
        }
 
953
 
 
954
/*
 
955
 * Verify-related method definitions.
 
956
 */
 
957
 
 
958
static int verify_command(char *data, char *digest, char *queryfile,
 
959
                          char *in, int token_in,
 
960
                          char *ca_path, char *ca_file, char *untrusted)
 
961
        {
 
962
        BIO *in_bio = NULL;
 
963
        PKCS7 *token = NULL;
 
964
        TS_RESP *response = NULL;
 
965
        TS_VERIFY_CTX *verify_ctx = NULL;
 
966
        int ret = 0;
 
967
 
 
968
        /* Decode the token (PKCS7) or response (TS_RESP) files. */
 
969
        if (!(in_bio = BIO_new_file(in, "rb"))) goto end;
 
970
        if (token_in)
 
971
                {
 
972
                if (!(token = d2i_PKCS7_bio(in_bio, NULL))) goto end;
 
973
                }
 
974
        else
 
975
                {
 
976
                if (!(response = d2i_TS_RESP_bio(in_bio, NULL))) goto end;
 
977
                }
 
978
 
 
979
        if (!(verify_ctx = create_verify_ctx(data, digest, queryfile, 
 
980
                                             ca_path, ca_file, untrusted)))
 
981
                goto end;
 
982
 
 
983
        /* Checking the token or response against the request. */
 
984
        ret = token_in ?
 
985
                TS_RESP_verify_token(verify_ctx, token) :
 
986
                TS_RESP_verify_response(verify_ctx, response);
 
987
 
 
988
 end:
 
989
        printf("Verification: ");
 
990
        if (ret)
 
991
                printf("OK\n");
 
992
        else
 
993
                {
 
994
                printf("FAILED\n");
 
995
                /* Print errors, if there are any. */
 
996
                ERR_print_errors(bio_err);
 
997
                }
 
998
        
 
999
        /* Clean up. */
 
1000
        BIO_free_all(in_bio);
 
1001
        PKCS7_free(token);
 
1002
        TS_RESP_free(response);
 
1003
        TS_VERIFY_CTX_free(verify_ctx);
 
1004
        return ret;
 
1005
        }
 
1006
 
 
1007
static TS_VERIFY_CTX *create_verify_ctx(char *data, char *digest, 
 
1008
                                        char *queryfile, 
 
1009
                                        char *ca_path, char *ca_file,
 
1010
                                        char *untrusted)
 
1011
        {
 
1012
        TS_VERIFY_CTX *ctx = NULL;
 
1013
        BIO *input = NULL;
 
1014
        TS_REQ *request = NULL;
 
1015
        int ret = 0;
 
1016
 
 
1017
        if (data != NULL || digest != NULL)
 
1018
                {
 
1019
                if (!(ctx = TS_VERIFY_CTX_new())) goto err;
 
1020
                ctx->flags = TS_VFY_VERSION | TS_VFY_SIGNER;
 
1021
                if (data != NULL)
 
1022
                        {
 
1023
                        ctx->flags |= TS_VFY_DATA;
 
1024
                        if (!(ctx->data = BIO_new_file(data, "rb"))) goto err;
 
1025
                        }
 
1026
                else if (digest != NULL)
 
1027
                        {
 
1028
                        long imprint_len;
 
1029
                        ctx->flags |= TS_VFY_IMPRINT;
 
1030
                        if (!(ctx->imprint = string_to_hex(digest,
 
1031
                                                           &imprint_len)))
 
1032
                                {
 
1033
                                BIO_printf(bio_err, "invalid digest string\n");
 
1034
                                goto err;
 
1035
                                }
 
1036
                        ctx->imprint_len = imprint_len;
 
1037
                        }
 
1038
                
 
1039
                }
 
1040
        else if (queryfile != NULL)
 
1041
                {
 
1042
                /* The request has just to be read, decoded and converted to
 
1043
                   a verify context object. */
 
1044
                if (!(input = BIO_new_file(queryfile, "rb"))) goto err;
 
1045
                if (!(request = d2i_TS_REQ_bio(input, NULL))) goto err;
 
1046
                if (!(ctx = TS_REQ_to_TS_VERIFY_CTX(request, NULL))) goto err;
 
1047
                }
 
1048
        else
 
1049
                return NULL;
 
1050
 
 
1051
        /* Add the signature verification flag and arguments. */
 
1052
        ctx->flags |= TS_VFY_SIGNATURE;
 
1053
 
 
1054
        /* Initialising the X509_STORE object. */
 
1055
        if (!(ctx->store = create_cert_store(ca_path, ca_file))) goto err;
 
1056
 
 
1057
        /* Loading untrusted certificates. */
 
1058
        if (untrusted && !(ctx->certs = TS_CONF_load_certs(untrusted))) 
 
1059
                goto err;
 
1060
 
 
1061
        ret = 1;
 
1062
 err:
 
1063
        if (!ret)
 
1064
                {
 
1065
                TS_VERIFY_CTX_free(ctx);
 
1066
                ctx = NULL;
 
1067
                }
 
1068
        BIO_free_all(input);
 
1069
        TS_REQ_free(request);
 
1070
        return ctx;
 
1071
        }
 
1072
 
 
1073
static X509_STORE *create_cert_store(char *ca_path, char *ca_file)
 
1074
        {
 
1075
        X509_STORE *cert_ctx = NULL;
 
1076
        X509_LOOKUP *lookup = NULL;
 
1077
        int i;
 
1078
 
 
1079
        /* Creating the X509_STORE object. */
 
1080
        cert_ctx = X509_STORE_new();
 
1081
 
 
1082
        /* Setting the callback for certificate chain verification. */
 
1083
        X509_STORE_set_verify_cb_func(cert_ctx, verify_cb);
 
1084
 
 
1085
        /* Adding a trusted certificate directory source. */
 
1086
        if (ca_path)
 
1087
                {
 
1088
                lookup = X509_STORE_add_lookup(cert_ctx,
 
1089
                                               X509_LOOKUP_hash_dir());
 
1090
                if (lookup == NULL)
 
1091
                        {
 
1092
                        BIO_printf(bio_err, "memory allocation failure\n");
 
1093
                        goto err;
 
1094
                        }
 
1095
                i = X509_LOOKUP_add_dir(lookup, ca_path, X509_FILETYPE_PEM);
 
1096
                if (!i)
 
1097
                        {
 
1098
                        BIO_printf(bio_err, "Error loading directory %s\n",
 
1099
                                   ca_path);
 
1100
                        goto err;
 
1101
                        }
 
1102
                }
 
1103
 
 
1104
        /* Adding a trusted certificate file source. */
 
1105
        if (ca_file)
 
1106
                {
 
1107
                lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());
 
1108
                if (lookup == NULL)
 
1109
                        {
 
1110
                        BIO_printf(bio_err, "memory allocation failure\n");
 
1111
                        goto err;
 
1112
                        }
 
1113
                i = X509_LOOKUP_load_file(lookup, ca_file, X509_FILETYPE_PEM);
 
1114
                if (!i)
 
1115
                        {
 
1116
                        BIO_printf(bio_err, "Error loading file %s\n", ca_file);
 
1117
                        goto err;
 
1118
                        }
 
1119
                }
 
1120
 
 
1121
        return cert_ctx;
 
1122
 err:
 
1123
        X509_STORE_free(cert_ctx);
 
1124
        return NULL;
 
1125
        }
 
1126
 
 
1127
static int MS_CALLBACK verify_cb(int ok, X509_STORE_CTX *ctx)
 
1128
        {
 
1129
        /*
 
1130
        char buf[256];
 
1131
 
 
1132
        if (!ok)
 
1133
                {
 
1134
                X509_NAME_oneline(X509_get_subject_name(ctx->current_cert),
 
1135
                                  buf, sizeof(buf));
 
1136
                printf("%s\n", buf);
 
1137
                printf("error %d at %d depth lookup: %s\n",
 
1138
                       ctx->error, ctx->error_depth,
 
1139
                        X509_verify_cert_error_string(ctx->error));
 
1140
                }
 
1141
        */
 
1142
 
 
1143
        return ok;
 
1144
        }