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