source: rtems-libbsd/freebsd/crypto/openssl/apps/ts.c @ d1dac78

5
Last change on this file since d1dac78 was d1dac78, checked in by Christian Mauderer <christian.mauderer@…>, on 03/26/19 at 10:08:47

bin/openssl: Port to RTEMS.

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