71RCSID(
"$Id: b056c118b0b6f0707b6adedd23e5deb6f02e4143 $")
74#include <freeradius-devel/unlang/function.h>
75#include <freeradius-devel/server/pair.h>
114 fr_tls_record_t *record,
size_t record_len,
size_t frag_len)
118 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
127 RDEBUG3(
"Setting flags %c%c%c%c%c%c%c%c",
145 if (record) len += frag_len;
149 if (record_len != 0) len += frag_len;
185 net_record_len = htonl(record_len);
186 memcpy(p, &net_record_len,
sizeof(net_record_len));
187 p +=
sizeof(net_record_len);
190 if (record) tls_session->record_to_buff(record, p, frag_len);
266 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
276 eap_tls_session->
base_flags, NULL, 0, 0) < 0)
return -1;
278 if (!prf_label)
return 0;
294 &session_id, eap_session->
type) < 0) {
324 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
333 fr_tls_cache_deny(request, tls_session);
336 eap_tls_session->
base_flags, NULL, 0, 0) < 0)
return -1;
374 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
377 bool length_included;
398 if ((tls_session->dirty_out.used +
412 RDEBUG2(
"Complete TLS record (%zu bytes) larger than MTU (%zu bytes), will fragment",
414 RDEBUG2(
"Sending first TLS record fragment (%zu bytes), %zu bytes remaining",
415 frag_len, tls_session->dirty_out.used - frag_len);
417 RDEBUG2(
"Sending additional TLS record fragment (%zu bytes), %zu bytes remaining",
418 frag_len, tls_session->dirty_out.used - frag_len);
426 frag_len = tls_session->dirty_out.used;
429 RDEBUG2(
"Sending complete TLS record (%zu bytes)", frag_len);
431 RDEBUG2(
"Sending final TLS record fragment (%zu bytes)", frag_len);
469 RDEBUG2(
"ACKing Peer's TLS record fragment");
486 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
488 if (tls_session == NULL){
489 REDEBUG(
"Unexpected ACK received: No ongoing SSL tls_session");
492 if (!tls_session->info.initialized) {
493 RDEBUG2(
"No SSL info available. Waiting for more SSL data");
497 if ((tls_session->info.content_type == SSL3_RT_HANDSHAKE) &&
498 (tls_session->info.origin == TLS_INFO_ORIGIN_RECORD_RECEIVED)) {
499 REDEBUG(
"Unexpected ACK received: We sent no previous messages");
503 switch (tls_session->info.content_type) {
505 RDEBUG2(
"Peer ACKed our alert");
508 case SSL3_RT_HANDSHAKE:
509 if (SSL_is_init_finished(tls_session->ssl) && (tls_session->dirty_out.used == 0)) {
510 RDEBUG2(
"Peer ACKed our handshake fragment. handshake is finished");
517 tls_session->info.content_type = SSL3_RT_APPLICATION_DATA;
521 RDEBUG2(
"Peer ACKed our handshake fragment");
525 case SSL3_RT_APPLICATION_DATA:
526 RDEBUG2(
"Peer ACKed our application data fragment");
538 REDEBUG(
"Invalid ACK received: %d", tls_session->info.content_type);
566 size_t frag_len, header_len;
574 REDEBUG(
"Invalid EAP-TLS packet: Expected at least %zu bytes got %zu bytes",
590 REDEBUG(
"Invalid EAP-TLS packet; no data");
597 RDEBUG3(
"Peer sent flags %c%c%c%c%c%c%c%c",
613 REDEBUG(
"Invalid EAP-TLS packet: Expected at least %zu bytes got %zu bytes",
627 ((eap_tls_data->
flags & 0xc0) == 0x00)) {
629 REDEBUG(
"Received Invalid TLS ACK");
639 REDEBUG(
"Peer sent EAP-TLS Start message (only the server is allowed to do this)");
652 REDEBUG(
"Peer sent EAP-TLS with zero-length fragment and 'more' bit set - if there is no data, there should not be more!");
672 if (eap_tls_data->
data[0] || eap_tls_data->
data[1]) {
673 REDEBUG(
"TLS record length is > 65536");
677 total_len = eap_tls_data->
data[2] * 256 | eap_tls_data->
data[3];
678 if (frag_len > total_len) {
679 REDEBUG(
"TLS fragment length (%zu bytes) greater than TLS record length (%zu bytes)",
680 frag_len, total_len);
684 if (total_len > FR_TLS_MAX_RECORD_SIZE) {
685 REDEBUG(
"Reassembled TLS record will be %zu bytes, "
686 "greater than our maximum record size (" STRINGIFY(FR_TLS_MAX_RECORD_SIZE)
" bytes)",
705 RDEBUG2(
"Peer indicated complete TLS record size will be %zu bytes", total_len);
716 RDEBUG2(
"Expecting %i TLS record fragments",
717 (
int)((((total_len - frag_len) + ((frag_len + 4) - 1)) / (frag_len + 4)) + 1));
724 RDEBUG2(
"Got first TLS record fragment (%zu bytes). Peer indicated more fragments "
725 "to follow", frag_len);
736 if (total_len != frag_len) {
737 REDEBUG(
"Peer indicated no more fragments, but TLS record length (%zu bytes) "
738 "does not match EAP-TLS data length (%zu bytes)", total_len, frag_len);
748 RDEBUG2(
"Got complete TLS record, with length field (%zu bytes)", frag_len);
759 REDEBUG(
"TLS More (M) flag set, but no fragmented record transfer was in progress");
767 RDEBUG2(
"Got additional TLS record fragment (%zu bytes). Peer indicated more fragments to follow",
771 REDEBUG(
"Total received TLS record fragments (%zu bytes), exceeds "
772 "indicated TLS record length (%zu bytes)",
790 RDEBUG2(
"Got final TLS record fragment (%zu bytes)", frag_len);
793 REDEBUG(
"Total received TLS record fragments (%zu bytes), does not equal indicated "
794 "TLS record length (%zu bytes)",
805 RDEBUG2(
"Got complete TLS record (%zu bytes)", frag_len);
823 fr_tls_session_t *tls_session = talloc_get_type_abort(eap_tls_session->
tls_session, fr_tls_session_t);
826 switch (tls_session->result) {
827 case FR_TLS_RESULT_IN_PROGRESS:
832 case FR_TLS_RESULT_ERROR:
833 REDEBUG(
"TLS receive handshake failed during operation");
836 case FR_TLS_RESULT_SUCCESS:
863 if ((tls_session->info.version == TLS1_3_VERSION) &&
864 (tls_session->client_cert_ok || eap_tls_session->
authentication_success || SSL_session_reused(tls_session->ssl))) {
868 RDEBUG(
"(TLS) EAP Sending final Commitment Message.");
869 tls_session->record_from_buff(&tls_session->clean_in,
"\0", 1);
875 ret = fr_tls_session_async_handshake_push(request, tls_session);
878 REDEBUG(
"TLS receive handshake failed during operation");
889 if (tls_session->dirty_out.used > 0) {
891 REDEBUG(
"TLS failed composing a response");
906 if (eap_tls_session->
phase2 || SSL_is_init_finished(tls_session->ssl)) {
907 eap_tls_session->
phase2 =
true;
913 tls_session->info.content_type = SSL3_RT_APPLICATION_DATA;
921 REDEBUG(
"TLS failed during operation");
923 fr_tls_cache_deny(request, tls_session);
939 fr_tls_session_t *tls_session = talloc_get_type_abort(eap_tls_session->
tls_session, fr_tls_session_t);
951 if (fr_tls_session_async_handshake_push(request, tls_session) < 0)
return UNLANG_ACTION_FAIL;
984 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
1000 switch (eap_tls_session->
state) {
1016 switch (eap_tls_session->
state) {
1050 if ((tls_session->record_from_buff)(&tls_session->dirty_in,
data, data_len) != data_len) {
1051 REDEBUG(
"Exceeded maximum record size");
1073 if (eap_tls_session->
phase2 || SSL_is_init_finished(tls_session->ssl)) {
1076 eap_tls_session->
phase2 =
true;
1078 ret = fr_tls_session_recv(request, tls_session);
1107 if (!eap_tls_session->
phase2 && (tls_session->dirty_out.used == 0) &&
1108 SSL_is_init_finished(tls_session->ssl)) {
1109 eap_tls_session->
phase2 =
true;
1156 SSL_CTX *ssl_ctx,
bool client_cert)
1159 fr_tls_session_t *tls_session;
1160 fr_tls_conf_t *
conf = fr_tls_ctx_conf(ssl_ctx);
1169 eap_session->
tls =
true;
1206 eap_tls_session->
tls_session = tls_session = fr_tls_session_alloc_server(eap_tls_session, ssl_ctx,
1207 request,
vp ?
vp->vp_uint32 : 0, client_cert);
1208 if (
unlikely(!tls_session))
return NULL;
1219 fr_tls_session_extra_pair_add_shallow(tls_session, identity);
1229 type_vp->vp_uint32 = eap_session->
type;
1230 fr_tls_session_extra_pair_add_shallow(tls_session, type_vp);
1236 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_EAP_SESSION, (
void *)eap_session);
1237 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_TLS_SESSION, (
void *)tls_session);
1238 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_CONF, (
void *)
conf);
1239 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_IDENTITY, (
void *)&(eap_session->
identity));
1243 if (tls_max && tls_min && (tls_min->vp_float32 > tls_max->vp_float32)) {
1244 RERROR(
"Can't set TLS min version greater than max version");
1245 goto skip_tls_version;
1248#define SET_TLS_VERSION(_type) \
1249 if (tls_ ## _type) { \
1250 int tls_version = 0; \
1251 if (tls_ ## _type->vp_float32 >= (float) 1.3) { \
1252 tls_version = TLS1_3_VERSION; \
1253 } else if (tls_ ## _type->vp_float32 >= (float) 1.2) { \
1254 tls_version = TLS1_2_VERSION; \
1255 } else if (tls_ ## _type->vp_float32 >= (float) 1.1) { \
1256 tls_version = TLS1_1_VERSION; \
1258 if (tls_version) { \
1259 if (SSL_set_ ## _type ## _proto_version(tls_session->ssl, tls_version) != 1) {\
1260 RERROR("Failed to set %pP", tls_ ## _type); \
1262 RDEBUG2("Setting TLS " #_type " version to %0.1f", tls_ ## _type->vp_float32); \
1265 RWARN("Invalid value %pP", tls_ ## _type); \
1273 return eap_tls_session;
1289 char const *tls_conf_name;
1293 fr_tls_conf_t *tls_conf;
1310 cf_log_perr(cp,
"Cannot find tls configuration section from reference '%s'",
1316 cf_log_err(cp,
"Invalid tls configuration reference '%s' - the result is not a configuration section",
1324 cf_log_err(cs,
"Cannot do TLS-based EAP method %s - missing 'tls = ...' configuration item",
1329 tls_conf = fr_tls_conf_parse_server(tls_cs);
1330 if (!tls_conf)
return NULL;
1351 tls_conf->fragment_size -= 10;
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.
#define USES_APPLE_DEPRECATED_API
#define L(_str)
Helper for initialising arrays of string literals.
CONF_ITEM * cf_reference_item(CONF_SECTION const *parent_cs, CONF_SECTION const *outer_cs, char const *ptr)
#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound)
Common header for all CONF_* types.
Configuration AVP similar to a fr_pair_t.
A section grouping multiple CONF_PAIR.
char const * cf_section_name1(CONF_SECTION const *cs)
Return the first identifier of a CONF_SECTION.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
#define cf_log_err(_cf, _fmt,...)
#define cf_log_perr(_cf, _fmt,...)
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 TLS_CONFIG_SECTION
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)
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang 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
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.
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_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.
int 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.
int eap_tls_compose(request_t *request, eap_session_t *eap_session, eap_tls_status_t status, uint8_t flags, fr_tls_record_t *record, size_t record_len, size_t frag_len)
Convert the EAP-TLS reply packet into an EAP packet.
size_t eap_tls_status_table_len
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.
int eap_tls_fail(request_t *request, eap_session_t *eap_session)
Send an EAP-TLS failure.
#define SET_TLS_VERSION(_type)
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.
fr_tls_conf_t * eap_tls_conf_parse(CONF_SECTION *cs)
Parse TLS configuration.
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_status_t state
The state of the EAP-TLS session.
bool phase2
Whether we're in phase 2.
@ 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).
#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 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.