71 RCSID(
"$Id: 1d71573a9a6f8e91f2f58efa8cdfdfe0042828c1 $")
74 #include <freeradius-devel/unlang/function.h>
113 fr_tls_record_t *record,
size_t record_len,
size_t frag_len)
117 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
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);
189 if (record) tls_session->record_to_buff(record, p, frag_len);
265 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
275 eap_tls_session->
base_flags, NULL, 0, 0) < 0)
return -1;
277 if (!prf_label)
return 0;
293 &session_id, eap_session->
type) < 0) {
323 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
332 fr_tls_cache_deny(request, tls_session);
335 eap_tls_session->
base_flags, NULL, 0, 0) < 0)
return -1;
373 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
376 bool length_included;
397 if ((tls_session->dirty_out.used +
411 RDEBUG2(
"Complete TLS record (%zu bytes) larger than MTU (%zu bytes), will fragment",
413 RDEBUG2(
"Sending first TLS record fragment (%zu bytes), %zu bytes remaining",
414 frag_len, tls_session->dirty_out.used - frag_len);
416 RDEBUG2(
"Sending additional TLS record fragment (%zu bytes), %zu bytes remaining",
417 frag_len, tls_session->dirty_out.used - frag_len);
425 frag_len = tls_session->dirty_out.used;
428 RDEBUG2(
"Sending complete TLS record (%zu bytes)", frag_len);
430 RDEBUG2(
"Sending final TLS record fragment (%zu bytes)", frag_len);
468 RDEBUG2(
"ACKing Peer's TLS record fragment");
485 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
487 if (tls_session == NULL){
488 REDEBUG(
"Unexpected ACK received: No ongoing SSL tls_session");
491 if (!tls_session->info.initialized) {
492 RDEBUG2(
"No SSL info available. Waiting for more SSL data");
496 if ((tls_session->info.content_type == SSL3_RT_HANDSHAKE) && (tls_session->info.origin == 0)) {
497 REDEBUG(
"Unexpected ACK received: We sent no previous messages");
501 switch (tls_session->info.content_type) {
503 RDEBUG2(
"Peer ACKed our alert");
506 case SSL3_RT_HANDSHAKE:
507 if (SSL_is_init_finished(tls_session->ssl) && (tls_session->dirty_out.used == 0)) {
508 RDEBUG2(
"Peer ACKed our handshake fragment. handshake is finished");
515 tls_session->info.content_type = SSL3_RT_APPLICATION_DATA;
519 RDEBUG2(
"Peer ACKed our handshake fragment");
523 case SSL3_RT_APPLICATION_DATA:
524 RDEBUG2(
"Peer ACKed our application data fragment");
532 REDEBUG(
"Invalid ACK received: %d", tls_session->info.content_type);
560 size_t frag_len, header_len;
568 REDEBUG(
"Invalid EAP-TLS packet: Expected at least %zu bytes got %zu bytes",
584 REDEBUG(
"Invalid EAP-TLS packet; no data");
591 RDEBUG3(
"Peer sent flags %c%c%c%c%c%c%c%c",
607 REDEBUG(
"Invalid EAP-TLS packet: Expected at least %zu bytes got %zu bytes",
621 ((eap_tls_data->
flags & 0xc0) == 0x00)) {
623 REDEBUG(
"Received Invalid TLS ACK");
633 REDEBUG(
"Peer sent EAP-TLS Start message (only the server is allowed to do this)");
658 total_len = eap_tls_data->
data[2] * 256 | eap_tls_data->
data[3];
659 if (frag_len > total_len) {
660 REDEBUG(
"TLS fragment length (%zu bytes) greater than TLS record length (%zu bytes)",
661 frag_len, total_len);
665 if (total_len > FR_TLS_MAX_RECORD_SIZE) {
666 REDEBUG(
"Reassembled TLS record will be %zu bytes, "
667 "greater than our maximum record size (" STRINGIFY(FR_TLS_MAX_RECORD_SIZE)
" bytes)",
686 RDEBUG2(
"Peer indicated complete TLS record size will be %zu bytes", total_len);
697 RDEBUG2(
"Expecting %i TLS record fragments",
698 (
int)((((total_len - frag_len) + ((frag_len + 4) - 1)) / (frag_len + 4)) + 1));
705 RDEBUG2(
"Got first TLS record fragment (%zu bytes). Peer indicated more fragments "
706 "to follow", frag_len);
717 if (total_len != frag_len) {
718 REDEBUG(
"Peer indicated no more fragments, but TLS record length (%zu bytes) "
719 "does not match EAP-TLS data length (%zu bytes)", total_len, frag_len);
729 RDEBUG2(
"Got complete TLS record, with length field (%zu bytes)", frag_len);
740 REDEBUG(
"TLS More (M) flag set, but no fragmented record transfer was in progress");
748 RDEBUG2(
"Got additional TLS record fragment (%zu bytes). Peer indicated more fragments to follow",
752 REDEBUG(
"Total received TLS record fragments (%zu bytes), exceeds "
753 "indicated TLS record length (%zu bytes)",
771 RDEBUG2(
"Got final TLS record fragment (%zu bytes)", frag_len);
774 REDEBUG(
"Total received TLS record fragments (%zu bytes), does not equal indicated "
775 "TLS record length (%zu bytes)",
786 RDEBUG2(
"Got complete TLS record (%zu bytes)", frag_len);
805 fr_tls_session_t *tls_session = talloc_get_type_abort(eap_tls_session->
tls_session, fr_tls_session_t);
807 switch (tls_session->result) {
808 case FR_TLS_RESULT_IN_PROGRESS:
813 case FR_TLS_RESULT_ERROR:
814 REDEBUG(
"TLS receive handshake failed during operation");
815 fr_tls_cache_deny(request, tls_session);
819 case FR_TLS_RESULT_SUCCESS:
823 #ifdef TLS1_3_VERSION
846 if ((tls_session->info.version == TLS1_3_VERSION) &&
847 (tls_session->client_cert_ok || eap_tls_session->
authentication_success || SSL_session_reused(tls_session->ssl))) {
851 RDEBUG(
"(TLS) EAP Sending final Commitment Message.");
852 tls_session->record_from_buff(&tls_session->clean_in,
"\0", 1);
858 (void) fr_tls_session_async_handshake_push(request, tls_session);
859 if (tls_session->result != FR_TLS_RESULT_SUCCESS) {
860 REDEBUG(
"TLS receive handshake failed during operation");
861 fr_tls_cache_deny(request, tls_session);
873 if (tls_session->dirty_out.used > 0) {
887 if (eap_tls_session->
phase2 || SSL_is_init_finished(tls_session->ssl)) {
888 eap_tls_session->
phase2 =
true;
894 tls_session->info.content_type = SSL3_RT_APPLICATION_DATA;
902 REDEBUG(
"TLS failed during operation");
919 fr_tls_session_t *tls_session = talloc_get_type_abort(eap_tls_session->
tls_session, fr_tls_session_t);
929 if (fr_tls_session_async_handshake_push(request, tls_session) < 0)
return UNLANG_ACTION_FAIL;
960 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
976 switch (eap_tls_session->
state) {
992 switch (eap_tls_session->
state) {
1026 if ((tls_session->record_from_buff)(&tls_session->dirty_in,
data, data_len) != data_len) {
1027 REDEBUG(
"Exceeded maximum record size");
1046 if (eap_tls_session->
phase2 || SSL_is_init_finished(tls_session->ssl)) {
1049 eap_tls_session->
phase2 =
true;
1051 ret = fr_tls_session_recv(request, tls_session);
1080 if (!eap_tls_session->
phase2 && (tls_session->dirty_out.used == 0) &&
1081 SSL_is_init_finished(tls_session->ssl)) {
1082 eap_tls_session->
phase2 =
true;
1126 SSL_CTX *ssl_ctx,
bool client_cert)
1129 fr_tls_session_t *tls_session;
1130 fr_tls_conf_t *
conf = fr_tls_ctx_conf(ssl_ctx);
1137 eap_session->
tls =
true;
1160 eap_tls_session->
tls_session = tls_session = fr_tls_session_alloc_server(eap_tls_session, ssl_ctx,
1161 request, client_cert);
1162 if (
unlikely(!tls_session))
return NULL;
1173 fr_tls_session_extra_pair_add_shallow(tls_session, identity);
1183 type_vp->vp_uint32 = eap_session->
type;
1184 fr_tls_session_extra_pair_add_shallow(tls_session, type_vp);
1190 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_EAP_SESSION, (
void *)eap_session);
1191 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_TLS_SESSION, (
void *)tls_session);
1192 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_CONF, (
void *)
conf);
1193 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_IDENTITY, (
void *)&(eap_session->
identity));
1195 return eap_tls_session;
1212 char const *tls_conf_name;
1216 fr_tls_conf_t *tls_conf;
1226 ERROR(
"Cannot find tls config \"%s\"", tls_conf_name);
1238 INFO(
"TLS section \"%s\" missing, trying to use legacy configuration", attr);
1242 if (!tls_cs)
return NULL;
1244 tls_conf = fr_tls_conf_parse_server(tls_cs);
1245 if (!tls_conf)
return NULL;
1265 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.
#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound)
Configuration AVP similar to a fr_pair_t.
A section grouping multiple CONF_PAIR.
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_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
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.
#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, UNUSED 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_eap_session_id
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_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.
rlm_rcode_t
Return codes indicating the result of the module call.
#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.
if(!subtype_vp) goto fail
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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.
static unlang_action_t eap_tls_handshake_push(request_t *request, eap_session_t *eap_session)
Push functions to continue the handshake asynchronously.
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 int eap_tls_ack(request_t *request, eap_session_t *eap_session)
ACK a fragment of the TLS record from the peer.
static unlang_action_t eap_tls_handshake_resume(UNUSED rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Process the result from the last TLS handshake round.
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.
USES_APPLE_DEPRECATED_API fr_table_num_ordered_t const eap_tls_status_table[]
fr_tls_conf_t * eap_tls_conf_parse(CONF_SECTION *cs, char const *attr)
Parse TLS configuration.
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.
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.