From: Nick Porter Date: Thu, 23 Jan 2025 18:37:59 +0000 (+0000) Subject: Define cbtls_psk_find_session() for TLS 1.3 PSK session creation X-Git-Tag: release_3_2_7~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=44220cd2110828447dcfa9613002395b49227705;p=thirdparty%2Ffreeradius-server.git Define cbtls_psk_find_session() for TLS 1.3 PSK session creation --- diff --git a/src/include/tls-h b/src/include/tls-h index 800b400ee5..2228e80cc9 100644 --- a/src/include/tls-h +++ b/src/include/tls-h @@ -311,6 +311,7 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx); #ifdef PSK_MAX_IDENTITY_LEN unsigned int psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len); #endif +int cbtls_psk_find_session(SSL *ssl, const unsigned char *id, size_t idlen, SSL_SESSION **sess); /* threads.c */ int tls_mutexes_init(void); diff --git a/src/main/cb.c b/src/main/cb.c index f045a39c93..e86d919b7c 100644 --- a/src/main/cb.c +++ b/src/main/cb.c @@ -363,5 +363,91 @@ unsigned int psk_server_callback(SSL *ssl, const char *identity, unsigned char * return fr_hex2bin(psk, max_psk_len, conf->psk_password, psk_len); } +/** Check that a whole string is valid utf8 + * @param str input string. + * @param inlen length of input string. + */ +static bool utf8_validate(uint8_t const *str, size_t inlen) { + size_t used, remaining = inlen; + uint8_t const *p = str; + + while (remaining > 0) { + used = fr_utf8_char(p, remaining); + if (used == 0) return false; + remaining -= used; + p += used; + } + return true; +} + +int cbtls_psk_find_session(SSL *ssl, const unsigned char *id, size_t idlen, SSL_SESSION **sess) { + fr_tls_server_conf_t *conf = (fr_tls_server_conf_t *) SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF); + REQUEST *request = (REQUEST *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST); + SSL_CIPHER const *cipher; + uint8_t psk_key[PSK_MAX_PSK_LEN]; + size_t key_len = 0; + + if (!utf8_validate(id, idlen)) { + DEBUG2("Id is not a valid utf-8 string, assuming session resumption"); + *sess = NULL; + return 1; + } else if (idlen > PSK_MAX_IDENTITY_LEN) { + WARN("id is longer than %d bytes", PSK_MAX_IDENTITY_LEN); + *sess = NULL; + return 0; + } + + if (!conf) { + ERROR("No configuration for client with PSK id %s found, rejecting connection", id); + *sess = NULL; + return 0; + } + + if (conf->psk_password) { + key_len = fr_hex2bin(psk_key, sizeof(psk_key), conf->psk_password, + talloc_array_length(conf->psk_password) - 1); + } else { + if (request && conf->psk_query) { + key_len = psk_query_run(psk_key, request, ssl, conf, (char const *)id, sizeof(psk_key)); + } + } + + if (key_len == 0) { + ERROR("No PSK for client with id %s found, rejecting connection", id); + *sess = NULL; + return 0; + } + + *sess = SSL_SESSION_new(); + if (!*sess) { + ERROR("Failed to create new SSL session"); + return 0; + } + if (!SSL_SESSION_set1_master_key(*sess, psk_key, key_len)) { + ERROR("Failed to set PSK key"); + return 0; + } + + if (!SSL_SESSION_set_protocol_version(*sess, TLS1_3_VERSION)) { + ERROR("Failed to set tls version 1.3, mandatory for PSK!"); + return 0; + } + + cipher = SSL_get_pending_cipher(ssl); + if (!cipher) { + ERROR("Failed to get pending cipher"); + return 0; + } + + DEBUG2("Setting session cipher %s", SSL_CIPHER_get_name(cipher)); + if (!SSL_SESSION_set_cipher(*sess, cipher)) { + ERROR("Failed to set session cipher"); + return 0; + } + + SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); + + return 1; +} #endif #endif