ts_conf.c revision 280304
1/* crypto/ts/ts_conf.c */
2/*
3 * Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL project
4 * 2002.
5 */
6/* ====================================================================
7 * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in
18 *    the documentation and/or other materials provided with the
19 *    distribution.
20 *
21 * 3. All advertising materials mentioning features or use of this
22 *    software must display the following acknowledgment:
23 *    "This product includes software developed by the OpenSSL Project
24 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25 *
26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27 *    endorse or promote products derived from this software without
28 *    prior written permission. For written permission, please contact
29 *    licensing@OpenSSL.org.
30 *
31 * 5. Products derived from this software may not be called "OpenSSL"
32 *    nor may "OpenSSL" appear in their names without prior written
33 *    permission of the OpenSSL Project.
34 *
35 * 6. Redistributions of any form whatsoever must retain the following
36 *    acknowledgment:
37 *    "This product includes software developed by the OpenSSL Project
38 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 * OF THE POSSIBILITY OF SUCH DAMAGE.
52 * ====================================================================
53 *
54 * This product includes cryptographic software written by Eric Young
55 * (eay@cryptsoft.com).  This product includes software written by Tim
56 * Hudson (tjh@cryptsoft.com).
57 *
58 */
59
60#include <string.h>
61
62#include <openssl/crypto.h>
63#include "cryptlib.h"
64#include <openssl/pem.h>
65#ifndef OPENSSL_NO_ENGINE
66# include <openssl/engine.h>
67#endif
68#include <openssl/ts.h>
69
70/* Macro definitions for the configuration file. */
71
72#define BASE_SECTION                    "tsa"
73#define ENV_DEFAULT_TSA                 "default_tsa"
74#define ENV_SERIAL                      "serial"
75#define ENV_CRYPTO_DEVICE               "crypto_device"
76#define ENV_SIGNER_CERT                 "signer_cert"
77#define ENV_CERTS                       "certs"
78#define ENV_SIGNER_KEY                  "signer_key"
79#define ENV_DEFAULT_POLICY              "default_policy"
80#define ENV_OTHER_POLICIES              "other_policies"
81#define ENV_DIGESTS                     "digests"
82#define ENV_ACCURACY                    "accuracy"
83#define ENV_ORDERING                    "ordering"
84#define ENV_TSA_NAME                    "tsa_name"
85#define ENV_ESS_CERT_ID_CHAIN           "ess_cert_id_chain"
86#define ENV_VALUE_SECS                  "secs"
87#define ENV_VALUE_MILLISECS             "millisecs"
88#define ENV_VALUE_MICROSECS             "microsecs"
89#define ENV_CLOCK_PRECISION_DIGITS      "clock_precision_digits"
90#define ENV_VALUE_YES                   "yes"
91#define ENV_VALUE_NO                    "no"
92
93/* Function definitions for certificate and key loading. */
94
95X509 *TS_CONF_load_cert(const char *file)
96{
97    BIO *cert = NULL;
98    X509 *x = NULL;
99
100    if ((cert = BIO_new_file(file, "r")) == NULL)
101        goto end;
102    x = PEM_read_bio_X509_AUX(cert, NULL, NULL, NULL);
103 end:
104    if (x == NULL)
105        fprintf(stderr, "unable to load certificate: %s\n", file);
106    BIO_free(cert);
107    return x;
108}
109
110STACK_OF(X509) *TS_CONF_load_certs(const char *file)
111{
112    BIO *certs = NULL;
113    STACK_OF(X509) *othercerts = NULL;
114    STACK_OF(X509_INFO) *allcerts = NULL;
115    int i;
116
117    if (!(certs = BIO_new_file(file, "r")))
118        goto end;
119
120    if (!(othercerts = sk_X509_new_null()))
121        goto end;
122    allcerts = PEM_X509_INFO_read_bio(certs, NULL, NULL, NULL);
123    for (i = 0; i < sk_X509_INFO_num(allcerts); i++) {
124        X509_INFO *xi = sk_X509_INFO_value(allcerts, i);
125        if (xi->x509) {
126            sk_X509_push(othercerts, xi->x509);
127            xi->x509 = NULL;
128        }
129    }
130 end:
131    if (othercerts == NULL)
132        fprintf(stderr, "unable to load certificates: %s\n", file);
133    sk_X509_INFO_pop_free(allcerts, X509_INFO_free);
134    BIO_free(certs);
135    return othercerts;
136}
137
138EVP_PKEY *TS_CONF_load_key(const char *file, const char *pass)
139{
140    BIO *key = NULL;
141    EVP_PKEY *pkey = NULL;
142
143    if (!(key = BIO_new_file(file, "r")))
144        goto end;
145    pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, (char *)pass);
146 end:
147    if (pkey == NULL)
148        fprintf(stderr, "unable to load private key: %s\n", file);
149    BIO_free(key);
150    return pkey;
151}
152
153/* Function definitions for handling configuration options. */
154
155static void TS_CONF_lookup_fail(const char *name, const char *tag)
156{
157    fprintf(stderr, "variable lookup failed for %s::%s\n", name, tag);
158}
159
160static void TS_CONF_invalid(const char *name, const char *tag)
161{
162    fprintf(stderr, "invalid variable value for %s::%s\n", name, tag);
163}
164
165const char *TS_CONF_get_tsa_section(CONF *conf, const char *section)
166{
167    if (!section) {
168        section = NCONF_get_string(conf, BASE_SECTION, ENV_DEFAULT_TSA);
169        if (!section)
170            TS_CONF_lookup_fail(BASE_SECTION, ENV_DEFAULT_TSA);
171    }
172    return section;
173}
174
175int TS_CONF_set_serial(CONF *conf, const char *section, TS_serial_cb cb,
176                       TS_RESP_CTX *ctx)
177{
178    int ret = 0;
179    char *serial = NCONF_get_string(conf, section, ENV_SERIAL);
180    if (!serial) {
181        TS_CONF_lookup_fail(section, ENV_SERIAL);
182        goto err;
183    }
184    TS_RESP_CTX_set_serial_cb(ctx, cb, serial);
185
186    ret = 1;
187 err:
188    return ret;
189}
190
191#ifndef OPENSSL_NO_ENGINE
192
193int TS_CONF_set_crypto_device(CONF *conf, const char *section,
194                              const char *device)
195{
196    int ret = 0;
197
198    if (!device)
199        device = NCONF_get_string(conf, section, ENV_CRYPTO_DEVICE);
200
201    if (device && !TS_CONF_set_default_engine(device)) {
202        TS_CONF_invalid(section, ENV_CRYPTO_DEVICE);
203        goto err;
204    }
205    ret = 1;
206 err:
207    return ret;
208}
209
210int TS_CONF_set_default_engine(const char *name)
211{
212    ENGINE *e = NULL;
213    int ret = 0;
214
215    /* Leave the default if builtin specified. */
216    if (strcmp(name, "builtin") == 0)
217        return 1;
218
219    if (!(e = ENGINE_by_id(name)))
220        goto err;
221    /* Enable the use of the NCipher HSM for forked children. */
222    if (strcmp(name, "chil") == 0)
223        ENGINE_ctrl(e, ENGINE_CTRL_CHIL_SET_FORKCHECK, 1, 0, 0);
224    /* All the operations are going to be carried out by the engine. */
225    if (!ENGINE_set_default(e, ENGINE_METHOD_ALL))
226        goto err;
227    ret = 1;
228 err:
229    if (!ret) {
230        TSerr(TS_F_TS_CONF_SET_DEFAULT_ENGINE, TS_R_COULD_NOT_SET_ENGINE);
231        ERR_add_error_data(2, "engine:", name);
232    }
233    if (e)
234        ENGINE_free(e);
235    return ret;
236}
237
238#endif
239
240int TS_CONF_set_signer_cert(CONF *conf, const char *section,
241                            const char *cert, TS_RESP_CTX *ctx)
242{
243    int ret = 0;
244    X509 *cert_obj = NULL;
245    if (!cert)
246        cert = NCONF_get_string(conf, section, ENV_SIGNER_CERT);
247    if (!cert) {
248        TS_CONF_lookup_fail(section, ENV_SIGNER_CERT);
249        goto err;
250    }
251    if (!(cert_obj = TS_CONF_load_cert(cert)))
252        goto err;
253    if (!TS_RESP_CTX_set_signer_cert(ctx, cert_obj))
254        goto err;
255
256    ret = 1;
257 err:
258    X509_free(cert_obj);
259    return ret;
260}
261
262int TS_CONF_set_certs(CONF *conf, const char *section, const char *certs,
263                      TS_RESP_CTX *ctx)
264{
265    int ret = 0;
266    STACK_OF(X509) *certs_obj = NULL;
267    if (!certs)
268        certs = NCONF_get_string(conf, section, ENV_CERTS);
269    /* Certificate chain is optional. */
270    if (!certs)
271        goto end;
272    if (!(certs_obj = TS_CONF_load_certs(certs)))
273        goto err;
274    if (!TS_RESP_CTX_set_certs(ctx, certs_obj))
275        goto err;
276 end:
277    ret = 1;
278 err:
279    sk_X509_pop_free(certs_obj, X509_free);
280    return ret;
281}
282
283int TS_CONF_set_signer_key(CONF *conf, const char *section,
284                           const char *key, const char *pass,
285                           TS_RESP_CTX *ctx)
286{
287    int ret = 0;
288    EVP_PKEY *key_obj = NULL;
289    if (!key)
290        key = NCONF_get_string(conf, section, ENV_SIGNER_KEY);
291    if (!key) {
292        TS_CONF_lookup_fail(section, ENV_SIGNER_KEY);
293        goto err;
294    }
295    if (!(key_obj = TS_CONF_load_key(key, pass)))
296        goto err;
297    if (!TS_RESP_CTX_set_signer_key(ctx, key_obj))
298        goto err;
299
300    ret = 1;
301 err:
302    EVP_PKEY_free(key_obj);
303    return ret;
304}
305
306int TS_CONF_set_def_policy(CONF *conf, const char *section,
307                           const char *policy, TS_RESP_CTX *ctx)
308{
309    int ret = 0;
310    ASN1_OBJECT *policy_obj = NULL;
311    if (!policy)
312        policy = NCONF_get_string(conf, section, ENV_DEFAULT_POLICY);
313    if (!policy) {
314        TS_CONF_lookup_fail(section, ENV_DEFAULT_POLICY);
315        goto err;
316    }
317    if (!(policy_obj = OBJ_txt2obj(policy, 0))) {
318        TS_CONF_invalid(section, ENV_DEFAULT_POLICY);
319        goto err;
320    }
321    if (!TS_RESP_CTX_set_def_policy(ctx, policy_obj))
322        goto err;
323
324    ret = 1;
325 err:
326    ASN1_OBJECT_free(policy_obj);
327    return ret;
328}
329
330int TS_CONF_set_policies(CONF *conf, const char *section, TS_RESP_CTX *ctx)
331{
332    int ret = 0;
333    int i;
334    STACK_OF(CONF_VALUE) *list = NULL;
335    char *policies = NCONF_get_string(conf, section,
336                                      ENV_OTHER_POLICIES);
337    /* If no other policy is specified, that's fine. */
338    if (policies && !(list = X509V3_parse_list(policies))) {
339        TS_CONF_invalid(section, ENV_OTHER_POLICIES);
340        goto err;
341    }
342    for (i = 0; i < sk_CONF_VALUE_num(list); ++i) {
343        CONF_VALUE *val = sk_CONF_VALUE_value(list, i);
344        const char *extval = val->value ? val->value : val->name;
345        ASN1_OBJECT *objtmp;
346        if (!(objtmp = OBJ_txt2obj(extval, 0))) {
347            TS_CONF_invalid(section, ENV_OTHER_POLICIES);
348            goto err;
349        }
350        if (!TS_RESP_CTX_add_policy(ctx, objtmp))
351            goto err;
352        ASN1_OBJECT_free(objtmp);
353    }
354
355    ret = 1;
356 err:
357    sk_CONF_VALUE_pop_free(list, X509V3_conf_free);
358    return ret;
359}
360
361int TS_CONF_set_digests(CONF *conf, const char *section, TS_RESP_CTX *ctx)
362{
363    int ret = 0;
364    int i;
365    STACK_OF(CONF_VALUE) *list = NULL;
366    char *digests = NCONF_get_string(conf, section, ENV_DIGESTS);
367    if (!digests) {
368        TS_CONF_lookup_fail(section, ENV_DIGESTS);
369        goto err;
370    }
371    if (!(list = X509V3_parse_list(digests))) {
372        TS_CONF_invalid(section, ENV_DIGESTS);
373        goto err;
374    }
375    if (sk_CONF_VALUE_num(list) == 0) {
376        TS_CONF_invalid(section, ENV_DIGESTS);
377        goto err;
378    }
379    for (i = 0; i < sk_CONF_VALUE_num(list); ++i) {
380        CONF_VALUE *val = sk_CONF_VALUE_value(list, i);
381        const char *extval = val->value ? val->value : val->name;
382        const EVP_MD *md;
383        if (!(md = EVP_get_digestbyname(extval))) {
384            TS_CONF_invalid(section, ENV_DIGESTS);
385            goto err;
386        }
387        if (!TS_RESP_CTX_add_md(ctx, md))
388            goto err;
389    }
390
391    ret = 1;
392 err:
393    sk_CONF_VALUE_pop_free(list, X509V3_conf_free);
394    return ret;
395}
396
397int TS_CONF_set_accuracy(CONF *conf, const char *section, TS_RESP_CTX *ctx)
398{
399    int ret = 0;
400    int i;
401    int secs = 0, millis = 0, micros = 0;
402    STACK_OF(CONF_VALUE) *list = NULL;
403    char *accuracy = NCONF_get_string(conf, section, ENV_ACCURACY);
404
405    if (accuracy && !(list = X509V3_parse_list(accuracy))) {
406        TS_CONF_invalid(section, ENV_ACCURACY);
407        goto err;
408    }
409    for (i = 0; i < sk_CONF_VALUE_num(list); ++i) {
410        CONF_VALUE *val = sk_CONF_VALUE_value(list, i);
411        if (strcmp(val->name, ENV_VALUE_SECS) == 0) {
412            if (val->value)
413                secs = atoi(val->value);
414        } else if (strcmp(val->name, ENV_VALUE_MILLISECS) == 0) {
415            if (val->value)
416                millis = atoi(val->value);
417        } else if (strcmp(val->name, ENV_VALUE_MICROSECS) == 0) {
418            if (val->value)
419                micros = atoi(val->value);
420        } else {
421            TS_CONF_invalid(section, ENV_ACCURACY);
422            goto err;
423        }
424    }
425    if (!TS_RESP_CTX_set_accuracy(ctx, secs, millis, micros))
426        goto err;
427
428    ret = 1;
429 err:
430    sk_CONF_VALUE_pop_free(list, X509V3_conf_free);
431    return ret;
432}
433
434int TS_CONF_set_clock_precision_digits(CONF *conf, const char *section,
435                                       TS_RESP_CTX *ctx)
436{
437    int ret = 0;
438    long digits = 0;
439
440    /*
441     * If not specified, set the default value to 0, i.e. sec precision
442     */
443    if (!NCONF_get_number_e(conf, section, ENV_CLOCK_PRECISION_DIGITS,
444                            &digits))
445        digits = 0;
446    if (digits < 0 || digits > TS_MAX_CLOCK_PRECISION_DIGITS) {
447        TS_CONF_invalid(section, ENV_CLOCK_PRECISION_DIGITS);
448        goto err;
449    }
450
451    if (!TS_RESP_CTX_set_clock_precision_digits(ctx, digits))
452        goto err;
453
454    return 1;
455 err:
456    return ret;
457}
458
459static int TS_CONF_add_flag(CONF *conf, const char *section,
460                            const char *field, int flag, TS_RESP_CTX *ctx)
461{
462    /* Default is false. */
463    const char *value = NCONF_get_string(conf, section, field);
464    if (value) {
465        if (strcmp(value, ENV_VALUE_YES) == 0)
466            TS_RESP_CTX_add_flags(ctx, flag);
467        else if (strcmp(value, ENV_VALUE_NO) != 0) {
468            TS_CONF_invalid(section, field);
469            return 0;
470        }
471    }
472
473    return 1;
474}
475
476int TS_CONF_set_ordering(CONF *conf, const char *section, TS_RESP_CTX *ctx)
477{
478    return TS_CONF_add_flag(conf, section, ENV_ORDERING, TS_ORDERING, ctx);
479}
480
481int TS_CONF_set_tsa_name(CONF *conf, const char *section, TS_RESP_CTX *ctx)
482{
483    return TS_CONF_add_flag(conf, section, ENV_TSA_NAME, TS_TSA_NAME, ctx);
484}
485
486int TS_CONF_set_ess_cert_id_chain(CONF *conf, const char *section,
487                                  TS_RESP_CTX *ctx)
488{
489    return TS_CONF_add_flag(conf, section, ENV_ESS_CERT_ID_CHAIN,
490                            TS_ESS_CERT_ID_CHAIN, ctx);
491}
492