1/* crypto/ts/ts_conf.c */
2/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
3 * project 2002.
4 */
5/* ====================================================================
6 * Copyright (c) 2006 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 <string.h>
60
61#include <openssl/crypto.h>
62#include "cryptlib.h"
63#include <openssl/pem.h>
64#ifndef OPENSSL_NO_ENGINE
65#include <openssl/engine.h>
66#endif
67#include <openssl/ts.h>
68
69/* Macro definitions for the configuration file. */
70
71#define	BASE_SECTION			"tsa"
72#define	ENV_DEFAULT_TSA			"default_tsa"
73#define	ENV_SERIAL			"serial"
74#define ENV_CRYPTO_DEVICE		"crypto_device"
75#define	ENV_SIGNER_CERT			"signer_cert"
76#define	ENV_CERTS			"certs"
77#define	ENV_SIGNER_KEY			"signer_key"
78#define	ENV_DEFAULT_POLICY		"default_policy"
79#define	ENV_OTHER_POLICIES		"other_policies"
80#define	ENV_DIGESTS			"digests"
81#define	ENV_ACCURACY			"accuracy"
82#define	ENV_ORDERING			"ordering"
83#define	ENV_TSA_NAME			"tsa_name"
84#define	ENV_ESS_CERT_ID_CHAIN		"ess_cert_id_chain"
85#define	ENV_VALUE_SECS			"secs"
86#define	ENV_VALUE_MILLISECS		"millisecs"
87#define	ENV_VALUE_MICROSECS		"microsecs"
88#define	ENV_CLOCK_PRECISION_DIGITS	"clock_precision_digits"
89#define	ENV_VALUE_YES			"yes"
90#define	ENV_VALUE_NO			"no"
91
92/* Function definitions for certificate and key loading. */
93
94X509 *TS_CONF_load_cert(const char *file)
95	{
96	BIO *cert = NULL;
97	X509 *x = NULL;
98
99	if ((cert = BIO_new_file(file, "r")) == NULL) goto end;
100	x = PEM_read_bio_X509_AUX(cert, NULL, NULL, NULL);
101end:
102	if (x == NULL)
103		fprintf(stderr, "unable to load certificate: %s\n", file);
104	BIO_free(cert);
105	return x;
106	}
107
108STACK_OF(X509) *TS_CONF_load_certs(const char *file)
109	{
110	BIO *certs = NULL;
111	STACK_OF(X509) *othercerts = NULL;
112	STACK_OF(X509_INFO) *allcerts = NULL;
113	int i;
114
115	if (!(certs = BIO_new_file(file, "r"))) goto end;
116
117	if (!(othercerts = sk_X509_new_null())) goto end;
118	allcerts = PEM_X509_INFO_read_bio(certs, NULL, NULL, NULL);
119	for(i = 0; i < sk_X509_INFO_num(allcerts); i++)
120		{
121		X509_INFO *xi = sk_X509_INFO_value(allcerts, i);
122		if (xi->x509)
123			{
124			sk_X509_push(othercerts, xi->x509);
125			xi->x509 = NULL;
126			}
127		}
128end:
129	if (othercerts == NULL)
130		fprintf(stderr, "unable to load certificates: %s\n", file);
131	sk_X509_INFO_pop_free(allcerts, X509_INFO_free);
132	BIO_free(certs);
133	return othercerts;
134	}
135
136EVP_PKEY *TS_CONF_load_key(const char *file, const char *pass)
137	{
138	BIO *key = NULL;
139	EVP_PKEY *pkey = NULL;
140
141	if (!(key = BIO_new_file(file, "r"))) goto end;
142	pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, (char *) pass);
143 end:
144	if (pkey == NULL)
145		fprintf(stderr, "unable to load private key: %s\n", file);
146	BIO_free(key);
147	return pkey;
148	}
149
150/* Function definitions for handling configuration options. */
151
152static void TS_CONF_lookup_fail(const char *name, const char *tag)
153	{
154	fprintf(stderr, "variable lookup failed for %s::%s\n", name, tag);
155	}
156
157static void TS_CONF_invalid(const char *name, const char *tag)
158	{
159	fprintf(stderr, "invalid variable value for %s::%s\n", name, tag);
160	}
161
162const char *TS_CONF_get_tsa_section(CONF *conf, const char *section)
163	{
164	if (!section)
165		{
166		section = NCONF_get_string(conf, BASE_SECTION, ENV_DEFAULT_TSA);
167		if (!section)
168			TS_CONF_lookup_fail(BASE_SECTION, ENV_DEFAULT_TSA);
169		}
170	return section;
171	}
172
173int TS_CONF_set_serial(CONF *conf, const char *section, TS_serial_cb cb,
174		       TS_RESP_CTX *ctx)
175	{
176	int ret = 0;
177	char *serial = NCONF_get_string(conf, section, ENV_SERIAL);
178	if (!serial)
179		{
180		TS_CONF_lookup_fail(section, ENV_SERIAL);
181		goto err;
182		}
183	TS_RESP_CTX_set_serial_cb(ctx, cb, serial);
184
185	ret = 1;
186 err:
187	return ret;
188	}
189
190#ifndef OPENSSL_NO_ENGINE
191
192int TS_CONF_set_crypto_device(CONF *conf, const char *section,
193			      const char *device)
194	{
195	int ret = 0;
196
197	if (!device)
198		device = NCONF_get_string(conf, section,
199					  ENV_CRYPTO_DEVICE);
200
201	if (device && !TS_CONF_set_default_engine(device))
202		{
203		TS_CONF_invalid(section, ENV_CRYPTO_DEVICE);
204		goto err;
205		}
206	ret = 1;
207 err:
208	return ret;
209	}
210
211int TS_CONF_set_default_engine(const char *name)
212	{
213	ENGINE *e = NULL;
214	int ret = 0;
215
216	/* Leave the default if builtin specified. */
217	if (strcmp(name, "builtin") == 0) return 1;
218
219	if (!(e = ENGINE_by_id(name))) goto err;
220	/* Enable the use of the NCipher HSM for forked children. */
221	if (strcmp(name, "chil") == 0)
222		ENGINE_ctrl(e, ENGINE_CTRL_CHIL_SET_FORKCHECK, 1, 0, 0);
223	/* All the operations are going to be carried out by the engine. */
224	if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) goto err;
225	ret = 1;
226 err:
227	if (!ret)
228		{
229		TSerr(TS_F_TS_CONF_SET_DEFAULT_ENGINE,
230		      TS_R_COULD_NOT_SET_ENGINE);
231		ERR_add_error_data(2, "engine:", name);
232		}
233	if (e) ENGINE_free(e);
234	return ret;
235	}
236
237#endif
238
239int TS_CONF_set_signer_cert(CONF *conf, const char *section,
240			    const char *cert, TS_RESP_CTX *ctx)
241	{
242	int ret = 0;
243	X509 *cert_obj = NULL;
244	if (!cert)
245		cert = NCONF_get_string(conf, section, ENV_SIGNER_CERT);
246	if (!cert)
247		{
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) goto end;
271	if (!(certs_obj = TS_CONF_load_certs(certs))) goto err;
272	if (!TS_RESP_CTX_set_certs(ctx, certs_obj)) goto err;
273 end:
274	ret = 1;
275 err:
276	sk_X509_pop_free(certs_obj, X509_free);
277	return ret;
278	}
279
280int TS_CONF_set_signer_key(CONF *conf, const char *section,
281			   const char *key, const char *pass,
282			   TS_RESP_CTX *ctx)
283	{
284	int ret = 0;
285	EVP_PKEY *key_obj = NULL;
286	if (!key)
287		key = NCONF_get_string(conf, section, ENV_SIGNER_KEY);
288	if (!key)
289		{
290		TS_CONF_lookup_fail(section, ENV_SIGNER_KEY);
291		goto err;
292		}
293	if (!(key_obj = TS_CONF_load_key(key, pass))) goto err;
294	if (!TS_RESP_CTX_set_signer_key(ctx, key_obj)) goto err;
295
296	ret = 1;
297 err:
298	EVP_PKEY_free(key_obj);
299	return ret;
300	}
301
302int TS_CONF_set_def_policy(CONF *conf, const char *section,
303			   const char *policy, TS_RESP_CTX *ctx)
304	{
305	int ret = 0;
306	ASN1_OBJECT *policy_obj = NULL;
307	if (!policy)
308		policy = NCONF_get_string(conf, section,
309					  ENV_DEFAULT_POLICY);
310	if (!policy)
311		{
312		TS_CONF_lookup_fail(section, ENV_DEFAULT_POLICY);
313		goto err;
314		}
315	if (!(policy_obj = OBJ_txt2obj(policy, 0)))
316		{
317		TS_CONF_invalid(section, ENV_DEFAULT_POLICY);
318		goto err;
319		}
320	if (!TS_RESP_CTX_set_def_policy(ctx, policy_obj))
321		goto err;
322
323	ret = 1;
324 err:
325	ASN1_OBJECT_free(policy_obj);
326	return ret;
327	}
328
329int TS_CONF_set_policies(CONF *conf, const char *section,
330			 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		{
340		TS_CONF_invalid(section, ENV_OTHER_POLICIES);
341		goto err;
342		}
343	for (i = 0; i < sk_CONF_VALUE_num(list); ++i)
344		{
345		CONF_VALUE *val = sk_CONF_VALUE_value(list, i);
346		const char *extval = val->value ? val->value : val->name;
347		ASN1_OBJECT *objtmp;
348		if (!(objtmp = OBJ_txt2obj(extval, 0)))
349			{
350			TS_CONF_invalid(section, ENV_OTHER_POLICIES);
351			goto err;
352			}
353		if (!TS_RESP_CTX_add_policy(ctx, objtmp))
354			goto err;
355		ASN1_OBJECT_free(objtmp);
356		}
357
358	ret = 1;
359 err:
360	sk_CONF_VALUE_pop_free(list, X509V3_conf_free);
361	return ret;
362	}
363
364int TS_CONF_set_digests(CONF *conf, const char *section,
365			TS_RESP_CTX *ctx)
366	{
367	int ret = 0;
368	int i;
369	STACK_OF(CONF_VALUE) *list = NULL;
370	char *digests = NCONF_get_string(conf, section, ENV_DIGESTS);
371	if (!digests)
372		{
373		TS_CONF_lookup_fail(section, ENV_DIGESTS);
374		goto err;
375		}
376	if (!(list = X509V3_parse_list(digests)))
377		{
378		TS_CONF_invalid(section, ENV_DIGESTS);
379		goto err;
380		}
381	if (sk_CONF_VALUE_num(list) == 0)
382		{
383		TS_CONF_invalid(section, ENV_DIGESTS);
384		goto err;
385		}
386	for (i = 0; i < sk_CONF_VALUE_num(list); ++i)
387		{
388		CONF_VALUE *val = sk_CONF_VALUE_value(list, i);
389		const char *extval = val->value ? val->value : val->name;
390		const EVP_MD *md;
391		if (!(md = EVP_get_digestbyname(extval)))
392			{
393			TS_CONF_invalid(section, ENV_DIGESTS);
394			goto err;
395			}
396		if (!TS_RESP_CTX_add_md(ctx, md))
397			goto err;
398		}
399
400	ret = 1;
401 err:
402	sk_CONF_VALUE_pop_free(list, X509V3_conf_free);
403	return ret;
404	}
405
406int TS_CONF_set_accuracy(CONF *conf, const char *section, TS_RESP_CTX *ctx)
407	{
408	int ret = 0;
409	int i;
410	int secs = 0, millis = 0, micros = 0;
411	STACK_OF(CONF_VALUE) *list = NULL;
412	char *accuracy = NCONF_get_string(conf, section, ENV_ACCURACY);
413
414	if (accuracy && !(list = X509V3_parse_list(accuracy)))
415		{
416		TS_CONF_invalid(section, ENV_ACCURACY);
417		goto err;
418		}
419	for (i = 0; i < sk_CONF_VALUE_num(list); ++i)
420		{
421		CONF_VALUE *val = sk_CONF_VALUE_value(list, i);
422		if (strcmp(val->name, ENV_VALUE_SECS) == 0)
423			{
424			if (val->value) secs = atoi(val->value);
425			}
426		else if (strcmp(val->name, ENV_VALUE_MILLISECS) == 0)
427			{
428			if (val->value) millis = atoi(val->value);
429			}
430		else if (strcmp(val->name, ENV_VALUE_MICROSECS) == 0)
431			{
432			if (val->value) micros = atoi(val->value);
433			}
434		else
435			{
436			TS_CONF_invalid(section, ENV_ACCURACY);
437			goto err;
438			}
439		}
440	if (!TS_RESP_CTX_set_accuracy(ctx, secs, millis, micros))
441		goto err;
442
443	ret = 1;
444 err:
445	sk_CONF_VALUE_pop_free(list, X509V3_conf_free);
446	return ret;
447	}
448
449int TS_CONF_set_clock_precision_digits(CONF *conf, const char *section,
450				       TS_RESP_CTX *ctx)
451	{
452	int ret = 0;
453	long digits = 0;
454
455	/* If not specified, set the default value to 0, i.e. sec  precision */
456	if (!NCONF_get_number_e(conf, section, ENV_CLOCK_PRECISION_DIGITS,
457				&digits))
458		digits = 0;
459	if (digits < 0 || digits > TS_MAX_CLOCK_PRECISION_DIGITS)
460		{
461		TS_CONF_invalid(section, ENV_CLOCK_PRECISION_DIGITS);
462		goto err;
463		}
464
465	if (!TS_RESP_CTX_set_clock_precision_digits(ctx, digits))
466		goto err;
467
468	return 1;
469 err:
470	return ret;
471	}
472
473static int TS_CONF_add_flag(CONF *conf, const char *section, const char *field,
474			    int flag, TS_RESP_CTX *ctx)
475	{
476	/* Default is false. */
477	const char *value = NCONF_get_string(conf, section, field);
478	if (value)
479		{
480		if (strcmp(value, ENV_VALUE_YES) == 0)
481			TS_RESP_CTX_add_flags(ctx, flag);
482		else if (strcmp(value, ENV_VALUE_NO) != 0)
483			{
484			TS_CONF_invalid(section, field);
485			return 0;
486			}
487		}
488
489	return 1;
490	}
491
492int TS_CONF_set_ordering(CONF *conf, const char *section, TS_RESP_CTX *ctx)
493	{
494	return TS_CONF_add_flag(conf, section, ENV_ORDERING, TS_ORDERING, ctx);
495	}
496
497int TS_CONF_set_tsa_name(CONF *conf, const char *section, TS_RESP_CTX *ctx)
498	{
499	return TS_CONF_add_flag(conf, section, ENV_TSA_NAME, TS_TSA_NAME, ctx);
500	}
501
502int TS_CONF_set_ess_cert_id_chain(CONF *conf, const char *section,
503				  TS_RESP_CTX *ctx)
504	{
505	return TS_CONF_add_flag(conf, section, ENV_ESS_CERT_ID_CHAIN,
506				TS_ESS_CERT_ID_CHAIN, ctx);
507	}
508