diff options
author | Daiki Ueno <ueno@gnu.org> | 2020-02-19 14:35:04 +0100 |
---|---|---|
committer | Daiki Ueno <ueno@gnu.org> | 2020-11-19 18:18:38 +0100 |
commit | e3d6a62938a5a53b89585ace73a13b0556f176a4 (patch) | |
tree | 85f9f33cafc7c19d5acad883b0b4a9ef17aa14b5 /lib/record.c | |
parent | 9f5dcddcaa6e89c3d0f9446fb7f2733f2933c3d9 (diff) | |
download | gnutls-e3d6a62938a5a53b89585ace73a13b0556f176a4.tar.gz |
handshake: add functions to read/write handshake messages directly
This adds a couple of functions, gnutls_handshake_set_read_function()
and gnutls_handshake_write(), to allow QUIC implementations to
directly interact with the TLS state machine.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
Diffstat (limited to 'lib/record.c')
-rw-r--r-- | lib/record.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/lib/record.c b/lib/record.c index faf53f5625..3a8f8e78cc 100644 --- a/lib/record.c +++ b/lib/record.c @@ -2340,3 +2340,74 @@ void gnutls_record_set_timeout(gnutls_session_t session, unsigned int ms) { session->internals.record_timeout_ms = ms; } + +/** + * gnutls_handshake_write: + * @session: is a #gnutls_session_t type. + * @level: the current encryption level for reading a handshake message + * @data: the (const) handshake data to be processed + * @data_size: the size of data + * + * This function processes a handshake message in the encryption level + * specified with @level. Prior to calling this function, a handshake + * read callback must be set on @session. Use + * gnutls_handshake_set_read_function() to do this. + * + * Since: 3.7.0 + */ +int +gnutls_handshake_write(gnutls_session_t session, + gnutls_record_encryption_level_t level, + const void *data, size_t data_size) +{ + record_parameters_st *record_params; + record_state_st *record_state; + mbuffer_st *bufel; + uint8_t *p; + int ret; + + /* DTLS is not supported */ + if (IS_DTLS(session)) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + /* When using this, the outgoing handshake messages should + * also be handled manually */ + if (!session->internals.h_read_func) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + if (session->internals.initial_negotiation_completed) { + const version_entry_st *vers = get_version(session); + if (unlikely(vers == NULL || !vers->tls13_sem)) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + } + + ret = _gnutls_epoch_get(session, EPOCH_READ_CURRENT, &record_params); + if (ret < 0) + return gnutls_assert_val(ret); + + record_state = &record_params->read; + if (record_state->level > level) + return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); + + bufel = _mbuffer_alloc_align16(data_size, 0); + if (bufel == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + memcpy(_mbuffer_get_udata_ptr(bufel), data, data_size); + _mbuffer_set_udata_size(bufel, data_size); + p = _mbuffer_get_udata_ptr(bufel); + bufel->htype = p[0]; + + if (sequence_increment(session, &record_state->sequence_number) != 0) { + _mbuffer_xfree(&bufel); + return gnutls_assert_val(GNUTLS_E_RECORD_LIMIT_REACHED); + } + + _gnutls_record_buffer_put(session, GNUTLS_HANDSHAKE, + record_state->sequence_number, bufel); + + if (session->internals.initial_negotiation_completed) + return _gnutls13_recv_async_handshake(session); + + return 0; +} |