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