51#include <freeradius-devel/server/base.h>
53#include <freeradius-devel/tls/base.h>
54#include <freeradius-devel/tls/connection.h>
56#include <freeradius-devel/unlang/interpret.h>
58#include <freeradius-devel/bio/bio_priv.h>
59#include <freeradius-devel/bio/fd.h>
60#include <freeradius-devel/bio/tls.h>
124 if (!my->events || (my->write_wait == wait))
return 0;
131 my->write_wait = wait;
141 if (!my->events)
return;
148 my->write_wait =
false;
159 if (this->priv_cb.write_resume) (void) this->priv_cb.write_resume(next);
171 my->conn->failed = reason;
172 my->conn->error = error;
177 if (my->cb.failed) my->cb.failed(&my->bio);
200 fr_bio_tls_t *my = talloc_get_type_abort(conn->uctx, fr_bio_tls_t);
208 if (my->write_blocked)
return 0;
214 slen = next->
write(next, my->packet_ctx,
data, size);
216 if ((
size_t) slen == size) {
230 my->write_blocked =
true;
245 if (slen ==
fr_bio_error(IO_WOULD_BLOCK)) errno = EAGAIN;
247 switch (fr_tls_connection_io_error(conn, slen)) {
248 case FR_TLS_CONNECTION_IO_RETRY:
251 case FR_TLS_CONNECTION_IO_BLOCKED:
252 my->write_blocked =
true;
259 case FR_TLS_CONNECTION_IO_OK:
260 case FR_TLS_CONNECTION_IO_EOF:
261 case FR_TLS_CONNECTION_IO_FATAL:
279 fr_bio_tls_t *my = talloc_get_type_abort(conn->uctx, fr_bio_tls_t);
286 if (my->cb.connected) my->cb.connected(&my->bio);
296 fr_bio_tls_t *my = talloc_get_type_abort(conn->uctx, fr_bio_tls_t);
303 if (my->cb.failed) my->cb.failed(&my->bio);
315 fr_tls_session_t *tls_session = my->conn->tls_session;
317 if (fr_tls_connection_write(my->conn) < 0)
return (
int) my->next_error;
329 fr_bio_tls_t *my = talloc_get_type_abort(bio, fr_bio_tls_t);
335 fr_assert((my->conn->state != TLS_CONNECTION_CONNECTED) ||
338 my->write_blocked =
true;
352 fr_bio_tls_t *my = talloc_get_type_abort(bio, fr_bio_tls_t);
358 my->write_blocked =
false;
361 if (rcode <= 0)
return rcode;
363 if (!my->cb.write_resume)
return 1;
365 return my->cb.write_resume(bio);
384 fr_tls_session_t *tls_session = my->conn->tls_session;
394 if (my->write_blocked) {
405 if (rcode < 0)
return rcode;
409 while (written < size) {
410 size_t chunk = size - written;
420 if (fr_tls_session_send(my->conn->request, tls_session) < 0) {
433 if (rcode == 1)
continue;
448 fr_bio_tls_t *my = talloc_get_type_abort(bio, fr_bio_tls_t);
459 my->write_blocked =
false;
477 my->packet_ctx = NULL;
487 fr_tls_session_t *tls_session = my->conn->tls_session;
490 (SSL_pending(tls_session->ssl) > 0);
502 fr_tls_session_t *tls_session = my->conn->tls_session;
505 rcode = fr_tls_session_recv(my->conn->request, tls_session);
516 if (rcode == 1)
return 0;
519 my->clean_offset = 0;
527 if (rcode < 0)
return rcode;
538 size_t used = my->clean_len - my->clean_offset;
543 my->clean_offset += size;
561 fr_bio_tls_t *my = talloc_get_type_abort(bio, fr_bio_tls_t);
562 fr_tls_connection_t *conn = my->conn;
563 fr_tls_session_t *tls_session = conn->tls_session;
582 if (rcode < 0)
return rcode;
585 if (my->clean_len > 0)
continue;
591 if ((SSL_get_shutdown(tls_session->ssl) & SSL_RECEIVED_SHUTDOWN) != 0) {
610 if (room >
sizeof(my->buffer)) room =
sizeof(my->buffer);
623 if (rcode ==
fr_bio_error(IO_WOULD_BLOCK)) errno = EAGAIN;
625 switch (fr_tls_connection_io_error(conn, rcode)) {
626 case FR_TLS_CONNECTION_IO_RETRY:
632 case FR_TLS_CONNECTION_IO_BLOCKED:
633 case FR_TLS_CONNECTION_IO_OK:
634 case FR_TLS_CONNECTION_IO_EOF:
635 case FR_TLS_CONNECTION_IO_FATAL:
655 fr_bio_tls_t *my = talloc_get_type_abort(bio, fr_bio_tls_t);
667 if (rcode < 0)
return rcode;
668 if (rcode == 0)
break;
675 my->priv_cb.eof = NULL;
691 fr_bio_tls_t *my = talloc_get_type_abort(bio, fr_bio_tls_t);
696 if (my->conn->state != TLS_CONNECTION_CONNECTED)
return 1;
714 fr_bio_tls_t *my = talloc_get_type_abort(bio, fr_bio_tls_t);
736 if (size == SIZE_MAX)
return 0;
748 fr_bio_tls_t *my = talloc_get_type_abort(uctx, fr_bio_tls_t);
753 slen = next->
read(next, NULL, my->buffer,
sizeof(my->buffer));
755 fr_tls_connection_recv(my->conn, my->buffer, (
size_t) slen);
763 if (slen ==
fr_bio_error(IO_WOULD_BLOCK)) errno = EAGAIN;
770 if (fr_tls_connection_io_error(my->conn, slen) != FR_TLS_CONNECTION_IO_RETRY)
return;
784 fr_bio_tls_t *my = talloc_get_type_abort(uctx, fr_bio_tls_t);
795 my->write_blocked =
false;
798 fr_tls_connection_process(my->conn);
806 fr_bio_tls_t *my = talloc_get_type_abort(uctx, fr_bio_tls_t);
809 (void) fr_tls_connection_io_error(my->conn, 0);
818 (void) fr_tls_connection_io_error(my->conn, -1);
833 fr_tls_connection_t *conn = my->conn;
847 if (!conn->name)
return -1;
851 conn->tls_session = fr_tls_session_alloc_client(
request, my->ssl_ctx,
request);
853 conn->tls_session = fr_tls_session_alloc_server(
request, my->ssl_ctx,
request, my->client_cert);
855 if (!conn->tls_session)
return -1;
861 if (info->
socket.
type == SOCK_DGRAM) conn->tls_session->cookie = &info->
socket;
875 my->write_wait =
true;
881 if (fr_tls_connection_push(conn) < 0) {
897 fr_tls_connection_wake(conn);
910 if (!prev)
return NULL;
912 return talloc_get_type_abort(prev, fr_bio_tls_t);
962 if (my->conn->state != TLS_CONNECTION_CONNECTED)
return;
963 if (my->conn->failed != TLS_CONNECTION_FAIL_NONE)
return;
969 fr_tls_session_close_send(my->conn->request, my->conn->tls_session);
993 my->cb.failed = NULL;
997 my->write_wait =
false;
1041 if (!talloc_check_name(next,
"fr_bio_fd_t")) {
1046 my = talloc_zero(
request, fr_bio_tls_t);
1047 if (!my)
return NULL;
1050 my->ssl_ctx = ssl_ctx;
1051 my->client = client;
1052 my->client_cert = client_cert;
1061 my->conn->uctx = my;
1062 my->conn->client = client;
static int const char char buffer[256]
fr_bio_write_t _CONST write
write to the underlying bio
static fr_bio_t * fr_bio_prev(fr_bio_t *bio)
fr_bio_read_t _CONST read
read from the underlying bio
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
static void fr_bio_tls_events_delete(fr_bio_tls_t *my)
Stop owning the events of the fd.
void fr_bio_tls_close_send(fr_bio_tls_t *my)
Send a TLS close_notify alert to the peer.
static void fr_bio_tls_el_write(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
The fd is ready for writes.
static void fr_bio_tls_conn_connected(fr_tls_connection_t *conn)
The TLS connection can carry application data.
size_t clean_offset
How much of the decrypted data the caller has read.
static ssize_t fr_bio_tls_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Read encrypted data from the next bio, and return the decrypted application data.
static void fr_bio_tls_conn_close(fr_tls_connection_t *conn)
The TLS connection failed.
static ssize_t fr_bio_tls_read_wait(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
Application data cannot move until the connection is connected.
bool client
Act as the client, and connect to a server.
fr_tls_connection_t * fr_bio_tls_conn(fr_bio_tls_t *my)
The TLS connection, so the caller can set conn->name
void * packet_ctx
Passed to the next bio when writing encrypted records.
bool events
The bio owns the events of the fd, which it has until the connection is connected.
static int fr_bio_tls_write_blocked(fr_bio_t *bio)
Record that the next bio is blocked.
static int fr_bio_tls_write_wait(fr_bio_tls_t *my, bool wait)
Start or stop waiting for the fd to have room for more records.
static ssize_t fr_bio_tls_write_data(fr_bio_tls_t *my, void const *buffer, size_t size)
Encrypt application data, and write the encrypted records to the next bio.
size_t clean_len
How much decrypted data is in clean_out.
static bool fr_bio_tls_pending(fr_bio_tls_t *my)
Check whether OpenSSL holds data which the bio has not yet processed.
static int fr_bio_tls_decrypt(fr_bio_tls_t *my)
Decrypt one record which is waiting in OpenSSL.
static void fr_bio_tls_fd_connected(fr_bio_t *fd_bio)
The fd is connected.
static fr_event_update_t const resume_write[]
ssize_t next_error
The error which the next bio returned from a write.
bool write_wait
The write event of the fd is active.
static ssize_t fr_bio_tls_write_wait_connected(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, size_t size)
int fd
The fd of the next bio.
static void fr_bio_tls_failed(fr_bio_tls_t *my, fr_tls_connection_fail_t reason, int error)
Stop the connection, and tell the application.
static void fr_bio_tls_fd_error(fr_bio_t *fd_bio)
The fd failed to connect.
SSL_CTX * ssl_ctx
Used to create the TLS session.
static void fr_bio_tls_el_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
The fd failed.
static int fr_bio_tls_write_resume(fr_bio_t *bio)
Write the encrypted records which were waiting for the next bio.
bool write_blocked
The next bio is blocked.
static ssize_t fr_bio_tls_read_eof(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Return the decrypted data which remains after the next bio reached EOF, and then return EOF.
static int fr_bio_tls_eof(fr_bio_t *bio)
Handle EOF from the next bio.
int fr_bio_tls_connect(fr_bio_tls_t *my)
Take the connection through every state which comes before application data.
static void fr_bio_tls_el_read(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
A record arrived on the fd, so hand the record to the TLS connection.
fr_bio_tls_t * fr_bio_tls_alloc(request_t *request, fr_bio_t *next, SSL_CTX *ssl_ctx, bool client, bool client_cert)
Allocate a TLS bio.
bool client_cert
For a server, require a client certificate.
static int fr_bio_tls_flush(fr_bio_tls_t *my)
Write any pending encrypted records to the next bio.
uint8_t buffer[SSL3_RT_MAX_PLAIN_LENGTH]
Encrypted data read from the next bio.
static int fr_bio_tls_shutdown(fr_bio_t *bio)
Disconnect the bio from the fd.
fr_tls_connection_t * conn
The TLS connection, which is a child of the bio.
static size_t fr_bio_tls_clean_read(fr_bio_tls_t *my, void *buffer, size_t size)
Copy decrypted data which the caller has not yet read into the caller's buffer.
static int fr_bio_tls_destructor(fr_bio_tls_t *my)
Send any close_notify, stop the fd events, cancel the request, and then run the common bio destructor...
static int fr_bio_tls_handshake_start(fr_bio_tls_t *my)
The fd is connected, so start the TLS connection.
static ssize_t fr_bio_tls_conn_write(fr_tls_connection_t *conn, uint8_t const *data, size_t size)
Write encrypted records to the next bio.
static fr_bio_tls_t * fr_bio_tls_from_fd(fr_bio_t *fd_bio)
Find the TLS bio from the fd bio.
static void fr_bio_tls_next_resume(fr_bio_t *next)
Tell the next bio that it can write again.
fr_event_list_t * el
The event list of the interpreter.
static fr_event_update_t const pause_write[]
static ssize_t fr_bio_tls_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
static int packet_ctx
the tests pass only the address of packet_ctx
static uint8_t request[4]
static void fr_bio_chain(fr_bio_t *first, fr_bio_t *second)
Chain one bio after another.
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
#define fr_event_fd_insert(...)
#define fr_event_filter_update(...)
#define FR_EVENT_RESUME(_s, _f)
Re-add the filter for a func from kevent.
#define FR_EVENT_SUSPEND(_s, _f)
Temporarily remove the filter for a func from kevent.
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Callbacks for the FR_EVENT_FILTER_IO filter.
Structure describing a modification to a filter's state.
int fr_bio_fd_connect_full(fr_bio_t *bio, fr_event_list_t *el, fr_bio_callback_t connected_cb, fr_bio_callback_t error_cb, fr_time_delta_t *timeout, fr_bio_callback_t timeout_cb)
Finalize a connect()
fr_bio_fd_info_t const * fr_bio_fd_info(fr_bio_t *bio)
Returns a pointer to the bio-specific information.
fr_socket_t socket
as connected socket
char const * name
printable name of this BIO
fr_bio_fd_state_t state
connecting, open, closed, etc.
@ FR_BIO_FD_STATE_OPEN
error states must be before this
Run-time status of the socket.
rlm_rcode_t unlang_interpret(request_t *request, bool running)
Run the interpreter for a current request.
void unlang_interpret_signal(request_t *request, fr_signal_t action)
Send a signal (usually stop) to a request.
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
#define UNLANG_REQUEST_RESUME
int fr_bio_write_blocked(fr_bio_t *bio)
Internal BIO function to tell all BIOs that it's blocked.
ssize_t fr_bio_shutdown_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
int fr_bio_destructor(fr_bio_t *bio)
Free this bio.
ssize_t fr_bio_shutdown_write(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
fr_bio_t * fr_bio_eof(fr_bio_t *bio)
Internal BIO function to run EOF callbacks.
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
Stores all information relating to an event list.
@ FR_SIGNAL_CANCEL
Request has been cancelled.
static fr_event_list_t * el
int fd
File descriptor if this is a live socket.
int type
SOCK_STREAM, SOCK_DGRAM, etc.
#define fr_strerror_const_push(_msg)
#define fr_strerror_const(_msg)