71RCSID(
"$Id: 9b3b7894540917f75cd3571469ee4cad8acdb421 $")
74#include <freeradius-devel/unlang/action.h>
75#include <freeradius-devel/unlang/function.h>
76#include <freeradius-devel/server/pair.h>
115 fr_dbuff_t *record,
size_t record_len,
size_t frag_len)
126 RDEBUG3(
"Setting flags %c%c%c%c%c%c%c%c",
144 if (record)
len += frag_len;
148 if (record_len != 0)
len += frag_len;
184 net_record_len = htonl(record_len);
185 memcpy(p, &net_record_len,
sizeof(net_record_len));
186 p +=
sizeof(net_record_len);
281 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
298 if (!prf_label)
return fr_tls_ticket_issue(
request, tls_session);
310 &session_id, eap_session->
type) < 0) {
320 return fr_tls_ticket_issue(
request, tls_session);
342 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
349 eap_tls_session->
base_flags, NULL, 0, 0) < 0) {
350 REDEBUG(
"Failed composing EAP-Failure");
358 return fr_tls_session_fail_session(
request, tls_session,
true);
395 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
398 bool length_included;
433 RDEBUG2(
"Complete TLS record (%zu bytes) larger than MTU (%zu bytes), will fragment",
435 RDEBUG2(
"Sending first TLS record fragment (%zu bytes), %zu bytes remaining",
438 RDEBUG2(
"Sending additional TLS record fragment (%zu bytes), %zu bytes remaining",
450 RDEBUG2(
"Sending complete TLS record (%zu bytes)", frag_len);
452 RDEBUG2(
"Sending final TLS record fragment (%zu bytes)", frag_len);
490 RDEBUG2(
"ACKing Peer's TLS record fragment");
507 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
509 if (tls_session == NULL){
510 REDEBUG(
"Unexpected ACK received: No ongoing SSL tls_session");
513 if (!tls_session->info.initialized) {
514 RDEBUG2(
"No SSL info available. Waiting for more SSL data");
518 if ((tls_session->info.content_type == SSL3_RT_HANDSHAKE) &&
519 (tls_session->info.origin == TLS_INFO_ORIGIN_RECORD_RECEIVED)) {
520 REDEBUG(
"Unexpected ACK received: We sent no previous messages");
524 switch (tls_session->info.content_type) {
526 RDEBUG2(
"Peer ACKed our alert");
529 case SSL3_RT_HANDSHAKE:
530 if (fr_tls_session_is_init_finished(tls_session) && (
fr_dbuff_remaining(tls_session->dirty_out) == 0)) {
531 RDEBUG2(
"Peer ACKed our handshake fragment. handshake is finished");
538 tls_session->info.content_type = SSL3_RT_APPLICATION_DATA;
542 RDEBUG2(
"Peer ACKed our handshake fragment");
546 case SSL3_RT_APPLICATION_DATA:
547 RDEBUG2(
"Peer ACKed our application data fragment");
559 if (tls_session->info.origin == TLS_INFO_ORIGIN_RECORD_SENT) {
563 REDEBUG(
"Invalid ACK received: %d", tls_session->info.content_type);
591 size_t frag_len, header_len;
599 REDEBUG(
"Invalid EAP-TLS packet: Expected at least %zu bytes got %zu bytes",
615 REDEBUG(
"Invalid EAP-TLS packet; no data");
622 RDEBUG3(
"Peer sent flags %c%c%c%c%c%c%c%c",
638 REDEBUG(
"Invalid EAP-TLS packet: Expected at least %zu bytes got %zu bytes",
652 ((eap_tls_data->
flags & 0xc0) == 0x00)) {
654 REDEBUG(
"Received Invalid TLS ACK");
664 REDEBUG(
"Peer sent EAP-TLS Start message (only the server is allowed to do this)");
677 REDEBUG(
"Peer sent EAP-TLS with zero-length fragment and 'more' bit set - if there is no data, there should not be more!");
697 if (eap_tls_data->
data[0] || eap_tls_data->
data[1]) {
698 REDEBUG(
"TLS record length is > 65536");
702 total_len = eap_tls_data->
data[2] * 256 | eap_tls_data->
data[3];
703 if (frag_len > total_len) {
704 REDEBUG(
"TLS fragment length (%zu bytes) greater than TLS record length (%zu bytes)",
705 frag_len, total_len);
709 if (total_len > SSL3_RT_MAX_PLAIN_LENGTH) {
710 REDEBUG(
"Reassembled TLS record will be %zu bytes, "
711 "greater than our maximum record size (" STRINGIFY(SSL3_RT_MAX_PLAIN_LENGTH)
" bytes)",
730 RDEBUG2(
"Peer indicated complete TLS record size will be %zu bytes", total_len);
741 RDEBUG2(
"Expecting %i TLS record fragments",
742 (
int)((((total_len - frag_len) + ((frag_len + 4) - 1)) / (frag_len + 4)) + 1));
749 RDEBUG2(
"Got first TLS record fragment (%zu bytes). Peer indicated more fragments "
750 "to follow", frag_len);
761 if (total_len != frag_len) {
762 REDEBUG(
"Peer indicated no more fragments, but TLS record length (%zu bytes) "
763 "does not match EAP-TLS data length (%zu bytes)", total_len, frag_len);
773 RDEBUG2(
"Got complete TLS record, with length field (%zu bytes)", frag_len);
784 REDEBUG(
"TLS More (M) flag set, but no fragmented record transfer was in progress");
792 RDEBUG2(
"Got additional TLS record fragment (%zu bytes). Peer indicated more fragments to follow",
796 REDEBUG(
"Total received TLS record fragments (%zu bytes), exceeds "
797 "indicated TLS record length (%zu bytes)",
815 RDEBUG2(
"Got final TLS record fragment (%zu bytes)", frag_len);
818 REDEBUG(
"Total received TLS record fragments (%zu bytes), does not equal indicated "
819 "TLS record length (%zu bytes)",
830 RDEBUG2(
"Got complete TLS record (%zu bytes)", frag_len);
848 fr_tls_session_t *tls_session = talloc_get_type_abort(eap_tls_session->
tls_session, fr_tls_session_t);
851 switch (tls_session->result) {
852 case FR_TLS_RESULT_IN_PROGRESS:
857 case FR_TLS_RESULT_ERROR:
858 REDEBUG(
"TLS receive handshake failed during operation");
861 case FR_TLS_RESULT_SUCCESS:
888 if ((tls_session->info.version == TLS1_3_VERSION) &&
889 (tls_session->peer_cert_ok || eap_tls_session->
authentication_success || SSL_session_reused(tls_session->ssl))) {
897 if (!tls_session->sent_commitment) {
898 RDEBUG2(
"(TLS) EAP Sending final Commitment Message.");
900 tls_session->sent_commitment =
true;
906 if (SSL_is_init_finished(tls_session->ssl)) fr_tls_session_send(
request, tls_session);
912 ret = fr_tls_session_async_handshake_push(
request, tls_session);
915 REDEBUG(
"TLS receive handshake failed during operation");
934 if (tls_session->seen_application_data &&
fr_dbuff_used(&tls_session->clean_out) > 0)
goto phase2;
937 REDEBUG(
"TLS failed composing a response");
952 if (eap_tls_session->
phase2 || fr_tls_session_is_init_finished(tls_session)) {
954 eap_tls_session->
phase2 =
true;
960 tls_session->info.content_type = SSL3_RT_APPLICATION_DATA;
968 REDEBUG(
"TLS failed during operation");
994 fr_tls_session_t *tls_session = talloc_get_type_abort(eap_tls_session->
tls_session, fr_tls_session_t);
1043 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
1053 RDEBUG2(
"Continuing EAP-TLS");
1059 switch (eap_tls_session->
state) {
1075 switch (eap_tls_session->
state) {
1111 REDEBUG(
"Exceeded maximum record size");
1133 if (eap_tls_session->
phase2 || fr_tls_session_is_init_finished(tls_session)) {
1136 eap_tls_session->
phase2 =
true;
1138 ret = fr_tls_session_recv(
request, tls_session);
1168 fr_tls_session_is_init_finished(tls_session)) {
1169 eap_tls_session->
phase2 =
true;
1216 SSL_CTX *ssl_ctx,
bool client_cert)
1219 fr_tls_session_t *tls_session;
1220 fr_tls_conf_t *
conf = fr_tls_ctx_conf(ssl_ctx);
1229 eap_session->
tls =
true;
1266 SSL_CTX_set_max_early_data(ssl_ctx, 0);
1276 eap_tls_session->
tls_session = tls_session = fr_tls_session_alloc_server(eap_tls_session, ssl_ctx,
1278 if (
unlikely(!tls_session))
return NULL;
1285 switch (eap_session->
type) {
1287 tls_session->disallow_stateless_tickets =
true;
1301 tls_session->mtu =
conf->fragment_size - 10;
1302 if (
vp && (
vp->vp_uint32 > 100) && (
vp->vp_uint32 < tls_session->mtu)) {
1303 RDEBUG2(
"Setting fragment_len from %pP",
vp);
1304 tls_session->mtu =
vp->vp_uint32;
1315 RDEBUG2(
"Nested inside another EAP method, lowering fragment_len to %zu", tls_session->mtu);
1327 fr_tls_session_extra_pair_add_shallow(tls_session, identity);
1337 type_vp->vp_uint32 = eap_session->
type;
1338 fr_tls_session_extra_pair_add_shallow(tls_session, type_vp);
1344 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_EAP_SESSION, (
void *)eap_session);
1345 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_TLS_SESSION, (
void *)tls_session);
1346 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_CONF, (
void *)
conf);
1347 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_IDENTITY, (
void *)&(eap_session->
identity));
1351 if (tls_max && tls_min && (tls_min->vp_float32 > tls_max->vp_float32)) {
1352 RERROR(
"Can't set TLS min version greater than max version");
1353 goto skip_tls_version;
1356#define SET_TLS_VERSION(_type) \
1357 if (tls_ ## _type) { \
1358 int tls_version = 0; \
1359 if (tls_ ## _type->vp_float32 >= (float) 1.3) { \
1360 tls_version = TLS1_3_VERSION; \
1361 } else if (tls_ ## _type->vp_float32 >= (float) 1.2) { \
1362 tls_version = TLS1_2_VERSION; \
1363 } else if (tls_ ## _type->vp_float32 >= (float) 1.1) { \
1364 tls_version = TLS1_1_VERSION; \
1366 if (tls_version) { \
1367 if (SSL_set_ ## _type ## _proto_version(tls_session->ssl, tls_version) != 1) {\
1368 RERROR("Failed to set %pP", tls_ ## _type); \
1370 RDEBUG2("Setting TLS " #_type " version to %0.1f", (double) tls_ ## _type->vp_float32); \
1373 RWARN("Invalid value %pP", tls_ ## _type); \
1381 return eap_tls_session;
1405 if (!tls_conf->cache.min_lifetime_is_set ||
1415 tls_conf->delayed_tickets = delayed_tickets;
1437 if ((tls_conf->tls_max_version > 0) && (tls_conf->tls_max_version < (
float)1.3))
return 0;
1439 if (!(tls_conf->cache.mode & FR_TLS_TICKET_STATELESS))
return 0;
1441 if (tls_conf->cache.mode == FR_TLS_TICKET_AUTO) {
1443 "and are not used with TLS 1.3");
1447 cf_log_err_by_child(cs,
"tls",
"session.mode = \"stateless\" does not work with this EAP method, "
1448 "which does not use stateless session tickets with TLS 1.3.");
1454 if (tls_conf->cache.mode_is_auto) {
1455 cf_log_warn_by_child(cs,
"tls",
"Add a 'store session { ... }' section to save stateful tickets, or");
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
static uint8_t request[4]
#define USES_APPLE_DEPRECATED_API
#define L(_str)
Helper for initialising arrays of string literals.
A section grouping multiple CONF_PAIR.
#define cf_log_err_by_child(_parent, _child, _fmt,...)
Log an error message against a specified child.
#define cf_log_warn_by_child(_parent, _child, _fmt,...)
Log a warning message against a specified child.
eap_packet_t * response
Packet we received from the peer.
eap_packet_t * request
Packet we will send to the peer.
Contains a pair of request and response packets.
static size_t min(size_t x, size_t y)
#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_out_memcpy(_out, _dbuff_or_marker, _outlen)
Copy exactly _outlen bytes from the dbuff.
#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_bytes(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker.
#define fr_dbuff_in_memcpy_partial(_out, _in, _inlen)
Copy at most _inlen bytes into the dbuff.
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
unlang_action_t eap_tls_success(request_t *request, eap_session_t *eap_session, eap_tls_prf_label_t *prf_label)
Send an EAP-TLS success.
static eap_tls_status_t eap_tls_verify(request_t *request, eap_session_t *eap_session)
Check that this EAP-TLS packet is correct and the progression of EAP-TLS packets is sane.
eap_tls_session_t * eap_tls_session_init(request_t *request, eap_session_t *eap_session, SSL_CTX *ssl_ctx, bool client_cert)
Create a new fr_tls_session_t associated with an eap_session_t.
static unlang_action_t eap_tls_handshake_push(request_t *request, eap_session_t *eap_session)
Push functions to continue the handshake asynchronously.
static int eap_tls_ack(request_t *request, eap_session_t *eap_session)
ACK a fragment of the TLS record from the peer.
void eap_tls_conf_check(CONF_SECTION *cs, fr_tls_conf_t *tls_conf, bool delayed_tickets)
Apply the limits that EAP puts on a parsed tls { ... } section.
size_t eap_tls_status_table_len
int eap_tls_compose(request_t *request, eap_session_t *eap_session, eap_tls_status_t status, uint8_t flags, fr_dbuff_t *record, size_t record_len, size_t frag_len)
Convert the EAP-TLS reply packet into an EAP packet.
int eap_tls_start(request_t *request, eap_session_t *eap_session)
Send an initial EAP-TLS request to the peer.
int eap_tls_request(request_t *request, eap_session_t *eap_session)
Frames the OpenSSL data that needs to be sent to the client in an EAP-Request.
#define SET_TLS_VERSION(_type)
int eap_tls_check_stateless(CONF_SECTION *cs, fr_tls_conf_t const *tls_conf)
Check that the TLS configuration does not need stateless session tickets.
unlang_action_t eap_tls_fail(request_t *request, eap_session_t *eap_session)
Send an EAP-TLS failure.
USES_APPLE_DEPRECATED_API fr_table_num_ordered_t const eap_tls_status_table[]
static eap_tls_status_t eap_tls_session_status(request_t *request, eap_session_t *eap_session)
Reduce session states down into an easy to use status.
static unlang_action_t eap_tls_handshake_resume(request_t *request, void *uctx)
Process the result from the last TLS handshake round.
unlang_action_t eap_tls_process(request_t *request, eap_session_t *eap_session)
Process an EAP TLS request.
Generic EAP over TLS API.
int base_flags
Some protocols use the reserved bits of the EAP-TLS flags (such as PEAP).
@ EAP_TLS_RECORD_RECV_FIRST
Received first fragment of a record.
@ EAP_TLS_INVALID
Invalid, don't reply.
@ EAP_TLS_HANDLED
TLS code has handled it.
@ EAP_TLS_RECORD_RECV_MORE
Received additional fragment of a record.
@ EAP_TLS_ACK_SEND
Acknowledge receipt of a record or record fragment.
@ EAP_TLS_RECORD_SEND
We're sending a record.
@ EAP_TLS_RECORD_RECV_COMPLETE
Received final fragment of a record.
@ EAP_TLS_START_SEND
We're starting a new TLS session.
@ EAP_TLS_FAIL
Fail, send fail.
@ EAP_TLS_ESTABLISHED
Session established, send success (or start phase2).
eap_tls_status_t state
The state of the EAP-TLS session.
bool phase2
Whether we're in phase 2.
#define TLS_MORE_FRAGMENTS(x)
fr_tls_session_t * tls_session
TLS session used to authenticate peer or tunnel sensitive data.
bool record_in_started
Whether a record transfer from the peer is currently in progress.
size_t record_out_total_len
Actual/Total TLS message length we're sending.
#define SET_LENGTH_INCLUDED(x)
size_t record_in_total_len
How long the peer indicated the complete tls record would be.
bool record_out_started
for methods with inner auth, if the inner auth succeeded.
size_t record_in_recvd_len
How much of the record we've received so far.
#define TLS_LENGTH_INCLUDED(x)
#define EAP_TLS_NESTED_OVERHEAD
Overhead subtracted from the MTU of an EAP-TLS session which is nested inside a tunneled method.
#define TLS_HEADER_LENGTH_FIELD_LEN
#define SET_MORE_FRAGMENTS(x)
bool authentication_success
bool include_length
A flag to include length in every TLS Data/Alert packet.
Tracks the state of an EAP-TLS session.
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack.
void unlang_interpet_frame_discard(request_t *request)
Discard the bottom most frame on the request's stack.
HIDDEN fr_dict_attr_t const * attr_eap_identity
HIDDEN fr_dict_attr_t const * attr_tls_min_version
HIDDEN fr_dict_attr_t const * attr_framed_mtu
HIDDEN fr_dict_attr_t const * attr_eap_session_id
HIDDEN fr_dict_attr_t const * attr_tls_max_version
HIDDEN fr_dict_attr_t const * attr_eap_type
int eap_crypto_mppe_keys(request_t *request, SSL *ssl, eap_tls_prf_label_t *prf_label)
Generate keys according to RFC 5216 and add to the reply.
int eap_crypto_tls_session_id(TALLOC_CTX *ctx, request_t *request, SSL *ssl, eap_tls_prf_label_t *prf_label, uint8_t **out, uint8_t eap_type)
bool eap_session_in_tunnel(request_t const *request)
Check whether a request runs inside the tunnel of another EAP method.
char * identity
NAI (User-Name) from EAP-Identity.
void * opaque
Opaque data used by EAP methods.
bool tls
Whether EAP method uses TLS.
eap_type_t type
EAP method number.
request_t * request
Current request.
eap_round_t * this_round
The EAP response we're processing, and the EAP request we're building.
eap_round_t * prev_round
Previous response/request pair.
bool finished
Whether we consider this session complete.
Tracks the progress of a single session of any EAP method.
#define REXDENT()
Exdent (unindent) R* messages by one level.
#define RINDENT()
Indent R* messages by one level.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
int fr_pair_value_memdup_buffer_shallow(fr_pair_t *vp, uint8_t const *src, bool tainted)
Assign a talloced buffer to a "octets" type value pair.
#define pair_delete_reply(_pair_or_da)
Delete a fr_pair_t in the reply list.
#define pair_append_reply(_attr, _da)
Allocate and append a fr_pair_t to reply list.
@ FR_SIGNAL_NONE
No signals.
fr_pair_value_bstrdup_buffer(vp, eap_session->identity, true)
Stores an attribute, a value and various bits of other data.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
An element in an arbitrarily ordered array of name to num mappings.
#define fr_time_delta_lt(_a, _b)
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
static fr_sbuff_err_t char size_t fr_sbuff_t size_t max
static fr_sbuff_err_t char size_t * len
#define fr_box_time_delta(_val)