1 /* $OpenBSD: ssl_get_shared_ciphers.c,v 1.11 2022/02/05 18:19:39 tb Exp $ */ 2 /* 3 * Copyright (c) 2021 Theo Buehler <tb@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 <stdint.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 23 #include <openssl/bio.h> 24 #include <openssl/crypto.h> 25 #include <openssl/err.h> 26 #include <openssl/ssl.h> 27 28 struct peer_config { 29 const char *name; 30 int server; 31 uint16_t max_version; 32 uint16_t min_version; 33 const char *ciphers; 34 }; 35 36 struct ssl_shared_ciphers_test_data { 37 const char *description; 38 struct peer_config client_config; 39 struct peer_config server_config; 40 const char *shared_ciphers; 41 const char *shared_ciphers_without_aesni; 42 }; 43 44 char *server_cert; 45 char *server_key; 46 47 static const struct ssl_shared_ciphers_test_data ssl_shared_ciphers_tests[] = { 48 { 49 .description = "TLSv1.3 defaults", 50 .client_config = { 51 .name = "client", 52 .server = 0, 53 .max_version = TLS1_3_VERSION, 54 .min_version = TLS1_3_VERSION, 55 .ciphers = 56 "TLS_AES_256_GCM_SHA384:" 57 "TLS_CHACHA20_POLY1305_SHA256:" 58 "TLS_AES_128_GCM_SHA256", 59 }, 60 .server_config = { 61 .name = "server", 62 .server = 1, 63 .max_version = TLS1_3_VERSION, 64 .min_version = TLS1_3_VERSION, 65 .ciphers = 66 "TLS_AES_256_GCM_SHA384:" 67 "TLS_CHACHA20_POLY1305_SHA256:" 68 "TLS_AES_128_GCM_SHA256", 69 }, 70 .shared_ciphers = 71 "TLS_AES_256_GCM_SHA384:" 72 "TLS_CHACHA20_POLY1305_SHA256:" 73 "TLS_AES_128_GCM_SHA256", 74 }, 75 76 { 77 .description = "TLSv1.3, client without ChaCha", 78 .client_config = { 79 .name = "client", 80 .server = 0, 81 .max_version = TLS1_3_VERSION, 82 .min_version = TLS1_3_VERSION, 83 .ciphers = 84 "TLS_AES_256_GCM_SHA384:" 85 "TLS_AES_128_GCM_SHA256", 86 }, 87 .server_config = { 88 .name = "server", 89 .server = 1, 90 .max_version = TLS1_3_VERSION, 91 .min_version = TLS1_3_VERSION, 92 .ciphers = 93 "TLS_AES_256_GCM_SHA384:" 94 "TLS_CHACHA20_POLY1305_SHA256:" 95 "TLS_AES_128_GCM_SHA256", 96 }, 97 .shared_ciphers = 98 "TLS_AES_256_GCM_SHA384:" 99 "TLS_AES_128_GCM_SHA256", 100 }, 101 102 { 103 .description = "TLSv1.2", 104 .client_config = { 105 .name = "client", 106 .server = 0, 107 .max_version = TLS1_2_VERSION, 108 .min_version = TLS1_2_VERSION, 109 .ciphers = 110 "ECDHE-RSA-AES256-GCM-SHA384:" 111 "ECDHE-ECDSA-AES256-GCM-SHA384:" 112 "ECDHE-RSA-AES256-SHA384:" 113 "ECDHE-ECDSA-AES256-SHA384:" 114 "ECDHE-RSA-AES256-SHA:" 115 "ECDHE-ECDSA-AES256-SHA", 116 }, 117 .server_config = { 118 .name = "server", 119 .server = 1, 120 .max_version = TLS1_2_VERSION, 121 .min_version = TLS1_2_VERSION, 122 .ciphers = 123 "ECDHE-RSA-AES256-GCM-SHA384:" 124 "ECDHE-ECDSA-AES256-GCM-SHA384:" 125 "ECDHE-RSA-AES256-SHA384:" 126 "ECDHE-ECDSA-AES256-SHA384:" 127 "ECDHE-RSA-AES256-SHA:" 128 "ECDHE-ECDSA-AES256-SHA", 129 }, 130 .shared_ciphers = 131 "ECDHE-RSA-AES256-GCM-SHA384:" 132 "ECDHE-ECDSA-AES256-GCM-SHA384:" 133 "ECDHE-RSA-AES256-SHA384:" 134 "ECDHE-ECDSA-AES256-SHA384:" 135 "ECDHE-RSA-AES256-SHA:" 136 "ECDHE-ECDSA-AES256-SHA", 137 }, 138 139 { 140 .description = "TLSv1.2, server without ECDSA", 141 .client_config = { 142 .name = "client", 143 .server = 0, 144 .max_version = TLS1_2_VERSION, 145 .min_version = TLS1_2_VERSION, 146 .ciphers = 147 "ECDHE-RSA-AES256-GCM-SHA384:" 148 "ECDHE-ECDSA-AES256-GCM-SHA384:" 149 "ECDHE-RSA-AES256-SHA384:" 150 "ECDHE-ECDSA-AES256-SHA384:" 151 "ECDHE-RSA-AES256-SHA:" 152 "ECDHE-ECDSA-AES256-SHA", 153 }, 154 .server_config = { 155 .name = "server", 156 .server = 1, 157 .max_version = TLS1_2_VERSION, 158 .min_version = TLS1_2_VERSION, 159 .ciphers = 160 "ECDHE-RSA-AES256-GCM-SHA384:" 161 "ECDHE-RSA-AES256-SHA384:" 162 "ECDHE-RSA-AES256-SHA", 163 }, 164 .shared_ciphers = 165 "ECDHE-RSA-AES256-GCM-SHA384:" 166 "ECDHE-RSA-AES256-SHA384:" 167 "ECDHE-RSA-AES256-SHA", 168 }, 169 170 { 171 .description = "TLSv1.3 ciphers are prepended", 172 .client_config = { 173 .name = "client", 174 .server = 0, 175 .max_version = TLS1_3_VERSION, 176 .min_version = TLS1_2_VERSION, 177 .ciphers = 178 "ECDHE-RSA-AES256-GCM-SHA384", 179 }, 180 .server_config = { 181 .name = "server", 182 .server = 1, 183 .max_version = TLS1_3_VERSION, 184 .min_version = TLS1_2_VERSION, 185 .ciphers = 186 "ECDHE-RSA-AES256-GCM-SHA384", 187 }, 188 .shared_ciphers = 189 "TLS_AES_256_GCM_SHA384:" 190 "TLS_CHACHA20_POLY1305_SHA256:" 191 "TLS_AES_128_GCM_SHA256:" 192 "ECDHE-RSA-AES256-GCM-SHA384", 193 .shared_ciphers_without_aesni = 194 "TLS_CHACHA20_POLY1305_SHA256:" 195 "TLS_AES_256_GCM_SHA384:" 196 "TLS_AES_128_GCM_SHA256:" 197 "ECDHE-RSA-AES256-GCM-SHA384", 198 }, 199 }; 200 201 static const size_t N_SHARED_CIPHERS_TESTS = 202 sizeof(ssl_shared_ciphers_tests) / sizeof(ssl_shared_ciphers_tests[0]); 203 204 static SSL_CTX * 205 peer_config_to_ssl_ctx(const struct peer_config *config) 206 { 207 SSL_CTX *ctx; 208 209 if ((ctx = SSL_CTX_new(TLS_method())) == NULL) { 210 fprintf(stderr, "SSL_CTX_new(%s) failed\n", config->name); 211 goto err; 212 } 213 if (!SSL_CTX_set_max_proto_version(ctx, config->max_version)) { 214 fprintf(stderr, "max_proto_version(%s) failed\n", config->name); 215 goto err; 216 } 217 if (!SSL_CTX_set_min_proto_version(ctx, config->min_version)) { 218 fprintf(stderr, "min_proto_version(%s) failed\n", config->name); 219 goto err; 220 } 221 if (!SSL_CTX_set_cipher_list(ctx, config->ciphers)) { 222 fprintf(stderr, "set_cipher_list(%s) failed\n", config->name); 223 goto err; 224 } 225 226 if (config->server) { 227 if (!SSL_CTX_use_certificate_file(ctx, server_cert, 228 SSL_FILETYPE_PEM)) { 229 fprintf(stderr, "use_certificate_file(%s) failed\n", 230 config->name); 231 goto err; 232 } 233 if (!SSL_CTX_use_PrivateKey_file(ctx, server_key, 234 SSL_FILETYPE_PEM)) { 235 fprintf(stderr, "use_PrivateKey_file(%s) failed\n", 236 config->name); 237 goto err; 238 } 239 } 240 241 return ctx; 242 243 err: 244 SSL_CTX_free(ctx); 245 return NULL; 246 } 247 248 /* Connect client and server via a pair of "nonblocking" memory BIOs. */ 249 static int 250 connect_peers(SSL *client_ssl, SSL *server_ssl, const char *description) 251 { 252 BIO *client_wbio = NULL, *server_wbio = NULL; 253 int ret = 0; 254 255 if ((client_wbio = BIO_new(BIO_s_mem())) == NULL) { 256 fprintf(stderr, "%s: failed to create client BIO\n", 257 description); 258 goto err; 259 } 260 if ((server_wbio = BIO_new(BIO_s_mem())) == NULL) { 261 fprintf(stderr, "%s: failed to create server BIO\n", 262 description); 263 goto err; 264 } 265 if (BIO_set_mem_eof_return(client_wbio, -1) <= 0) { 266 fprintf(stderr, "%s: failed to set client eof return\n", 267 description); 268 goto err; 269 } 270 if (BIO_set_mem_eof_return(server_wbio, -1) <= 0) { 271 fprintf(stderr, "%s: failed to set server eof return\n", 272 description); 273 goto err; 274 } 275 276 /* Avoid double free. SSL_set_bio() takes ownership of the BIOs. */ 277 BIO_up_ref(client_wbio); 278 BIO_up_ref(server_wbio); 279 280 SSL_set_bio(client_ssl, server_wbio, client_wbio); 281 SSL_set_bio(server_ssl, client_wbio, server_wbio); 282 client_wbio = NULL; 283 server_wbio = NULL; 284 285 ret = 1; 286 287 err: 288 BIO_free(client_wbio); 289 BIO_free(server_wbio); 290 291 return ret; 292 } 293 294 static int 295 push_data_to_peer(SSL *ssl, int *ret, int (*func)(SSL *), const char *func_name, 296 const char *description) 297 { 298 int ssl_err = 0; 299 300 if (*ret == 1) 301 return 1; 302 303 /* 304 * Do SSL_connect/SSL_accept/SSL_shutdown once and loop while hitting 305 * WANT_WRITE. If done or on WANT_READ hand off to peer. 306 */ 307 308 do { 309 if ((*ret = func(ssl)) <= 0) 310 ssl_err = SSL_get_error(ssl, *ret); 311 } while (*ret <= 0 && ssl_err == SSL_ERROR_WANT_WRITE); 312 313 /* Ignore erroneous error - see SSL_shutdown(3)... */ 314 if (func == SSL_shutdown && ssl_err == SSL_ERROR_SYSCALL) 315 return 1; 316 317 if (*ret <= 0 && ssl_err != SSL_ERROR_WANT_READ) { 318 fprintf(stderr, "%s: %s failed\n", description, func_name); 319 ERR_print_errors_fp(stderr); 320 return 0; 321 } 322 323 return 1; 324 } 325 326 /* 327 * Alternate between loops of SSL_connect() and SSL_accept() as long as only 328 * WANT_READ and WANT_WRITE situations are encountered. A function is repeated 329 * until WANT_READ is returned or it succeeds, then it's the other function's 330 * turn to make progress. Succeeds if SSL_connect() and SSL_accept() return 1. 331 */ 332 static int 333 handshake(SSL *client_ssl, SSL *server_ssl, const char *description) 334 { 335 int loops = 0, client_ret = 0, server_ret = 0; 336 337 while (loops++ < 10 && (client_ret <= 0 || server_ret <= 0)) { 338 if (!push_data_to_peer(client_ssl, &client_ret, SSL_connect, 339 "SSL_connect", description)) 340 return 0; 341 342 if (!push_data_to_peer(server_ssl, &server_ret, SSL_accept, 343 "SSL_accept", description)) 344 return 0; 345 } 346 347 if (client_ret != 1 || server_ret != 1) { 348 fprintf(stderr, "%s: failed\n", __func__); 349 return 0; 350 } 351 352 return 1; 353 } 354 355 static int 356 shutdown_peers(SSL *client_ssl, SSL *server_ssl, const char *description) 357 { 358 int loops = 0, client_ret = 0, server_ret = 0; 359 360 while (loops++ < 10 && (client_ret <= 0 || server_ret <= 0)) { 361 if (!push_data_to_peer(client_ssl, &client_ret, SSL_shutdown, 362 "client shutdown", description)) 363 return 0; 364 365 if (!push_data_to_peer(server_ssl, &server_ret, SSL_shutdown, 366 "server shutdown", description)) 367 return 0; 368 } 369 370 if (client_ret != 1 || server_ret != 1) { 371 fprintf(stderr, "%s: failed\n", __func__); 372 return 0; 373 } 374 375 return 1; 376 } 377 378 /* from ssl_ciph.c */ 379 static inline int 380 ssl_aes_is_accelerated(void) 381 { 382 #if defined(__i386__) || defined(__x86_64__) 383 return ((OPENSSL_cpu_caps() & (1ULL << 57)) != 0); 384 #else 385 return (0); 386 #endif 387 } 388 389 static int 390 check_shared_ciphers(const struct ssl_shared_ciphers_test_data *test, 391 const char *got) 392 { 393 const char *want = test->shared_ciphers; 394 int failed; 395 396 if (!ssl_aes_is_accelerated() && 397 test->shared_ciphers_without_aesni != NULL) 398 want = test->shared_ciphers_without_aesni; 399 400 failed = strcmp(want, got); 401 402 if (failed) 403 fprintf(stderr, "%s: want \"%s\", got \"%s\"\n", 404 test->description, want, got); 405 406 return failed; 407 } 408 409 static int 410 test_get_shared_ciphers(const struct ssl_shared_ciphers_test_data *test) 411 { 412 SSL_CTX *client_ctx = NULL, *server_ctx = NULL; 413 SSL *client_ssl = NULL, *server_ssl = NULL; 414 char buf[4096]; 415 int failed = 1; 416 417 if ((client_ctx = peer_config_to_ssl_ctx(&test->client_config)) == NULL) 418 goto err; 419 if ((server_ctx = peer_config_to_ssl_ctx(&test->server_config)) == NULL) 420 goto err; 421 422 if ((client_ssl = SSL_new(client_ctx)) == NULL) { 423 fprintf(stderr, "%s: failed to create client SSL\n", 424 test->description); 425 goto err; 426 } 427 if ((server_ssl = SSL_new(server_ctx)) == NULL) { 428 fprintf(stderr, "%s: failed to create server SSL\n", 429 test->description); 430 goto err; 431 } 432 433 if (!connect_peers(client_ssl, server_ssl, test->description)) 434 goto err; 435 436 if (!handshake(client_ssl, server_ssl, test->description)) 437 goto err; 438 439 if (SSL_get_shared_ciphers(server_ssl, buf, sizeof(buf)) == NULL) { 440 fprintf(stderr, "%s: failed to get shared ciphers\n", 441 test->description); 442 goto err; 443 } 444 445 if (!shutdown_peers(client_ssl, server_ssl, test->description)) 446 goto err; 447 448 failed = check_shared_ciphers(test, buf); 449 450 err: 451 SSL_CTX_free(client_ctx); 452 SSL_CTX_free(server_ctx); 453 SSL_free(client_ssl); 454 SSL_free(server_ssl); 455 456 return failed; 457 } 458 459 int 460 main(int argc, char **argv) 461 { 462 size_t i; 463 int failed = 0; 464 465 if (asprintf(&server_cert, "%s/server.pem", CERTSDIR) == -1) { 466 fprintf(stderr, "asprintf server_cert failed\n"); 467 failed = 1; 468 goto err; 469 } 470 server_key = server_cert; 471 472 for (i = 0; i < N_SHARED_CIPHERS_TESTS; i++) 473 failed |= test_get_shared_ciphers(&ssl_shared_ciphers_tests[i]); 474 475 if (failed == 0) 476 printf("PASS %s\n", __FILE__); 477 478 err: 479 free(server_cert); 480 481 return failed; 482 } 483