diff options
author | tb <> | 2023-04-23 18:51:53 +0000 |
---|---|---|
committer | tb <> | 2023-04-23 18:51:53 +0000 |
commit | fb7a7adad4b566192144a21e4c93b739671b0cae (patch) | |
tree | fa6d649a58d3a734a4bc9dea3b97a71426074f8b | |
parent | 292e18c3ddebe32b0e929925c98c01b416d0210e (diff) | |
download | openbsd-fb7a7adad4b566192144a21e4c93b739671b0cae.tar.gz openbsd-fb7a7adad4b566192144a21e4c93b739671b0cae.tar.bz2 openbsd-fb7a7adad4b566192144a21e4c93b739671b0cae.zip |
Randomize the order of TLS extensions
On creation of an SSL using SSL_new(), randomize the order in which the
extensions will be sent. There are several constraints: the PSK extension
must always come last. The order cannot be randomized on a per-message
basis as the strict interpretation of the standard chosen in the CH hashing
doesn't allow changing the order between first and second ClientHello.
Another constraint is that the current code calls callbacks directly on
parsing an extension, which means that the order callbacks are called
depends on the order in which the peer sent the extensions. This results
in breaking apache-httpd setups using virtual hosts with full ranomization
because virtual hosts don't work if the SNI is unknown at the time the
ALPN callback is called. So for the time being, we ensure that SNI always
precedes ALPN to avoid issues until this issue is fixed.
This is based on an idea by David Benjamin
https://boringssl-review.googlesource.com/c/boringssl/+/48045
Input & ok jsing
-rw-r--r-- | src/lib/libssl/ssl_lib.c | 7 | ||||
-rw-r--r-- | src/lib/libssl/ssl_local.h | 3 | ||||
-rw-r--r-- | src/lib/libssl/ssl_tlsext.c | 63 | ||||
-rw-r--r-- | src/lib/libssl/ssl_tlsext.h | 3 |
4 files changed, 71 insertions, 5 deletions
diff --git a/src/lib/libssl/ssl_lib.c b/src/lib/libssl/ssl_lib.c index de4ef3fb5e..68e60a5481 100644 --- a/src/lib/libssl/ssl_lib.c +++ b/src/lib/libssl/ssl_lib.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssl_lib.c,v 1.308 2022/11/26 16:08:55 tb Exp $ */ | 1 | /* $OpenBSD: ssl_lib.c,v 1.309 2023/04/23 18:51:53 tb Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -302,6 +302,9 @@ SSL_new(SSL_CTX *ctx) | |||
302 | CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX); | 302 | CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX); |
303 | s->initial_ctx = ctx; | 303 | s->initial_ctx = ctx; |
304 | 304 | ||
305 | if (!tlsext_randomize_build_order(s)) | ||
306 | goto err; | ||
307 | |||
305 | if (ctx->tlsext_ecpointformatlist != NULL) { | 308 | if (ctx->tlsext_ecpointformatlist != NULL) { |
306 | s->tlsext_ecpointformatlist = | 309 | s->tlsext_ecpointformatlist = |
307 | calloc(ctx->tlsext_ecpointformatlist_length, | 310 | calloc(ctx->tlsext_ecpointformatlist_length, |
@@ -550,6 +553,8 @@ SSL_free(SSL *s) | |||
550 | 553 | ||
551 | ssl_cert_free(s->cert); | 554 | ssl_cert_free(s->cert); |
552 | 555 | ||
556 | free(s->tlsext_build_order); | ||
557 | |||
553 | free(s->tlsext_hostname); | 558 | free(s->tlsext_hostname); |
554 | SSL_CTX_free(s->initial_ctx); | 559 | SSL_CTX_free(s->initial_ctx); |
555 | 560 | ||
diff --git a/src/lib/libssl/ssl_local.h b/src/lib/libssl/ssl_local.h index d510f80d8c..1748eccbfd 100644 --- a/src/lib/libssl/ssl_local.h +++ b/src/lib/libssl/ssl_local.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssl_local.h,v 1.3 2022/12/26 07:31:44 jmc Exp $ */ | 1 | /* $OpenBSD: ssl_local.h,v 1.4 2023/04/23 18:51:53 tb Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -974,6 +974,7 @@ struct ssl_st { | |||
974 | 974 | ||
975 | unsigned int max_send_fragment; | 975 | unsigned int max_send_fragment; |
976 | 976 | ||
977 | const struct tls_extension **tlsext_build_order; | ||
977 | char *tlsext_hostname; | 978 | char *tlsext_hostname; |
978 | 979 | ||
979 | /* certificate status request info */ | 980 | /* certificate status request info */ |
diff --git a/src/lib/libssl/ssl_tlsext.c b/src/lib/libssl/ssl_tlsext.c index e576384118..5ff61f39a5 100644 --- a/src/lib/libssl/ssl_tlsext.c +++ b/src/lib/libssl/ssl_tlsext.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssl_tlsext.c,v 1.131 2022/11/26 16:08:56 tb Exp $ */ | 1 | /* $OpenBSD: ssl_tlsext.c,v 1.132 2023/04/23 18:51:53 tb Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2016, 2017, 2019 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2016, 2017, 2019 Joel Sing <jsing@openbsd.org> |
4 | * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> | 4 | * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> |
@@ -32,6 +32,8 @@ | |||
32 | #include "ssl_sigalgs.h" | 32 | #include "ssl_sigalgs.h" |
33 | #include "ssl_tlsext.h" | 33 | #include "ssl_tlsext.h" |
34 | 34 | ||
35 | #define TLSEXT_TYPE_alpn TLSEXT_TYPE_application_layer_protocol_negotiation | ||
36 | |||
35 | /* | 37 | /* |
36 | * Supported Application-Layer Protocol Negotiation - RFC 7301 | 38 | * Supported Application-Layer Protocol Negotiation - RFC 7301 |
37 | */ | 39 | */ |
@@ -2239,6 +2241,63 @@ tlsext_funcs(const struct tls_extension *tlsext, int is_server) | |||
2239 | return &tlsext->client; | 2241 | return &tlsext->client; |
2240 | } | 2242 | } |
2241 | 2243 | ||
2244 | int | ||
2245 | tlsext_randomize_build_order(SSL *s) | ||
2246 | { | ||
2247 | size_t idx, new_idx, psk_idx; | ||
2248 | size_t alpn_idx, sni_idx; | ||
2249 | |||
2250 | if ((s->tlsext_build_order = calloc(sizeof(*s->tlsext_build_order), | ||
2251 | N_TLS_EXTENSIONS)) == NULL) | ||
2252 | return 0; | ||
2253 | |||
2254 | /* RFC 8446, section 4.2: PSK must be the last extension in the CH. */ | ||
2255 | psk_idx = N_TLS_EXTENSIONS - 1; | ||
2256 | s->tlsext_build_order[psk_idx] = &tls_extensions[psk_idx]; | ||
2257 | |||
2258 | /* Fisher-Yates shuffle with PSK fixed. */ | ||
2259 | for (idx = 0; idx < psk_idx; idx++) { | ||
2260 | new_idx = arc4random_uniform(idx + 1); | ||
2261 | s->tlsext_build_order[idx] = s->tlsext_build_order[new_idx]; | ||
2262 | s->tlsext_build_order[new_idx] = &tls_extensions[idx]; | ||
2263 | } | ||
2264 | |||
2265 | /* | ||
2266 | * XXX - Apache2 special until year 2025: ensure that SNI precedes ALPN | ||
2267 | * for clients so that virtual host setups work correctly. | ||
2268 | */ | ||
2269 | |||
2270 | if (s->server) | ||
2271 | return 1; | ||
2272 | |||
2273 | for (idx = 0; idx < N_TLS_EXTENSIONS; idx++) { | ||
2274 | if (s->tlsext_build_order[idx]->type == TLSEXT_TYPE_alpn) | ||
2275 | alpn_idx = idx; | ||
2276 | if (s->tlsext_build_order[idx]->type == TLSEXT_TYPE_server_name) | ||
2277 | sni_idx = idx; | ||
2278 | } | ||
2279 | if (alpn_idx < sni_idx) { | ||
2280 | const struct tls_extension *tmp; | ||
2281 | |||
2282 | tmp = s->tlsext_build_order[alpn_idx]; | ||
2283 | s->tlsext_build_order[alpn_idx] = s->tlsext_build_order[sni_idx]; | ||
2284 | s->tlsext_build_order[sni_idx] = tmp; | ||
2285 | } | ||
2286 | |||
2287 | return 1; | ||
2288 | } | ||
2289 | |||
2290 | int | ||
2291 | tlsext_linearize_build_order(SSL *s) | ||
2292 | { | ||
2293 | size_t idx; | ||
2294 | |||
2295 | for (idx = 0; idx < N_TLS_EXTENSIONS; idx++) | ||
2296 | s->tlsext_build_order[idx] = &tls_extensions[idx]; | ||
2297 | |||
2298 | return 1; | ||
2299 | } | ||
2300 | |||
2242 | static int | 2301 | static int |
2243 | tlsext_build(SSL *s, int is_server, uint16_t msg_type, CBB *cbb) | 2302 | tlsext_build(SSL *s, int is_server, uint16_t msg_type, CBB *cbb) |
2244 | { | 2303 | { |
@@ -2255,7 +2314,7 @@ tlsext_build(SSL *s, int is_server, uint16_t msg_type, CBB *cbb) | |||
2255 | return 0; | 2314 | return 0; |
2256 | 2315 | ||
2257 | for (i = 0; i < N_TLS_EXTENSIONS; i++) { | 2316 | for (i = 0; i < N_TLS_EXTENSIONS; i++) { |
2258 | tlsext = &tls_extensions[i]; | 2317 | tlsext = s->tlsext_build_order[i]; |
2259 | ext = tlsext_funcs(tlsext, is_server); | 2318 | ext = tlsext_funcs(tlsext, is_server); |
2260 | 2319 | ||
2261 | /* RFC 8446 Section 4.2 */ | 2320 | /* RFC 8446 Section 4.2 */ |
diff --git a/src/lib/libssl/ssl_tlsext.h b/src/lib/libssl/ssl_tlsext.h index 7a41c8095d..da14f7fa94 100644 --- a/src/lib/libssl/ssl_tlsext.h +++ b/src/lib/libssl/ssl_tlsext.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssl_tlsext.h,v 1.32 2022/08/04 09:27:36 tb Exp $ */ | 1 | /* $OpenBSD: ssl_tlsext.h,v 1.33 2023/04/23 18:51:53 tb Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org> |
4 | * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> | 4 | * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> |
@@ -41,6 +41,7 @@ int tlsext_server_build(SSL *s, uint16_t msg_type, CBB *cbb); | |||
41 | int tlsext_server_parse(SSL *s, uint16_t msg_type, CBS *cbs, int *alert); | 41 | int tlsext_server_parse(SSL *s, uint16_t msg_type, CBS *cbs, int *alert); |
42 | 42 | ||
43 | int tlsext_extension_seen(SSL *s, uint16_t); | 43 | int tlsext_extension_seen(SSL *s, uint16_t); |
44 | int tlsext_randomize_build_order(SSL *s); | ||
44 | 45 | ||
45 | __END_HIDDEN_DECLS | 46 | __END_HIDDEN_DECLS |
46 | 47 | ||