The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
Data Structures | Macros | Functions | Variables
unit_test_tls.c File Reference

TLS server test framework. More...

#include <freeradius-devel/server/base.h>
#include <freeradius-devel/server/module_rlm.h>
#include <freeradius-devel/io/listen.h>
#include <freeradius-devel/io/thread.h>
#include <freeradius-devel/tls/base.h>
#include <freeradius-devel/tls/strerror.h>
#include <freeradius-devel/tls/version.h>
#include <freeradius-devel/tls/connection.h>
#include <freeradius-devel/unlang/base.h>
#include <freeradius-devel/unlang/function.h>
#include <freeradius-devel/unlang/interpret.h>
#include <freeradius-devel/util/socket.h>
#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
+ Include dependency graph for unit_test_tls.c:

Go to the source code of this file.

Data Structures

struct  unit_test_tls_conf_t
 The "unit_test_tls" section. More...
 
struct  unit_test_tls_t
 State of the test program. More...
 

Macros

#define EXIT_WITH_FAILURE
 

Functions

static void _request_detach (request_t *request, UNUSED void *uctx)
 
static void _request_done_detached (request_t *request, UNUSED rlm_rcode_t rcode, UNUSED void *uctx)
 
static void _request_done_external (request_t *request, UNUSED rlm_rcode_t rcode, UNUSED void *uctx)
 
static void _request_done_internal (request_t *request, UNUSED rlm_rcode_t rcode, UNUSED void *uctx)
 
static void _request_init_internal (request_t *request, void *uctx)
 An internal request created by the interpreter has to run on ours.
 
static void _request_resume (request_t *request, UNUSED void *uctx)
 
static void _request_runnable (request_t *request, void *uctx)
 
static bool _request_scheduled (request_t const *request, UNUSED void *uctx)
 
static void _request_yield (request_t *request, void *uctx)
 
static void _tls_connection_error (UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
 The connection failed at the socket level.
 
static void _tls_connection_read (UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
 A record arrived on the connection, so hand the record to the connection.
 
static void _tls_connection_start (fr_event_list_t *el, void *uctx)
 Add the connection to the event loop, and get it moving.
 
static void _tls_runnable (UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
 Drain the runnable heap once per pass of the event loop.
 
int main (int argc, char *argv[])
 
static fr_client_t * tls_client_alloc (TALLOC_CTX *ctx, fr_ipaddr_t const *ipaddr)
 Build an internal client.
 
static int tls_connection_run (unit_test_tls_t *utt)
 Run one connection from the first byte to the last.
 
static int tls_connection_write (void *uctx, fr_tls_connection_t *conn)
 Write whatever OpenSSL has produced out to the connection.
 
static request_t * tls_request_alloc (TALLOC_CTX *ctx, int fd)
 Build the request the handshake runs under.
 
static void tls_request_failed (unit_test_tls_t *utt)
 Record a failure this program cannot recover from, and stop.
 
static void tls_request_finished (void *uctx, fr_tls_connection_t *conn)
 Stop the event loop, recording why.
 
static void tls_runnable_insert (unit_test_tls_t *utt, request_t *request)
 Schedule a request, once.
 
static int tls_socket_connect (unit_test_tls_t *utt)
 Connect to the server named by -s.
 
static int tls_socket_open (unit_test_tls_t *utt)
 Open the listening socket described by the "unit_test_tls" section.
 
static void usage (main_config_t const *config, int status)
 

Variables

static fr_dict_t const * dict_freeradius
 
static fr_dict_t const * dict_tls
 
char const * radiusd_version = RADIUSD_VERSION_BUILD("unit_test_tls")
 
static const conf_parser_t unit_test_tls_config []
 
fr_dict_autoload_t unit_test_tls_dict []
 

Detailed Description

TLS server test framework.

Id
57ea0bacf592519657600199da53e554812a8b5c

This program loads the "tls" protocol and reads two top-level sections from unit_test_tls.conf. The "tls" section supplies the TLS server context, and takes exactly the items that a TLS configuration takes anywhere else in the server. The "unit_test_tls" section supplies what steers the test program itself, which is the address of the listening TCP socket and whether a client certificate is required.

One connection is accepted, and the TLS handshake for that connection is run to completion.

The handshake runs on a persistent asynchronous interpreter, the same way radiusd runs one. A persistent interpreter keeps the handshake state across the several rounds of a single connection.

The "virtual_server" item in the "tls" section names a virtual server. That virtual server supplies the "verify certificate", "load session", "store session" and "clear session" sections which the handshake calls.

To run the test, start unit_test_tls with the test configuration, then connect to the listening socket:

./scripts/bin/unit_test_tls -d src/tests/tls -X
openssl s_client -connect 127.0.0.1:2083 \
-cert raddb/certs/rsa/client.pem \
-key raddb/certs/rsa/client.key -pass pass:whatever \
-CAfile raddb/certs/rsa/ca.pem
#define X
Definition base.h:64

src/tests/tls/unit_test_tls.conf documents every configuration item.

Definition in file unit_test_tls.c.


Data Structure Documentation

◆ unit_test_tls_conf_t

struct unit_test_tls_conf_t

The "unit_test_tls" section.

These items steer the test program, and have nothing to do with TLS itself. Keeping them out of the "tls" section leaves that section holding only what fr_tls_conf_parse_server() understands.

Definition at line 105 of file unit_test_tls.c.

+ Collaboration diagram for unit_test_tls_conf_t:
Data Fields
fr_ipaddr_t ipaddr Address of the listening socket. Server mode only.
uint16_t port Port of the listening socket, and the default port for -s.
bool require_client_certificate Whether the client has to present a certificate.

◆ unit_test_tls_t

struct unit_test_tls_t

State of the test program.

The interpreter and the runnable heap live for the whole of the connection. A TLS handshake takes several rounds, and each round may yield while a virtual server section runs. The interpreter and the runnable heap therefore cannot be allocated once per round.

Definition at line 132 of file unit_test_tls.c.

+ Collaboration diagram for unit_test_tls_t:
Data Fields
bool alert Reject the peer with a TLS alert, see -A.
unit_test_tls_conf_t conf Parsed "unit_test_tls" section.
fr_tls_connection_t * conn State of the connection being run.
unsigned int connections How many connections have been run so far.
unsigned int count How many connections to run.
bool done Set once the connection has a result.
fr_event_fd_t * ef Read event for fd.
fr_event_list_t * el Event list everything runs on.
int fd Accepted or connected socket.
unlang_interpret_t * intp Interpreter for the connection.
bool reject Reject the session once the handshake succeeds, see -R.
int ret Exit status.
fr_heap_t * runnable Requests the interpreter has marked runnable.
fr_ipaddr_t server_ipaddr Server named by -s.
uint16_t server_port Port from -s, or from the configuration.
int sockfd Listening socket.
SSL_CTX * ssl_ctx Context built from the "tls" section.
int yielded How many requests are currently yielded.

Macro Definition Documentation

◆ EXIT_WITH_FAILURE

#define EXIT_WITH_FAILURE
Value:
do { \
ret = EXIT_FAILURE; \
goto cleanup; \
} while (0)
static bool cleanup
Definition radsniff.c:59

Definition at line 81 of file unit_test_tls.c.

Function Documentation

◆ _request_detach()

static void _request_detach ( request_t *  request,
UNUSED void *  uctx 
)
static

Definition at line 239 of file unit_test_tls.c.

+ Here is the call graph for this function:

◆ _request_done_detached()

static void _request_done_detached ( request_t *  request,
UNUSED rlm_rcode_t  rcode,
UNUSED void *  uctx 
)
static

Definition at line 228 of file unit_test_tls.c.

+ Here is the call graph for this function:

◆ _request_done_external()

static void _request_done_external ( request_t *  request,
UNUSED rlm_rcode_t  rcode,
UNUSED void *  uctx 
)
static

Definition at line 210 of file unit_test_tls.c.

◆ _request_done_internal()

static void _request_done_internal ( request_t *  request,
UNUSED rlm_rcode_t  rcode,
UNUSED void *  uctx 
)
static

Definition at line 221 of file unit_test_tls.c.

◆ _request_init_internal()

static void _request_init_internal ( request_t *  request,
void *  uctx 
)
static

An internal request created by the interpreter has to run on ours.

The subrequests created for the "verify certificate" section and for the session cache sections reach this callback.

fr_tls_call_push() pushes each of them as a detachable subrequest, which the parent waits on rather than running inline, so the subrequest has to be scheduled here or nothing ever runs it.

Definition at line 194 of file unit_test_tls.c.

+ Here is the call graph for this function:

◆ _request_resume()

static void _request_resume ( request_t *  request,
UNUSED void *  uctx 
)
static

Definition at line 255 of file unit_test_tls.c.

◆ _request_runnable()

static void _request_runnable ( request_t *  request,
void *  uctx 
)
static

Definition at line 260 of file unit_test_tls.c.

+ Here is the call graph for this function:

◆ _request_scheduled()

static bool _request_scheduled ( request_t const *  request,
UNUSED void *  uctx 
)
static

Definition at line 270 of file unit_test_tls.c.

+ Here is the call graph for this function:

◆ _request_yield()

static void _request_yield ( request_t *  request,
void *  uctx 
)
static

Definition at line 246 of file unit_test_tls.c.

◆ _tls_connection_error()

static void _tls_connection_error ( UNUSED fr_event_list_t *  el,
UNUSED int  fd,
UNUSED int  flags,
int  fd_errno,
void *  uctx 
)
static

The connection failed at the socket level.

Definition at line 406 of file unit_test_tls.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _tls_connection_read()

static void _tls_connection_read ( UNUSED fr_event_list_t *  el,
int  fd,
UNUSED int  flags,
void *  uctx 
)
static

A record arrived on the connection, so hand the record to the connection.

Reading the socket is all this program does here. Everything the record means to TLS is fr_tls_connection_recv()'s business.

Definition at line 358 of file unit_test_tls.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _tls_connection_start()

static void _tls_connection_start ( fr_event_list_t *  el,
void *  uctx 
)
static

Add the connection to the event loop, and get it moving.

Runs from inside the event loop, see tls_connection_run().

Definition at line 646 of file unit_test_tls.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _tls_runnable()

static void _tls_runnable ( UNUSED fr_event_list_t *  el,
UNUSED fr_time_t  now,
void *  uctx 
)
static

Drain the runnable heap once per pass of the event loop.

A handshake round yields whenever the round runs a virtual server section. When that section finishes, unlang_interpret_mark_runnable() puts the request on the runnable heap, and this drains the heap again.

Definition at line 420 of file unit_test_tls.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 804 of file unit_test_tls.c.

◆ tls_client_alloc()

static fr_client_t * tls_client_alloc ( TALLOC_CTX *  ctx,
fr_ipaddr_t const *  ipaddr 
)
static

Build an internal client.

unit_test_tls accepts packets from anywhere (for now), and doesn't read "client" configuration sections.

The client is built by allocating a CONF_SECTION rather than by filling in fr_client_t manually, which allows fields to be examined by request.client().

"proto = tls" sets both the protocol and tls_required. It also fixes the secret at "radsec", so that is the secret set here.

Definition at line 537 of file unit_test_tls.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_connection_run()

static int tls_connection_run ( unit_test_tls_t *  utt)
static

Run one connection from the first byte to the last.

Everything which belongs to a single connection is allocated here and freed again at the end, so that the next connection starts clean. What survives is what the cache needs: the interpreter, the modules, and so the sessions a policy stored.

Definition at line 676 of file unit_test_tls.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_connection_write()

static int tls_connection_write ( void *  uctx,
fr_tls_connection_t *  conn 
)
static

Write whatever OpenSSL has produced out to the connection.

The TLS session reads and writes memory BIOs, which are OpenSSL's in-memory I/O buffers, and never a socket. Writing each record to the socket is therefore the caller's job. The EAP code in src/lib/eap/tls.c writes records the same way.

Definition at line 312 of file unit_test_tls.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_request_alloc()

static request_t * tls_request_alloc ( TALLOC_CTX *  ctx,
int  fd 
)
static

Build the request the handshake runs under.

The TLS code reads the control list for TLS-Session-Cert-File and TLS-Session-Require-Client-Certificate, and writes the negotiated version and cipher suite into the session-state list, so a real request is needed.

Definition at line 579 of file unit_test_tls.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_request_failed()

static void tls_request_failed ( unit_test_tls_t *  utt)
static

Record a failure this program cannot recover from, and stop.

tls_request_finished() reads the result from the connection, so a failure has to reach the connection before the callback runs.

Definition at line 299 of file unit_test_tls.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_request_finished()

static void tls_request_finished ( void *  uctx,
fr_tls_connection_t *  conn 
)
static

Stop the event loop, recording why.

The connection carries the result, so the exit status is decided here rather than by the state machine. A process exit status is this program's notion of a result, and no part of a TLS connection should have to know about one.

Definition at line 282 of file unit_test_tls.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_runnable_insert()

static void tls_runnable_insert ( unit_test_tls_t *  utt,
request_t *  request 
)
static

Schedule a request, once.

A request reaches the heap from two directions: the interpreter creating it, and the interpreter marking it runnable again. Inserting a request which is already on the heap puts it there twice, and popping it then returns a request which the heap still holds, which the interpreter refuses to run.

Definition at line 178 of file unit_test_tls.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_socket_connect()

static int tls_socket_connect ( unit_test_tls_t *  utt)
static

Connect to the server named by -s.

Definition at line 507 of file unit_test_tls.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ tls_socket_open()

static int tls_socket_open ( unit_test_tls_t *  utt)
static

Open the listening socket described by the "unit_test_tls" section.

Definition at line 463 of file unit_test_tls.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ usage()

static NEVER_RETURNS void usage ( main_config_t const *  config,
int  status 
)
static

Definition at line 1351 of file unit_test_tls.c.

Variable Documentation

◆ dict_freeradius

fr_dict_t const* dict_freeradius
static

Definition at line 89 of file unit_test_tls.c.

◆ dict_tls

fr_dict_t const* dict_tls
static

Definition at line 90 of file unit_test_tls.c.

◆ radiusd_version

char const* radiusd_version = RADIUSD_VERSION_BUILD("unit_test_tls")

Definition at line 87 of file unit_test_tls.c.

◆ unit_test_tls_config

const conf_parser_t unit_test_tls_config[]
static
Initial value:
= {
{ FR_CONF_OFFSET("require_client_certificate", unit_test_tls_conf_t, require_client_certificate),
.dflt = "no" },
}
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:673
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:280
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:238
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
The "unit_test_tls" section.

Definition at line 112 of file unit_test_tls.c.

◆ unit_test_tls_dict

fr_dict_autoload_t unit_test_tls_dict
Initial value:
= {
{ .out = &dict_freeradius, .proto = "freeradius" },
{ .out = &dict_tls, .proto = "tls" },
}
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:335
static fr_dict_t const * dict_freeradius
static fr_dict_t const * dict_tls

Definition at line 93 of file unit_test_tls.c.