The diff below implements sending and parsing the psk_key_exchange_modes extension. Only PSK_DHE_KE will be supported, so clients only indicate support for this mode and servers ignore all other modes (i.e., PSK_KE).
This is currently gated behind a use_psk_dhe_ke Boolean in the TLSv1.3 handshake struct, which isn't set client side and ignored server side. The diff also adds boiler plate for the pre-shared key extension. Due to the way the transcript hash for PSK binders is calculated, clients MUST send this as the last extension, so the extension is added to the end of tls_extensions[] which makes sure of this for both clients and servers. Index: ssl_locl.h =================================================================== RCS file: /cvs/src/lib/libssl/ssl_locl.h,v retrieving revision 1.388 diff -u -p -r1.388 ssl_locl.h --- ssl_locl.h 17 Mar 2022 17:22:16 -0000 1.388 +++ ssl_locl.h 31 May 2022 13:16:07 -0000 @@ -548,6 +548,9 @@ typedef struct ssl_handshake_tls13_st { int use_legacy; int hrr; + /* Client indicates psk_dhe_ke support in PskKeyExchangeMode. */ + int use_psk_dhe_ke; + /* Certificate selected for use (static pointer). */ const SSL_CERT_PKEY *cpk; Index: ssl_tlsext.c =================================================================== RCS file: /cvs/src/lib/libssl/ssl_tlsext.c,v retrieving revision 1.110 diff -u -p -r1.110 ssl_tlsext.c --- ssl_tlsext.c 5 Feb 2022 14:54:10 -0000 1.110 +++ ssl_tlsext.c 31 May 2022 13:15:05 -0000 @@ -1832,6 +1832,119 @@ tlsext_cookie_client_parse(SSL *s, uint1 return 0; } +/* + * Pre-Shared Key Exchange Modes - RFC 8446, 4.2.9. + */ + +int +tlsext_psk_key_exchange_modes_client_needs(SSL *s, uint16_t msg_type) +{ + return (s->s3->hs.tls13.use_psk_dhe_ke && + s->s3->hs.our_max_tls_version >= TLS1_3_VERSION); +} + +int +tlsext_psk_key_exchange_modes_client_build(SSL *s, uint16_t msg_type, CBB *cbb) +{ + CBB ke_modes; + + if (!CBB_add_u8_length_prefixed(cbb, &ke_modes)) + return 0; + + /* Do not indicate support for PSK-only key establishment. */ + if (!CBB_add_u8(&ke_modes, TLS13_PSK_DHE_KE)) + return 0; + + if (!CBB_flush(cbb)) + return 0; + + return 1; +} + +int +tlsext_psk_key_exchange_modes_server_parse(SSL *s, uint16_t msg_type, CBS *cbs, + int *alert) +{ + CBS ke_modes; + uint8_t ke_mode; + + if (!CBS_get_u8_length_prefixed(cbs, &ke_modes)) + return 0; + + while (CBS_len(&ke_modes) > 0) { + if (!CBS_get_u8(&ke_modes, &ke_mode)) + return 0; + + if (ke_mode == TLS13_PSK_DHE_KE) + s->s3->hs.tls13.use_psk_dhe_ke = 1; + } + + return 1; +} + +/* Servers MUST NOT send this extension. */ + +int +tlsext_psk_key_exchange_modes_server_needs(SSL *s, uint16_t msg_type) +{ + return 0; +} + +int +tlsext_psk_key_exchange_modes_server_build(SSL *s, uint16_t msg_type, CBB *cbb) +{ + return 0; +} + +int +tlsext_psk_key_exchange_modes_client_parse(SSL *s, uint16_t msg_type, CBS *cbs, + int *alert) +{ + return 0; +} + +/* + * Pre-Shared Key Extension - RFC 8446, 4.2.11 + */ + +int +tlsext_pre_shared_key_client_needs(SSL *s, uint16_t msg_type) +{ + return 0; +} + +int +tlsext_pre_shared_key_client_build(SSL *s, uint16_t msg_type, CBB *cbb) +{ + return 0; +} + +int +tlsext_pre_shared_key_client_parse(SSL *s, uint16_t msg_type, CBS *cbs, + int *alert) +{ + return 0; +} + +int +tlsext_pre_shared_key_server_needs(SSL *s, uint16_t msg_type) +{ + return 0; +} + +int +tlsext_pre_shared_key_server_build(SSL *s, uint16_t msg_type, CBB *cbb) +{ + return 0; +} + +int +tlsext_pre_shared_key_server_parse(SSL *s, uint16_t msg_type, CBS *cbs, + int *alert) +{ + return 0; +} + struct tls_extension_funcs { int (*needs)(SSL *s, uint16_t msg_type); int (*build)(SSL *s, uint16_t msg_type, CBB *cbb); @@ -2018,8 +2131,38 @@ static const struct tls_extension tls_ex .build = tlsext_srtp_server_build, .parse = tlsext_srtp_server_parse, }, - } + }, #endif /* OPENSSL_NO_SRTP */ + { + .type = TLSEXT_TYPE_psk_key_exchange_modes, + .messages = SSL_TLSEXT_MSG_CH, + .client = { + .needs = tlsext_psk_key_exchange_modes_client_needs, + .build = tlsext_psk_key_exchange_modes_client_build, + .parse = tlsext_psk_key_exchange_modes_client_parse, + }, + .server = { + .needs = tlsext_psk_key_exchange_modes_server_needs, + .build = tlsext_psk_key_exchange_modes_server_build, + .parse = tlsext_psk_key_exchange_modes_server_parse, + }, + }, + { + /* RFC 8446, 4.2 - MUST be the last extension in the CH. */ + + .type = TLSEXT_TYPE_pre_shared_key, + .messages = SSL_TLSEXT_MSG_CH | SSL_TLSEXT_MSG_SH, + .client = { + .needs = tlsext_pre_shared_key_client_needs, + .build = tlsext_pre_shared_key_client_build, + .parse = tlsext_pre_shared_key_client_parse, + }, + .server = { + .needs = tlsext_pre_shared_key_server_needs, + .build = tlsext_pre_shared_key_server_build, + .parse = tlsext_pre_shared_key_server_parse, + }, + }, }; #define N_TLS_EXTENSIONS (sizeof(tls_extensions) / sizeof(*tls_extensions)) Index: ssl_tlsext.h =================================================================== RCS file: /cvs/src/lib/libssl/ssl_tlsext.h,v retrieving revision 1.27 diff -u -p -r1.27 ssl_tlsext.h --- ssl_tlsext.h 1 Nov 2021 16:37:17 -0000 1.27 +++ ssl_tlsext.h 31 May 2022 13:11:55 -0000 @@ -119,6 +119,28 @@ int tlsext_cookie_server_needs(SSL *s, u int tlsext_cookie_server_build(SSL *s, uint16_t msg_type, CBB *cbb); int tlsext_cookie_server_parse(SSL *s, uint16_t msg_type, CBS *cbs, int *alert); +int tlsext_psk_key_exchange_modes_client_needs(SSL *s, uint16_t msg_type); +int tlsext_psk_key_exchange_modes_client_build(SSL *s, uint16_t msg_type, + CBB *cbb); +int tlsext_psk_key_exchange_modes_client_parse(SSL *s, uint16_t msg_type, + CBS *cbs, int *alert); +int tlsext_psk_key_exchange_modes_server_needs(SSL *s, uint16_t msg_type); +int tlsext_psk_key_exchange_modes_server_build(SSL *s, uint16_t msg_type, + CBB *cbb); +int tlsext_psk_key_exchange_modes_server_parse(SSL *s, uint16_t msg_type, + CBS *cbs, int *alert); + +int tlsext_pre_shared_key_client_needs(SSL *s, uint16_t msg_type); +int tlsext_pre_shared_key_client_build(SSL *s, uint16_t msg_type, + CBB *cbb); +int tlsext_pre_shared_key_client_parse(SSL *s, uint16_t msg_type, CBS *cbs, + int *alert); +int tlsext_pre_shared_key_server_needs(SSL *s, uint16_t msg_type); +int tlsext_pre_shared_key_server_build(SSL *s, uint16_t msg_type, CBB *cbb); +int tlsext_pre_shared_key_server_parse(SSL *s, uint16_t msg_type, CBS *cbs, + int *alert); + + #ifndef OPENSSL_NO_SRTP int tlsext_srtp_client_needs(SSL *s, uint16_t msg_type); int tlsext_srtp_client_build(SSL *s, uint16_t msg_type, CBB *cbb); Index: tls13_internal.h =================================================================== RCS file: /cvs/src/lib/libssl/tls13_internal.h,v retrieving revision 1.96 diff -u -p -r1.96 tls13_internal.h --- tls13_internal.h 5 Jan 2022 17:10:02 -0000 1.96 +++ tls13_internal.h 31 May 2022 13:11:55 -0000 @@ -95,6 +95,17 @@ typedef void (*tls13_info_cb)(void *_cb_ typedef int (*tls13_ocsp_status_cb)(void *_cb_arg); /* + * PSK support + */ + +/* + * Known PskKeyExchangeMode values. + * https://www.iana.org/assignments/tls-parameters/#tls-pskkeyexchangemode + */ +#define TLS13_PSK_KE 0 +#define TLS13_PSK_DHE_KE 1 + +/* * Secrets. */ struct tls13_secret {