diff options
Diffstat (limited to 'src/lib/libtls/tls_config.c')
| -rw-r--r-- | src/lib/libtls/tls_config.c | 954 |
1 files changed, 0 insertions, 954 deletions
diff --git a/src/lib/libtls/tls_config.c b/src/lib/libtls/tls_config.c deleted file mode 100644 index 22fa8455a1..0000000000 --- a/src/lib/libtls/tls_config.c +++ /dev/null | |||
| @@ -1,954 +0,0 @@ | |||
| 1 | /* $OpenBSD: tls_config.c,v 1.71 2024/08/02 15:00:01 tb Exp $ */ | ||
| 2 | /* | ||
| 3 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> | ||
| 4 | * | ||
| 5 | * Permission to use, copy, modify, and distribute this software for any | ||
| 6 | * purpose with or without fee is hereby granted, provided that the above | ||
| 7 | * copyright notice and this permission notice appear in all copies. | ||
| 8 | * | ||
| 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <sys/stat.h> | ||
| 19 | |||
| 20 | #include <ctype.h> | ||
| 21 | #include <errno.h> | ||
| 22 | #include <fcntl.h> | ||
| 23 | #include <pthread.h> | ||
| 24 | #include <stdlib.h> | ||
| 25 | #include <string.h> | ||
| 26 | #include <unistd.h> | ||
| 27 | |||
| 28 | #include <tls.h> | ||
| 29 | |||
| 30 | #include "tls_internal.h" | ||
| 31 | |||
| 32 | static const char default_ca_file[] = TLS_DEFAULT_CA_FILE; | ||
| 33 | |||
| 34 | const char * | ||
| 35 | tls_default_ca_cert_file(void) | ||
| 36 | { | ||
| 37 | return default_ca_file; | ||
| 38 | } | ||
| 39 | |||
| 40 | int | ||
| 41 | tls_config_load_file(struct tls_error *error, const char *filetype, | ||
| 42 | const char *filename, char **buf, size_t *len) | ||
| 43 | { | ||
| 44 | struct stat st; | ||
| 45 | int fd = -1; | ||
| 46 | ssize_t n; | ||
| 47 | |||
| 48 | free(*buf); | ||
| 49 | *buf = NULL; | ||
| 50 | *len = 0; | ||
| 51 | |||
| 52 | if ((fd = open(filename, O_RDONLY)) == -1) { | ||
| 53 | tls_error_set(error, TLS_ERROR_UNKNOWN, | ||
| 54 | "failed to open %s file '%s'", | ||
| 55 | filetype, filename); | ||
| 56 | goto err; | ||
| 57 | } | ||
| 58 | if (fstat(fd, &st) != 0) { | ||
| 59 | tls_error_set(error, TLS_ERROR_UNKNOWN, | ||
| 60 | "failed to stat %s file '%s'", | ||
| 61 | filetype, filename); | ||
| 62 | goto err; | ||
| 63 | } | ||
| 64 | if (st.st_size < 0) | ||
| 65 | goto err; | ||
| 66 | *len = (size_t)st.st_size; | ||
| 67 | if ((*buf = malloc(*len)) == NULL) { | ||
| 68 | tls_error_set(error, TLS_ERROR_UNKNOWN, | ||
| 69 | "failed to allocate buffer for %s file", | ||
| 70 | filetype); | ||
| 71 | goto err; | ||
| 72 | } | ||
| 73 | n = read(fd, *buf, *len); | ||
| 74 | if (n < 0 || (size_t)n != *len) { | ||
| 75 | tls_error_set(error, TLS_ERROR_UNKNOWN, | ||
| 76 | "failed to read %s file '%s'", | ||
| 77 | filetype, filename); | ||
| 78 | goto err; | ||
| 79 | } | ||
| 80 | close(fd); | ||
| 81 | return 0; | ||
| 82 | |||
| 83 | err: | ||
| 84 | if (fd != -1) | ||
| 85 | close(fd); | ||
| 86 | freezero(*buf, *len); | ||
| 87 | *buf = NULL; | ||
| 88 | *len = 0; | ||
| 89 | |||
| 90 | return -1; | ||
| 91 | } | ||
| 92 | |||
| 93 | struct tls_config * | ||
| 94 | tls_config_new_internal(void) | ||
| 95 | { | ||
| 96 | struct tls_config *config; | ||
| 97 | unsigned char sid[TLS_MAX_SESSION_ID_LENGTH]; | ||
| 98 | |||
| 99 | if ((config = calloc(1, sizeof(*config))) == NULL) | ||
| 100 | return (NULL); | ||
| 101 | |||
| 102 | if (pthread_mutex_init(&config->mutex, NULL) != 0) | ||
| 103 | goto err; | ||
| 104 | |||
| 105 | config->refcount = 1; | ||
| 106 | config->session_fd = -1; | ||
| 107 | |||
| 108 | if ((config->keypair = tls_keypair_new()) == NULL) | ||
| 109 | goto err; | ||
| 110 | |||
| 111 | /* | ||
| 112 | * Default configuration. | ||
| 113 | */ | ||
| 114 | if (tls_config_set_dheparams(config, "none") != 0) | ||
| 115 | goto err; | ||
| 116 | if (tls_config_set_ecdhecurves(config, "default") != 0) | ||
| 117 | goto err; | ||
| 118 | if (tls_config_set_ciphers(config, "secure") != 0) | ||
| 119 | goto err; | ||
| 120 | |||
| 121 | if (tls_config_set_protocols(config, TLS_PROTOCOLS_DEFAULT) != 0) | ||
| 122 | goto err; | ||
| 123 | if (tls_config_set_verify_depth(config, 6) != 0) | ||
| 124 | goto err; | ||
| 125 | |||
| 126 | /* | ||
| 127 | * Set session ID context to a random value. For the simple case | ||
| 128 | * of a single process server this is good enough. For multiprocess | ||
| 129 | * servers the session ID needs to be set by the caller. | ||
| 130 | */ | ||
| 131 | arc4random_buf(sid, sizeof(sid)); | ||
| 132 | if (tls_config_set_session_id(config, sid, sizeof(sid)) != 0) | ||
| 133 | goto err; | ||
| 134 | config->ticket_keyrev = arc4random(); | ||
| 135 | config->ticket_autorekey = 1; | ||
| 136 | |||
| 137 | tls_config_prefer_ciphers_server(config); | ||
| 138 | |||
| 139 | tls_config_verify(config); | ||
| 140 | |||
| 141 | return (config); | ||
| 142 | |||
| 143 | err: | ||
| 144 | tls_config_free(config); | ||
| 145 | return (NULL); | ||
| 146 | } | ||
| 147 | |||
| 148 | struct tls_config * | ||
| 149 | tls_config_new(void) | ||
| 150 | { | ||
| 151 | if (tls_init() == -1) | ||
| 152 | return (NULL); | ||
| 153 | |||
| 154 | return tls_config_new_internal(); | ||
| 155 | } | ||
| 156 | |||
| 157 | void | ||
| 158 | tls_config_free(struct tls_config *config) | ||
| 159 | { | ||
| 160 | struct tls_keypair *kp, *nkp; | ||
| 161 | int refcount; | ||
| 162 | |||
| 163 | if (config == NULL) | ||
| 164 | return; | ||
| 165 | |||
| 166 | pthread_mutex_lock(&config->mutex); | ||
| 167 | refcount = --config->refcount; | ||
| 168 | pthread_mutex_unlock(&config->mutex); | ||
| 169 | |||
| 170 | if (refcount > 0) | ||
| 171 | return; | ||
| 172 | |||
| 173 | for (kp = config->keypair; kp != NULL; kp = nkp) { | ||
| 174 | nkp = kp->next; | ||
| 175 | tls_keypair_free(kp); | ||
| 176 | } | ||
| 177 | |||
| 178 | free(config->error.msg); | ||
| 179 | |||
| 180 | free(config->alpn); | ||
| 181 | free((char *)config->ca_mem); | ||
| 182 | free((char *)config->ca_path); | ||
| 183 | free((char *)config->ciphers); | ||
| 184 | free((char *)config->crl_mem); | ||
| 185 | free(config->ecdhecurves); | ||
| 186 | |||
| 187 | pthread_mutex_destroy(&config->mutex); | ||
| 188 | |||
| 189 | free(config); | ||
| 190 | } | ||
| 191 | |||
| 192 | static void | ||
| 193 | tls_config_keypair_add(struct tls_config *config, struct tls_keypair *keypair) | ||
| 194 | { | ||
| 195 | struct tls_keypair *kp; | ||
| 196 | |||
| 197 | kp = config->keypair; | ||
| 198 | while (kp->next != NULL) | ||
| 199 | kp = kp->next; | ||
| 200 | |||
| 201 | kp->next = keypair; | ||
| 202 | } | ||
| 203 | |||
| 204 | const char * | ||
| 205 | tls_config_error(struct tls_config *config) | ||
| 206 | { | ||
| 207 | return config->error.msg; | ||
| 208 | } | ||
| 209 | |||
| 210 | int | ||
| 211 | tls_config_error_code(struct tls_config *config) | ||
| 212 | { | ||
| 213 | return config->error.code; | ||
| 214 | } | ||
| 215 | |||
| 216 | void | ||
| 217 | tls_config_clear_keys(struct tls_config *config) | ||
| 218 | { | ||
| 219 | struct tls_keypair *kp; | ||
| 220 | |||
| 221 | for (kp = config->keypair; kp != NULL; kp = kp->next) | ||
| 222 | tls_keypair_clear_key(kp); | ||
| 223 | } | ||
| 224 | |||
| 225 | int | ||
| 226 | tls_config_parse_protocols(uint32_t *protocols, const char *protostr) | ||
| 227 | { | ||
| 228 | uint32_t proto, protos = 0; | ||
| 229 | char *s, *p, *q; | ||
| 230 | int negate; | ||
| 231 | |||
| 232 | if (protostr == NULL) { | ||
| 233 | *protocols = TLS_PROTOCOLS_DEFAULT; | ||
| 234 | return (0); | ||
| 235 | } | ||
| 236 | |||
| 237 | if ((s = strdup(protostr)) == NULL) | ||
| 238 | return (-1); | ||
| 239 | |||
| 240 | q = s; | ||
| 241 | while ((p = strsep(&q, ",:")) != NULL) { | ||
| 242 | while (*p == ' ' || *p == '\t') | ||
| 243 | p++; | ||
| 244 | |||
| 245 | negate = 0; | ||
| 246 | if (*p == '!') { | ||
| 247 | negate = 1; | ||
| 248 | p++; | ||
| 249 | } | ||
| 250 | |||
| 251 | if (negate && protos == 0) | ||
| 252 | protos = TLS_PROTOCOLS_ALL; | ||
| 253 | |||
| 254 | proto = 0; | ||
| 255 | if (strcasecmp(p, "all") == 0 || | ||
| 256 | strcasecmp(p, "legacy") == 0) | ||
| 257 | proto = TLS_PROTOCOLS_ALL; | ||
| 258 | else if (strcasecmp(p, "default") == 0 || | ||
| 259 | strcasecmp(p, "secure") == 0) | ||
| 260 | proto = TLS_PROTOCOLS_DEFAULT; | ||
| 261 | if (strcasecmp(p, "tlsv1") == 0) | ||
| 262 | proto = TLS_PROTOCOL_TLSv1; | ||
| 263 | else if (strcasecmp(p, "tlsv1.0") == 0) | ||
| 264 | proto = TLS_PROTOCOL_TLSv1_0; | ||
| 265 | else if (strcasecmp(p, "tlsv1.1") == 0) | ||
| 266 | proto = TLS_PROTOCOL_TLSv1_1; | ||
| 267 | else if (strcasecmp(p, "tlsv1.2") == 0) | ||
| 268 | proto = TLS_PROTOCOL_TLSv1_2; | ||
| 269 | else if (strcasecmp(p, "tlsv1.3") == 0) | ||
| 270 | proto = TLS_PROTOCOL_TLSv1_3; | ||
| 271 | |||
| 272 | if (proto == 0) { | ||
| 273 | free(s); | ||
| 274 | return (-1); | ||
| 275 | } | ||
| 276 | |||
| 277 | if (negate) | ||
| 278 | protos &= ~proto; | ||
| 279 | else | ||
| 280 | protos |= proto; | ||
| 281 | } | ||
| 282 | |||
| 283 | *protocols = protos; | ||
| 284 | |||
| 285 | free(s); | ||
| 286 | |||
| 287 | return (0); | ||
| 288 | } | ||
| 289 | |||
| 290 | static int | ||
| 291 | tls_config_parse_alpn(struct tls_config *config, const char *alpn, | ||
| 292 | char **alpn_data, size_t *alpn_len) | ||
| 293 | { | ||
| 294 | size_t buf_len, i, len; | ||
| 295 | char *buf = NULL; | ||
| 296 | char *s = NULL; | ||
| 297 | char *p, *q; | ||
| 298 | |||
| 299 | free(*alpn_data); | ||
| 300 | *alpn_data = NULL; | ||
| 301 | *alpn_len = 0; | ||
| 302 | |||
| 303 | if ((buf_len = strlen(alpn) + 1) > 65535) { | ||
| 304 | tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT, | ||
| 305 | "alpn too large"); | ||
| 306 | goto err; | ||
| 307 | } | ||
| 308 | |||
| 309 | if ((buf = malloc(buf_len)) == NULL) { | ||
| 310 | tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY, | ||
| 311 | "out of memory"); | ||
| 312 | goto err; | ||
| 313 | } | ||
| 314 | |||
| 315 | if ((s = strdup(alpn)) == NULL) { | ||
| 316 | tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY, | ||
| 317 | "out of memory"); | ||
| 318 | goto err; | ||
| 319 | } | ||
| 320 | |||
| 321 | i = 0; | ||
| 322 | q = s; | ||
| 323 | while ((p = strsep(&q, ",")) != NULL) { | ||
| 324 | if ((len = strlen(p)) == 0) { | ||
| 325 | tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT, | ||
| 326 | "alpn protocol with zero length"); | ||
| 327 | goto err; | ||
| 328 | } | ||
| 329 | if (len > 255) { | ||
| 330 | tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT, | ||
| 331 | "alpn protocol too long"); | ||
| 332 | goto err; | ||
| 333 | } | ||
| 334 | buf[i++] = len & 0xff; | ||
| 335 | memcpy(&buf[i], p, len); | ||
| 336 | i += len; | ||
| 337 | } | ||
| 338 | |||
| 339 | free(s); | ||
| 340 | |||
| 341 | *alpn_data = buf; | ||
| 342 | *alpn_len = buf_len; | ||
| 343 | |||
| 344 | return (0); | ||
| 345 | |||
| 346 | err: | ||
| 347 | free(buf); | ||
| 348 | free(s); | ||
| 349 | |||
| 350 | return (-1); | ||
| 351 | } | ||
| 352 | |||
| 353 | int | ||
| 354 | tls_config_set_alpn(struct tls_config *config, const char *alpn) | ||
| 355 | { | ||
| 356 | return tls_config_parse_alpn(config, alpn, &config->alpn, | ||
| 357 | &config->alpn_len); | ||
| 358 | } | ||
| 359 | |||
| 360 | static int | ||
| 361 | tls_config_add_keypair_file_internal(struct tls_config *config, | ||
| 362 | const char *cert_file, const char *key_file, const char *ocsp_file) | ||
| 363 | { | ||
| 364 | struct tls_keypair *keypair; | ||
| 365 | |||
| 366 | if ((keypair = tls_keypair_new()) == NULL) | ||
| 367 | return (-1); | ||
| 368 | if (tls_keypair_set_cert_file(keypair, &config->error, cert_file) != 0) | ||
| 369 | goto err; | ||
| 370 | if (key_file != NULL && | ||
| 371 | tls_keypair_set_key_file(keypair, &config->error, key_file) != 0) | ||
| 372 | goto err; | ||
| 373 | if (ocsp_file != NULL && | ||
| 374 | tls_keypair_set_ocsp_staple_file(keypair, &config->error, | ||
| 375 | ocsp_file) != 0) | ||
| 376 | goto err; | ||
| 377 | |||
| 378 | tls_config_keypair_add(config, keypair); | ||
| 379 | |||
| 380 | return (0); | ||
| 381 | |||
| 382 | err: | ||
| 383 | tls_keypair_free(keypair); | ||
| 384 | return (-1); | ||
| 385 | } | ||
| 386 | |||
| 387 | static int | ||
| 388 | tls_config_add_keypair_mem_internal(struct tls_config *config, const uint8_t *cert, | ||
| 389 | size_t cert_len, const uint8_t *key, size_t key_len, | ||
| 390 | const uint8_t *staple, size_t staple_len) | ||
| 391 | { | ||
| 392 | struct tls_keypair *keypair; | ||
| 393 | |||
| 394 | if ((keypair = tls_keypair_new()) == NULL) | ||
| 395 | return (-1); | ||
| 396 | if (tls_keypair_set_cert_mem(keypair, &config->error, cert, cert_len) != 0) | ||
| 397 | goto err; | ||
| 398 | if (key != NULL && | ||
| 399 | tls_keypair_set_key_mem(keypair, &config->error, key, key_len) != 0) | ||
| 400 | goto err; | ||
| 401 | if (staple != NULL && | ||
| 402 | tls_keypair_set_ocsp_staple_mem(keypair, &config->error, staple, | ||
| 403 | staple_len) != 0) | ||
| 404 | goto err; | ||
| 405 | |||
| 406 | tls_config_keypair_add(config, keypair); | ||
| 407 | |||
| 408 | return (0); | ||
| 409 | |||
| 410 | err: | ||
| 411 | tls_keypair_free(keypair); | ||
| 412 | return (-1); | ||
| 413 | } | ||
| 414 | |||
| 415 | int | ||
| 416 | tls_config_add_keypair_mem(struct tls_config *config, const uint8_t *cert, | ||
| 417 | size_t cert_len, const uint8_t *key, size_t key_len) | ||
| 418 | { | ||
| 419 | return tls_config_add_keypair_mem_internal(config, cert, cert_len, key, | ||
| 420 | key_len, NULL, 0); | ||
| 421 | } | ||
| 422 | |||
| 423 | int | ||
| 424 | tls_config_add_keypair_file(struct tls_config *config, | ||
| 425 | const char *cert_file, const char *key_file) | ||
| 426 | { | ||
| 427 | return tls_config_add_keypair_file_internal(config, cert_file, | ||
| 428 | key_file, NULL); | ||
| 429 | } | ||
| 430 | |||
| 431 | int | ||
| 432 | tls_config_add_keypair_ocsp_mem(struct tls_config *config, const uint8_t *cert, | ||
| 433 | size_t cert_len, const uint8_t *key, size_t key_len, const uint8_t *staple, | ||
| 434 | size_t staple_len) | ||
| 435 | { | ||
| 436 | return tls_config_add_keypair_mem_internal(config, cert, cert_len, key, | ||
| 437 | key_len, staple, staple_len); | ||
| 438 | } | ||
| 439 | |||
| 440 | int | ||
| 441 | tls_config_add_keypair_ocsp_file(struct tls_config *config, | ||
| 442 | const char *cert_file, const char *key_file, const char *ocsp_file) | ||
| 443 | { | ||
| 444 | return tls_config_add_keypair_file_internal(config, cert_file, | ||
| 445 | key_file, ocsp_file); | ||
| 446 | } | ||
| 447 | |||
| 448 | int | ||
| 449 | tls_config_set_ca_file(struct tls_config *config, const char *ca_file) | ||
| 450 | { | ||
| 451 | return tls_config_load_file(&config->error, "CA", ca_file, | ||
| 452 | &config->ca_mem, &config->ca_len); | ||
| 453 | } | ||
| 454 | |||
| 455 | int | ||
| 456 | tls_config_set_ca_path(struct tls_config *config, const char *ca_path) | ||
| 457 | { | ||
| 458 | return tls_set_string(&config->ca_path, ca_path); | ||
| 459 | } | ||
| 460 | |||
| 461 | int | ||
| 462 | tls_config_set_ca_mem(struct tls_config *config, const uint8_t *ca, size_t len) | ||
| 463 | { | ||
| 464 | return tls_set_mem(&config->ca_mem, &config->ca_len, ca, len); | ||
| 465 | } | ||
| 466 | |||
| 467 | int | ||
| 468 | tls_config_set_cert_file(struct tls_config *config, const char *cert_file) | ||
| 469 | { | ||
| 470 | return tls_keypair_set_cert_file(config->keypair, &config->error, | ||
| 471 | cert_file); | ||
| 472 | } | ||
| 473 | |||
| 474 | int | ||
| 475 | tls_config_set_cert_mem(struct tls_config *config, const uint8_t *cert, | ||
| 476 | size_t len) | ||
| 477 | { | ||
| 478 | return tls_keypair_set_cert_mem(config->keypair, &config->error, | ||
| 479 | cert, len); | ||
| 480 | } | ||
| 481 | |||
| 482 | int | ||
| 483 | tls_config_set_ciphers(struct tls_config *config, const char *ciphers) | ||
| 484 | { | ||
| 485 | SSL_CTX *ssl_ctx = NULL; | ||
| 486 | |||
| 487 | if (ciphers == NULL || | ||
| 488 | strcasecmp(ciphers, "default") == 0 || | ||
| 489 | strcasecmp(ciphers, "secure") == 0) | ||
| 490 | ciphers = TLS_CIPHERS_DEFAULT; | ||
| 491 | else if (strcasecmp(ciphers, "compat") == 0) | ||
| 492 | ciphers = TLS_CIPHERS_COMPAT; | ||
| 493 | else if (strcasecmp(ciphers, "legacy") == 0) | ||
| 494 | ciphers = TLS_CIPHERS_LEGACY; | ||
| 495 | else if (strcasecmp(ciphers, "all") == 0 || | ||
| 496 | strcasecmp(ciphers, "insecure") == 0) | ||
| 497 | ciphers = TLS_CIPHERS_ALL; | ||
| 498 | |||
| 499 | if ((ssl_ctx = SSL_CTX_new(SSLv23_method())) == NULL) { | ||
| 500 | tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY, | ||
| 501 | "out of memory"); | ||
| 502 | goto err; | ||
| 503 | } | ||
| 504 | if (SSL_CTX_set_cipher_list(ssl_ctx, ciphers) != 1) { | ||
| 505 | tls_config_set_errorx(config, TLS_ERROR_UNKNOWN, | ||
| 506 | "no ciphers for '%s'", ciphers); | ||
| 507 | goto err; | ||
| 508 | } | ||
| 509 | |||
| 510 | SSL_CTX_free(ssl_ctx); | ||
| 511 | return tls_set_string(&config->ciphers, ciphers); | ||
| 512 | |||
| 513 | err: | ||
| 514 | SSL_CTX_free(ssl_ctx); | ||
| 515 | return -1; | ||
| 516 | } | ||
| 517 | |||
| 518 | int | ||
| 519 | tls_config_set_crl_file(struct tls_config *config, const char *crl_file) | ||
| 520 | { | ||
| 521 | return tls_config_load_file(&config->error, "CRL", crl_file, | ||
| 522 | &config->crl_mem, &config->crl_len); | ||
| 523 | } | ||
| 524 | |||
| 525 | int | ||
| 526 | tls_config_set_crl_mem(struct tls_config *config, const uint8_t *crl, | ||
| 527 | size_t len) | ||
| 528 | { | ||
| 529 | return tls_set_mem(&config->crl_mem, &config->crl_len, crl, len); | ||
| 530 | } | ||
| 531 | |||
| 532 | int | ||
| 533 | tls_config_set_dheparams(struct tls_config *config, const char *params) | ||
| 534 | { | ||
| 535 | int keylen; | ||
| 536 | |||
| 537 | if (params == NULL || strcasecmp(params, "none") == 0) | ||
| 538 | keylen = 0; | ||
| 539 | else if (strcasecmp(params, "auto") == 0) | ||
| 540 | keylen = -1; | ||
| 541 | else if (strcasecmp(params, "legacy") == 0) | ||
| 542 | keylen = 1024; | ||
| 543 | else { | ||
| 544 | tls_config_set_errorx(config, TLS_ERROR_UNKNOWN, | ||
| 545 | "invalid dhe param '%s'", params); | ||
| 546 | return (-1); | ||
| 547 | } | ||
| 548 | |||
| 549 | config->dheparams = keylen; | ||
| 550 | |||
| 551 | return (0); | ||
| 552 | } | ||
| 553 | |||
| 554 | int | ||
| 555 | tls_config_set_ecdhecurve(struct tls_config *config, const char *curve) | ||
| 556 | { | ||
| 557 | if (curve == NULL || | ||
| 558 | strcasecmp(curve, "none") == 0 || | ||
| 559 | strcasecmp(curve, "auto") == 0) { | ||
| 560 | curve = TLS_ECDHE_CURVES; | ||
| 561 | } else if (strchr(curve, ',') != NULL || strchr(curve, ':') != NULL) { | ||
| 562 | tls_config_set_errorx(config, TLS_ERROR_UNKNOWN, | ||
| 563 | "invalid ecdhe curve '%s'", curve); | ||
| 564 | return (-1); | ||
| 565 | } | ||
| 566 | |||
| 567 | return tls_config_set_ecdhecurves(config, curve); | ||
| 568 | } | ||
| 569 | |||
| 570 | int | ||
| 571 | tls_config_set_ecdhecurves(struct tls_config *config, const char *curves) | ||
| 572 | { | ||
| 573 | int *curves_list = NULL, *curves_new; | ||
| 574 | size_t curves_num = 0; | ||
| 575 | char *cs = NULL; | ||
| 576 | char *p, *q; | ||
| 577 | int rv = -1; | ||
| 578 | int nid; | ||
| 579 | |||
| 580 | free(config->ecdhecurves); | ||
| 581 | config->ecdhecurves = NULL; | ||
| 582 | config->ecdhecurves_len = 0; | ||
| 583 | |||
| 584 | if (curves == NULL || strcasecmp(curves, "default") == 0) | ||
| 585 | curves = TLS_ECDHE_CURVES; | ||
| 586 | |||
| 587 | if ((cs = strdup(curves)) == NULL) { | ||
| 588 | tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY, | ||
| 589 | "out of memory"); | ||
| 590 | goto err; | ||
| 591 | } | ||
| 592 | |||
| 593 | q = cs; | ||
| 594 | while ((p = strsep(&q, ",:")) != NULL) { | ||
| 595 | while (*p == ' ' || *p == '\t') | ||
| 596 | p++; | ||
| 597 | |||
| 598 | nid = OBJ_sn2nid(p); | ||
| 599 | if (nid == NID_undef) | ||
| 600 | nid = OBJ_ln2nid(p); | ||
| 601 | if (nid == NID_undef) | ||
| 602 | nid = EC_curve_nist2nid(p); | ||
| 603 | if (nid == NID_undef) { | ||
| 604 | tls_config_set_errorx(config, TLS_ERROR_UNKNOWN, | ||
| 605 | "invalid ecdhe curve '%s'", p); | ||
| 606 | goto err; | ||
| 607 | } | ||
| 608 | |||
| 609 | if ((curves_new = reallocarray(curves_list, curves_num + 1, | ||
| 610 | sizeof(int))) == NULL) { | ||
| 611 | tls_config_set_errorx(config, TLS_ERROR_OUT_OF_MEMORY, | ||
| 612 | "out of memory"); | ||
| 613 | goto err; | ||
| 614 | } | ||
| 615 | curves_list = curves_new; | ||
| 616 | curves_list[curves_num] = nid; | ||
| 617 | curves_num++; | ||
| 618 | } | ||
| 619 | |||
| 620 | config->ecdhecurves = curves_list; | ||
| 621 | config->ecdhecurves_len = curves_num; | ||
| 622 | curves_list = NULL; | ||
| 623 | |||
| 624 | rv = 0; | ||
| 625 | |||
| 626 | err: | ||
| 627 | free(cs); | ||
| 628 | free(curves_list); | ||
| 629 | |||
| 630 | return (rv); | ||
| 631 | } | ||
| 632 | |||
| 633 | int | ||
| 634 | tls_config_set_key_file(struct tls_config *config, const char *key_file) | ||
| 635 | { | ||
| 636 | return tls_keypair_set_key_file(config->keypair, &config->error, | ||
| 637 | key_file); | ||
| 638 | } | ||
| 639 | |||
| 640 | int | ||
| 641 | tls_config_set_key_mem(struct tls_config *config, const uint8_t *key, | ||
| 642 | size_t len) | ||
| 643 | { | ||
| 644 | return tls_keypair_set_key_mem(config->keypair, &config->error, | ||
| 645 | key, len); | ||
| 646 | } | ||
| 647 | |||
| 648 | static int | ||
| 649 | tls_config_set_keypair_file_internal(struct tls_config *config, | ||
| 650 | const char *cert_file, const char *key_file, const char *ocsp_file) | ||
| 651 | { | ||
| 652 | if (tls_config_set_cert_file(config, cert_file) != 0) | ||
| 653 | return (-1); | ||
| 654 | if (tls_config_set_key_file(config, key_file) != 0) | ||
| 655 | return (-1); | ||
| 656 | if (ocsp_file != NULL && | ||
| 657 | tls_config_set_ocsp_staple_file(config, ocsp_file) != 0) | ||
| 658 | return (-1); | ||
| 659 | |||
| 660 | return (0); | ||
| 661 | } | ||
| 662 | |||
| 663 | static int | ||
| 664 | tls_config_set_keypair_mem_internal(struct tls_config *config, const uint8_t *cert, | ||
| 665 | size_t cert_len, const uint8_t *key, size_t key_len, | ||
| 666 | const uint8_t *staple, size_t staple_len) | ||
| 667 | { | ||
| 668 | if (tls_config_set_cert_mem(config, cert, cert_len) != 0) | ||
| 669 | return (-1); | ||
| 670 | if (tls_config_set_key_mem(config, key, key_len) != 0) | ||
| 671 | return (-1); | ||
| 672 | if ((staple != NULL) && | ||
| 673 | (tls_config_set_ocsp_staple_mem(config, staple, staple_len) != 0)) | ||
| 674 | return (-1); | ||
| 675 | |||
| 676 | return (0); | ||
| 677 | } | ||
| 678 | |||
| 679 | int | ||
| 680 | tls_config_set_keypair_file(struct tls_config *config, | ||
| 681 | const char *cert_file, const char *key_file) | ||
| 682 | { | ||
| 683 | return tls_config_set_keypair_file_internal(config, cert_file, key_file, | ||
| 684 | NULL); | ||
| 685 | } | ||
| 686 | |||
| 687 | int | ||
| 688 | tls_config_set_keypair_mem(struct tls_config *config, const uint8_t *cert, | ||
| 689 | size_t cert_len, const uint8_t *key, size_t key_len) | ||
| 690 | { | ||
| 691 | return tls_config_set_keypair_mem_internal(config, cert, cert_len, | ||
| 692 | key, key_len, NULL, 0); | ||
| 693 | } | ||
| 694 | |||
| 695 | int | ||
| 696 | tls_config_set_keypair_ocsp_file(struct tls_config *config, | ||
| 697 | const char *cert_file, const char *key_file, const char *ocsp_file) | ||
| 698 | { | ||
| 699 | return tls_config_set_keypair_file_internal(config, cert_file, key_file, | ||
| 700 | ocsp_file); | ||
| 701 | } | ||
| 702 | |||
| 703 | int | ||
| 704 | tls_config_set_keypair_ocsp_mem(struct tls_config *config, const uint8_t *cert, | ||
| 705 | size_t cert_len, const uint8_t *key, size_t key_len, | ||
| 706 | const uint8_t *staple, size_t staple_len) | ||
| 707 | { | ||
| 708 | return tls_config_set_keypair_mem_internal(config, cert, cert_len, | ||
| 709 | key, key_len, staple, staple_len); | ||
| 710 | } | ||
| 711 | |||
| 712 | |||
| 713 | int | ||
| 714 | tls_config_set_protocols(struct tls_config *config, uint32_t protocols) | ||
| 715 | { | ||
| 716 | config->protocols = protocols; | ||
| 717 | |||
| 718 | return (0); | ||
| 719 | } | ||
| 720 | |||
| 721 | int | ||
| 722 | tls_config_set_session_fd(struct tls_config *config, int session_fd) | ||
| 723 | { | ||
| 724 | struct stat sb; | ||
| 725 | mode_t mugo; | ||
| 726 | |||
| 727 | if (session_fd == -1) { | ||
| 728 | config->session_fd = session_fd; | ||
| 729 | return (0); | ||
| 730 | } | ||
| 731 | |||
| 732 | if (fstat(session_fd, &sb) == -1) { | ||
| 733 | tls_config_set_error(config, TLS_ERROR_UNKNOWN, | ||
| 734 | "failed to stat session file"); | ||
| 735 | return (-1); | ||
| 736 | } | ||
| 737 | if (!S_ISREG(sb.st_mode)) { | ||
| 738 | tls_config_set_errorx(config, TLS_ERROR_UNKNOWN, | ||
| 739 | "session file is not a regular file"); | ||
| 740 | return (-1); | ||
| 741 | } | ||
| 742 | |||
| 743 | if (sb.st_uid != getuid()) { | ||
| 744 | tls_config_set_errorx(config, TLS_ERROR_UNKNOWN, | ||
| 745 | "session file has incorrect owner (uid %u != %u)", | ||
| 746 | sb.st_uid, getuid()); | ||
| 747 | return (-1); | ||
| 748 | } | ||
| 749 | mugo = sb.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO); | ||
| 750 | if (mugo != (S_IRUSR|S_IWUSR)) { | ||
| 751 | tls_config_set_errorx(config, TLS_ERROR_UNKNOWN, | ||
| 752 | "session file has incorrect permissions (%o != 600)", mugo); | ||
| 753 | return (-1); | ||
| 754 | } | ||
| 755 | |||
| 756 | config->session_fd = session_fd; | ||
| 757 | |||
| 758 | return (0); | ||
| 759 | } | ||
| 760 | |||
| 761 | int | ||
| 762 | tls_config_set_sign_cb(struct tls_config *config, tls_sign_cb cb, void *cb_arg) | ||
| 763 | { | ||
| 764 | config->use_fake_private_key = 1; | ||
| 765 | config->skip_private_key_check = 1; | ||
| 766 | config->sign_cb = cb; | ||
| 767 | config->sign_cb_arg = cb_arg; | ||
| 768 | |||
| 769 | return (0); | ||
| 770 | } | ||
| 771 | |||
| 772 | int | ||
| 773 | tls_config_set_verify_depth(struct tls_config *config, int verify_depth) | ||
| 774 | { | ||
| 775 | config->verify_depth = verify_depth; | ||
| 776 | |||
| 777 | return (0); | ||
| 778 | } | ||
| 779 | |||
| 780 | void | ||
| 781 | tls_config_prefer_ciphers_client(struct tls_config *config) | ||
| 782 | { | ||
| 783 | config->ciphers_server = 0; | ||
| 784 | } | ||
| 785 | |||
| 786 | void | ||
| 787 | tls_config_prefer_ciphers_server(struct tls_config *config) | ||
| 788 | { | ||
| 789 | config->ciphers_server = 1; | ||
| 790 | } | ||
| 791 | |||
| 792 | void | ||
| 793 | tls_config_insecure_noverifycert(struct tls_config *config) | ||
| 794 | { | ||
| 795 | config->verify_cert = 0; | ||
| 796 | } | ||
| 797 | |||
| 798 | void | ||
| 799 | tls_config_insecure_noverifyname(struct tls_config *config) | ||
| 800 | { | ||
| 801 | config->verify_name = 0; | ||
| 802 | } | ||
| 803 | |||
| 804 | void | ||
| 805 | tls_config_insecure_noverifytime(struct tls_config *config) | ||
| 806 | { | ||
| 807 | config->verify_time = 0; | ||
| 808 | } | ||
| 809 | |||
| 810 | void | ||
| 811 | tls_config_verify(struct tls_config *config) | ||
| 812 | { | ||
| 813 | config->verify_cert = 1; | ||
| 814 | config->verify_name = 1; | ||
| 815 | config->verify_time = 1; | ||
| 816 | } | ||
| 817 | |||
| 818 | void | ||
| 819 | tls_config_ocsp_require_stapling(struct tls_config *config) | ||
| 820 | { | ||
| 821 | config->ocsp_require_stapling = 1; | ||
| 822 | } | ||
| 823 | |||
| 824 | void | ||
| 825 | tls_config_verify_client(struct tls_config *config) | ||
| 826 | { | ||
| 827 | config->verify_client = 1; | ||
| 828 | } | ||
| 829 | |||
| 830 | void | ||
| 831 | tls_config_verify_client_optional(struct tls_config *config) | ||
| 832 | { | ||
| 833 | config->verify_client = 2; | ||
| 834 | } | ||
| 835 | |||
| 836 | void | ||
| 837 | tls_config_skip_private_key_check(struct tls_config *config) | ||
| 838 | { | ||
| 839 | config->skip_private_key_check = 1; | ||
| 840 | } | ||
| 841 | |||
| 842 | void | ||
| 843 | tls_config_use_fake_private_key(struct tls_config *config) | ||
| 844 | { | ||
| 845 | config->use_fake_private_key = 1; | ||
| 846 | config->skip_private_key_check = 1; | ||
| 847 | } | ||
| 848 | |||
| 849 | int | ||
| 850 | tls_config_set_ocsp_staple_file(struct tls_config *config, const char *staple_file) | ||
| 851 | { | ||
| 852 | return tls_keypair_set_ocsp_staple_file(config->keypair, &config->error, | ||
| 853 | staple_file); | ||
| 854 | } | ||
| 855 | |||
| 856 | int | ||
| 857 | tls_config_set_ocsp_staple_mem(struct tls_config *config, const uint8_t *staple, | ||
| 858 | size_t len) | ||
| 859 | { | ||
| 860 | return tls_keypair_set_ocsp_staple_mem(config->keypair, &config->error, | ||
| 861 | staple, len); | ||
| 862 | } | ||
| 863 | |||
| 864 | int | ||
| 865 | tls_config_set_session_id(struct tls_config *config, | ||
| 866 | const unsigned char *session_id, size_t len) | ||
| 867 | { | ||
| 868 | if (len > TLS_MAX_SESSION_ID_LENGTH) { | ||
| 869 | tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT, | ||
| 870 | "session ID too large"); | ||
| 871 | return (-1); | ||
| 872 | } | ||
| 873 | memset(config->session_id, 0, sizeof(config->session_id)); | ||
| 874 | memcpy(config->session_id, session_id, len); | ||
| 875 | return (0); | ||
| 876 | } | ||
| 877 | |||
| 878 | int | ||
| 879 | tls_config_set_session_lifetime(struct tls_config *config, int lifetime) | ||
| 880 | { | ||
| 881 | if (lifetime > TLS_MAX_SESSION_TIMEOUT) { | ||
| 882 | tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT, | ||
| 883 | "session lifetime too large"); | ||
| 884 | return (-1); | ||
| 885 | } | ||
| 886 | if (lifetime != 0 && lifetime < TLS_MIN_SESSION_TIMEOUT) { | ||
| 887 | tls_config_set_errorx(config, TLS_ERROR_INVALID_ARGUMENT, | ||
| 888 | "session lifetime too small"); | ||
| 889 | return (-1); | ||
| 890 | } | ||
| 891 | |||
| 892 | config->session_lifetime = lifetime; | ||
| 893 | return (0); | ||
| 894 | } | ||
| 895 | |||
| 896 | int | ||
| 897 | tls_config_add_ticket_key(struct tls_config *config, uint32_t keyrev, | ||
| 898 | unsigned char *key, size_t keylen) | ||
| 899 | { | ||
| 900 | struct tls_ticket_key newkey; | ||
| 901 | int i; | ||
| 902 | |||
| 903 | if (TLS_TICKET_KEY_SIZE != keylen || | ||
| 904 | sizeof(newkey.aes_key) + sizeof(newkey.hmac_key) > keylen) { | ||
| 905 | tls_config_set_errorx(config, TLS_ERROR_UNKNOWN, | ||
| 906 | "wrong amount of ticket key data"); | ||
| 907 | return (-1); | ||
| 908 | } | ||
| 909 | |||
| 910 | keyrev = htonl(keyrev); | ||
| 911 | memset(&newkey, 0, sizeof(newkey)); | ||
| 912 | memcpy(newkey.key_name, &keyrev, sizeof(keyrev)); | ||
| 913 | memcpy(newkey.aes_key, key, sizeof(newkey.aes_key)); | ||
| 914 | memcpy(newkey.hmac_key, key + sizeof(newkey.aes_key), | ||
| 915 | sizeof(newkey.hmac_key)); | ||
| 916 | newkey.time = time(NULL); | ||
| 917 | |||
| 918 | for (i = 0; i < TLS_NUM_TICKETS; i++) { | ||
| 919 | struct tls_ticket_key *tk = &config->ticket_keys[i]; | ||
| 920 | if (memcmp(newkey.key_name, tk->key_name, | ||
| 921 | sizeof(tk->key_name)) != 0) | ||
| 922 | continue; | ||
| 923 | |||
| 924 | /* allow re-entry of most recent key */ | ||
| 925 | if (i == 0 && memcmp(newkey.aes_key, tk->aes_key, | ||
| 926 | sizeof(tk->aes_key)) == 0 && memcmp(newkey.hmac_key, | ||
| 927 | tk->hmac_key, sizeof(tk->hmac_key)) == 0) | ||
| 928 | return (0); | ||
| 929 | tls_config_set_errorx(config, TLS_ERROR_UNKNOWN, | ||
| 930 | "ticket key already present"); | ||
| 931 | return (-1); | ||
| 932 | } | ||
| 933 | |||
| 934 | memmove(&config->ticket_keys[1], &config->ticket_keys[0], | ||
| 935 | sizeof(config->ticket_keys) - sizeof(config->ticket_keys[0])); | ||
| 936 | config->ticket_keys[0] = newkey; | ||
| 937 | |||
| 938 | config->ticket_autorekey = 0; | ||
| 939 | |||
| 940 | return (0); | ||
| 941 | } | ||
| 942 | |||
| 943 | int | ||
| 944 | tls_config_ticket_autorekey(struct tls_config *config) | ||
| 945 | { | ||
| 946 | unsigned char key[TLS_TICKET_KEY_SIZE]; | ||
| 947 | int rv; | ||
| 948 | |||
| 949 | arc4random_buf(key, sizeof(key)); | ||
| 950 | rv = tls_config_add_ticket_key(config, config->ticket_keyrev++, key, | ||
| 951 | sizeof(key)); | ||
| 952 | config->ticket_autorekey = 1; | ||
| 953 | return (rv); | ||
| 954 | } | ||
