71 RCSID(
"$Id: 261c048e06f784e24ea9e6b274e7b412dd3797c7 $")
74 #include <freeradius-devel/unlang/function.h>
75 #include <freeradius-devel/unlang/interpret.h>
76 #include <freeradius-devel/server/pair.h>
115 fr_tls_record_t *record,
size_t record_len,
size_t frag_len)
119 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
128 RDEBUG3(
"Setting flags %c%c%c%c%c%c%c%c",
146 if (record) len += frag_len;
150 if (record_len != 0) len += frag_len;
186 net_record_len = htonl(record_len);
187 memcpy(p, &net_record_len,
sizeof(net_record_len));
188 p +=
sizeof(net_record_len);
191 if (record) tls_session->record_to_buff(record, p, frag_len);
267 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
277 eap_tls_session->
base_flags, NULL, 0, 0) < 0)
return -1;
279 if (!prf_label)
return 0;
295 &session_id, eap_session->
type) < 0) {
325 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
334 fr_tls_cache_deny(request, tls_session);
337 eap_tls_session->
base_flags, NULL, 0, 0) < 0)
return -1;
375 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
378 bool length_included;
399 if ((tls_session->dirty_out.used +
413 RDEBUG2(
"Complete TLS record (%zu bytes) larger than MTU (%zu bytes), will fragment",
415 RDEBUG2(
"Sending first TLS record fragment (%zu bytes), %zu bytes remaining",
416 frag_len, tls_session->dirty_out.used - frag_len);
418 RDEBUG2(
"Sending additional TLS record fragment (%zu bytes), %zu bytes remaining",
419 frag_len, tls_session->dirty_out.used - frag_len);
427 frag_len = tls_session->dirty_out.used;
430 RDEBUG2(
"Sending complete TLS record (%zu bytes)", frag_len);
432 RDEBUG2(
"Sending final TLS record fragment (%zu bytes)", frag_len);
470 RDEBUG2(
"ACKing Peer's TLS record fragment");
487 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
489 if (tls_session == NULL){
490 REDEBUG(
"Unexpected ACK received: No ongoing SSL tls_session");
493 if (!tls_session->info.initialized) {
494 RDEBUG2(
"No SSL info available. Waiting for more SSL data");
498 if ((tls_session->info.content_type == SSL3_RT_HANDSHAKE) && (tls_session->info.origin == 0)) {
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)");
664 total_len = eap_tls_data->
data[2] * 256 | eap_tls_data->
data[3];
665 if (frag_len > total_len) {
666 REDEBUG(
"TLS fragment length (%zu bytes) greater than TLS record length (%zu bytes)",
667 frag_len, total_len);
671 if (total_len > FR_TLS_MAX_RECORD_SIZE) {
672 REDEBUG(
"Reassembled TLS record will be %zu bytes, "
673 "greater than our maximum record size (" STRINGIFY(FR_TLS_MAX_RECORD_SIZE)
" bytes)",
692 RDEBUG2(
"Peer indicated complete TLS record size will be %zu bytes", total_len);
703 RDEBUG2(
"Expecting %i TLS record fragments",
704 (
int)((((total_len - frag_len) + ((frag_len + 4) - 1)) / (frag_len + 4)) + 1));
711 RDEBUG2(
"Got first TLS record fragment (%zu bytes). Peer indicated more fragments "
712 "to follow", frag_len);
723 if (total_len != frag_len) {
724 REDEBUG(
"Peer indicated no more fragments, but TLS record length (%zu bytes) "
725 "does not match EAP-TLS data length (%zu bytes)", total_len, frag_len);
735 RDEBUG2(
"Got complete TLS record, with length field (%zu bytes)", frag_len);
746 REDEBUG(
"TLS More (M) flag set, but no fragmented record transfer was in progress");
754 RDEBUG2(
"Got additional TLS record fragment (%zu bytes). Peer indicated more fragments to follow",
758 REDEBUG(
"Total received TLS record fragments (%zu bytes), exceeds "
759 "indicated TLS record length (%zu bytes)",
777 RDEBUG2(
"Got final TLS record fragment (%zu bytes)", frag_len);
780 REDEBUG(
"Total received TLS record fragments (%zu bytes), does not equal indicated "
781 "TLS record length (%zu bytes)",
792 RDEBUG2(
"Got complete TLS record (%zu bytes)", frag_len);
811 fr_tls_session_t *tls_session = talloc_get_type_abort(eap_tls_session->
tls_session, fr_tls_session_t);
813 switch (tls_session->result) {
814 case FR_TLS_RESULT_IN_PROGRESS:
819 case FR_TLS_RESULT_ERROR:
820 REDEBUG(
"TLS receive handshake failed during operation");
821 fr_tls_cache_deny(request, tls_session);
825 case FR_TLS_RESULT_SUCCESS:
829 #ifdef TLS1_3_VERSION
852 if ((tls_session->info.version == TLS1_3_VERSION) &&
853 (tls_session->client_cert_ok || eap_tls_session->
authentication_success || SSL_session_reused(tls_session->ssl))) {
857 RDEBUG(
"(TLS) EAP Sending final Commitment Message.");
858 tls_session->record_from_buff(&tls_session->clean_in,
"\0", 1);
864 (void) fr_tls_session_async_handshake_push(request, tls_session);
865 if (tls_session->result != FR_TLS_RESULT_SUCCESS) {
866 REDEBUG(
"TLS receive handshake failed during operation");
867 fr_tls_cache_deny(request, tls_session);
879 if (tls_session->dirty_out.used > 0) {
893 if (eap_tls_session->
phase2 || SSL_is_init_finished(tls_session->ssl)) {
894 eap_tls_session->
phase2 =
true;
900 tls_session->info.content_type = SSL3_RT_APPLICATION_DATA;
908 REDEBUG(
"TLS failed during operation");
925 fr_tls_session_t *tls_session = talloc_get_type_abort(eap_tls_session->
tls_session, fr_tls_session_t);
935 if (fr_tls_session_async_handshake_push(request, tls_session) < 0)
return UNLANG_ACTION_FAIL;
966 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
982 switch (eap_tls_session->
state) {
998 switch (eap_tls_session->
state) {
1032 if ((tls_session->record_from_buff)(&tls_session->dirty_in,
data, data_len) != data_len) {
1033 REDEBUG(
"Exceeded maximum record size");
1052 if (eap_tls_session->
phase2 || SSL_is_init_finished(tls_session->ssl)) {
1055 eap_tls_session->
phase2 =
true;
1057 ret = fr_tls_session_recv(request, tls_session);
1086 if (!eap_tls_session->
phase2 && (tls_session->dirty_out.used == 0) &&
1087 SSL_is_init_finished(tls_session->ssl)) {
1088 eap_tls_session->
phase2 =
true;
1132 SSL_CTX *ssl_ctx,
bool client_cert)
1135 fr_tls_session_t *tls_session;
1136 fr_tls_conf_t *
conf = fr_tls_ctx_conf(ssl_ctx);
1144 eap_session->
tls =
true;
1181 eap_tls_session->
tls_session = tls_session = fr_tls_session_alloc_server(eap_tls_session, ssl_ctx,
1182 request,
vp ?
vp->vp_uint32 : 0, client_cert);
1183 if (
unlikely(!tls_session))
return NULL;
1194 fr_tls_session_extra_pair_add_shallow(tls_session, identity);
1204 type_vp->vp_uint32 = eap_session->
type;
1205 fr_tls_session_extra_pair_add_shallow(tls_session, type_vp);
1211 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_EAP_SESSION, (
void *)eap_session);
1212 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_TLS_SESSION, (
void *)tls_session);
1213 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_CONF, (
void *)
conf);
1214 SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_IDENTITY, (
void *)&(eap_session->
identity));
1216 return eap_tls_session;
1233 char const *tls_conf_name;
1237 fr_tls_conf_t *tls_conf;
1247 ERROR(
"Cannot find tls config \"%s\"", tls_conf_name);
1259 INFO(
"TLS section \"%s\" missing, trying to use legacy configuration", attr);
1263 if (!tls_cs)
return NULL;
1265 tls_conf = fr_tls_conf_parse_server(tls_cs);
1266 if (!tls_conf)
return NULL;
1286 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.
fr_dcursor_eval_t void const * uctx
#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_framed_mtu
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_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.
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.
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.