diff options
Diffstat (limited to 'lib/ext/record_size_limit.c')
-rw-r--r-- | lib/ext/record_size_limit.c | 68 |
1 files changed, 57 insertions, 11 deletions
diff --git a/lib/ext/record_size_limit.c b/lib/ext/record_size_limit.c index c74ae81e4b..4c7698ea20 100644 --- a/lib/ext/record_size_limit.c +++ b/lib/ext/record_size_limit.c @@ -52,6 +52,7 @@ _gnutls_record_size_limit_recv_params(gnutls_session_t session, { ssize_t new_size; ssize_t data_size = _data_size; + const version_entry_st *vers; DECR_LEN(data_size, 2); if (data_size != 0) @@ -62,19 +63,35 @@ _gnutls_record_size_limit_recv_params(gnutls_session_t session, if (new_size < 64) return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); - /* we do not want to accept sizes less than our minimum */ - if (new_size < MIN_RECORD_SIZE) - return 0; + session->internals.hsk_flags |= HSK_RECORD_SIZE_LIMIT_RECEIVED; + + /* we do not want to accept sizes outside of our supported range */ + if (new_size < MIN_RECORD_SIZE) { + /* for server, reject it by omitting the extension in the reply */ + if (session->security_parameters.entity == GNUTLS_SERVER) { + _gnutls_handshake_log("EXT[%p]: client requested too small record_size_limit %u; ignoring\n", + session, (unsigned)new_size); + return gnutls_assert_val(0); + } else { + _gnutls_handshake_log("EXT[%p]: server requested too small record_size_limit %u; closing the connection\n", + session, (unsigned)new_size); + return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); + } + } session->internals.hsk_flags |= HSK_RECORD_SIZE_LIMIT_NEGOTIATED; - /* if a larger record size limit than the protocol limit is - * provided by the peer, ignore it and stick to the default */ - if (unlikely(new_size > DEFAULT_MAX_RECORD_SIZE)) - return gnutls_assert_val(0); + _gnutls_handshake_log("EXT[%p]: record_size_limit %u negotiated\n", + session, (unsigned)new_size); - session->security_parameters.max_record_send_size = new_size; - session->security_parameters.max_record_recv_size = new_size; + /* subtract 1 octet for content type */ + vers = get_version(session); + if (unlikely(vers == NULL)) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + session->security_parameters.max_record_recv_size = + MIN(new_size - vers->tls13_sem, + session->security_parameters.max_record_send_size); return 0; } @@ -86,15 +103,44 @@ _gnutls_record_size_limit_send_params(gnutls_session_t session, gnutls_buffer_st * extdata) { int ret; + uint16_t send_size; assert(session->security_parameters.max_record_send_size >= 64 && session->security_parameters.max_record_send_size <= DEFAULT_MAX_RECORD_SIZE); - ret = _gnutls_buffer_append_prefix(extdata, 16, - session->security_parameters.max_record_send_size); + send_size = session->security_parameters.max_record_send_size; + + if (session->security_parameters.entity == GNUTLS_SERVER) { + const version_entry_st *vers; + + /* if we had received the extension and rejected, don't send it */ + if (session->internals.hsk_flags & HSK_RECORD_SIZE_LIMIT_RECEIVED && + !(session->internals.hsk_flags & HSK_RECORD_SIZE_LIMIT_NEGOTIATED)) + return gnutls_assert_val(0); + + /* add 1 octet for content type */ + vers = get_version(session); + if (unlikely(vers == NULL)) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + send_size += vers->tls13_sem; + } else { + const version_entry_st *vers; + + /* add 1 octet for content type */ + vers = _gnutls_version_max(session); + if (unlikely(vers == NULL)) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + send_size += vers->tls13_sem; + } + + ret = _gnutls_buffer_append_prefix(extdata, 16, send_size); if (ret < 0) return gnutls_assert_val(ret); + session->internals.hsk_flags |= HSK_RECORD_SIZE_LIMIT_SENT; + return 2; } |