📄 eap_tls.c
字号:
/* * eap_tls.c * * Version: $Id: eap_tls.c,v 1.10 2007/12/15 14:56:10 aland Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com> * Copyright 2003 Alan DeKok <aland@freeradius.org> * Copyright 2006 The FreeRADIUS server project *//* * * TLS Packet Format in EAP * --- ------ ------ -- --- * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Code | Identifier | Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type | Flags | TLS Message Length * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | TLS Message Length | TLS Data... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */#include <freeradius-devel/ident.h>RCSID("$Id: eap_tls.c,v 1.10 2007/12/15 14:56:10 aland Exp $")#include <freeradius-devel/autoconf.h>#include <assert.h>#include "eap_tls.h"/* * Allocate a new TLS_PACKET */EAPTLS_PACKET *eaptls_alloc(void){ EAPTLS_PACKET *rp; if ((rp = malloc(sizeof(EAPTLS_PACKET))) == NULL) { radlog(L_ERR, "rlm_eap_tls: out of memory"); return NULL; } memset(rp, 0, sizeof(EAPTLS_PACKET)); return rp;}/* * Free EAPTLS_PACKET */void eaptls_free(EAPTLS_PACKET **eaptls_packet_ptr){ EAPTLS_PACKET *eaptls_packet; if (!eaptls_packet_ptr) return; eaptls_packet = *eaptls_packet_ptr; if (eaptls_packet == NULL) return; if (eaptls_packet->data) { free(eaptls_packet->data); eaptls_packet->data = NULL; } free(eaptls_packet); *eaptls_packet_ptr = NULL;}/* The S flag is set only within the EAP-TLS start message sent from the EAP server to the peer.*/int eaptls_start(EAP_DS *eap_ds, int peap_flag){ EAPTLS_PACKET reply; reply.code = EAPTLS_START; reply.length = TLS_HEADER_LEN + 1/*flags*/; reply.flags = peap_flag; reply.flags = SET_START(reply.flags); reply.data = NULL; reply.dlen = 0; eaptls_compose(eap_ds, &reply); return 1;}int eaptls_success(EAP_DS *eap_ds, int peap_flag){ EAPTLS_PACKET reply; reply.code = EAPTLS_SUCCESS; reply.length = TLS_HEADER_LEN; reply.flags = peap_flag; reply.data = NULL; reply.dlen = 0; eaptls_compose(eap_ds, &reply); return 1;}int eaptls_fail(EAP_DS *eap_ds, int peap_flag){ EAPTLS_PACKET reply; reply.code = EAPTLS_FAIL; reply.length = TLS_HEADER_LEN; reply.flags = peap_flag; reply.data = NULL; reply.dlen = 0; eaptls_compose(eap_ds, &reply); return 1;}/* A single TLS record may be up to 16384 octets in length, but a TLS message may span multiple TLS records, and a TLS certificate message may in principle be as long as 16MB.*//* * Frame the Dirty data that needs to be send to the client in an * EAP-Request. We always embed the TLS-length in all EAP-TLS * packets that we send, for easy reference purpose. Handle * fragmentation and sending the next fragment etc. */int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn){ EAPTLS_PACKET reply; unsigned int size; unsigned int nlen; unsigned int lbit = 0; /* This value determines whether we set (L)ength flag for EVERY packet we send and add corresponding "TLS Message Length" field. length_flag = TRUE; This means we include L flag and "TLS Msg Len" in EVERY packet we send out. length_flag = FALSE; This means we include L flag and "TLS Msg Len" **ONLY** in First packet of a fragment series. We do not use it anywhere else. Having L flag in every packet is prefered. */ if (ssn->length_flag) { lbit = 4; } if (ssn->fragment == 0) { ssn->tls_msg_len = ssn->dirty_out.used; } reply.code = EAPTLS_REQUEST; reply.flags = ssn->peap_flag; /* Send data, NOT more than the FRAGMENT size */ if (ssn->dirty_out.used > ssn->offset) { size = ssn->offset; reply.flags = SET_MORE_FRAGMENTS(reply.flags); /* Length MUST be included if it is the First Fragment */ if (ssn->fragment == 0) { lbit = 4; } ssn->fragment = 1; } else { size = ssn->dirty_out.used; ssn->fragment = 0; } reply.dlen = lbit + size; reply.length = TLS_HEADER_LEN + 1/*flags*/ + reply.dlen; reply.data = malloc(reply.dlen); if (lbit) { nlen = htonl(ssn->tls_msg_len); memcpy(reply.data, &nlen, lbit); reply.flags = SET_LENGTH_INCLUDED(reply.flags); } (ssn->record_minus)(&ssn->dirty_out, reply.data + lbit, size); eaptls_compose(eap_ds, &reply); free(reply.data); reply.data = NULL; return 1;}/* * Acknowledge received is for one of the following messages sent earlier * 1. Handshake completed Message, so now send, EAP-Success * 2. Alert Message, now send, EAP-Failure * 3. Fragment Message, now send, next Fragment */static eaptls_status_t eaptls_ack_handler(EAP_HANDLER *handler){ tls_session_t *tls_session; tls_session = (tls_session_t *)handler->opaque; if (tls_session == NULL){ radlog(L_ERR, "rlm_eap_tls: Unexpected ACK received"); return EAPTLS_FAIL; } if (tls_session->info.initialized == 0) { DEBUG(" rlm_eap_tls: No SSL info available. Waiting for more SSL data."); return EAPTLS_REQUEST; } if (tls_session->info.origin == 0) { radlog(L_ERR, "rlm_eap_tls: Unexpected ACK received"); return EAPTLS_FAIL; } switch (tls_session->info.content_type) { case alert: DEBUG2(" rlm_eap_tls: ack alert"); eaptls_fail(handler->eap_ds, tls_session->peap_flag); return EAPTLS_FAIL; case handshake: if ((tls_session->info.handshake_type == finished) && (tls_session->dirty_out.used == 0)) { DEBUG2(" rlm_eap_tls: ack handshake is finished"); return EAPTLS_SUCCESS; } /* else more data to send */ DEBUG2(" rlm_eap_tls: ack handshake fragment handler"); /* Fragmentation handler, send next fragment */ return EAPTLS_REQUEST; /* * For the rest of the conditions, switch over * to the default section below. */ default: DEBUG2(" rlm_eap_tls: ack default"); radlog(L_ERR, "rlm_eap_tls: Invalid ACK received: %d", tls_session->info.content_type); return EAPTLS_FAIL; }}/* * Similarly, when the EAP server receives an EAP-Response with * the M bit set, it MUST respond with an EAP-Request with * EAP-Type=EAP-TLS and no data. This serves as a fragment ACK. * * In order to prevent errors in the processing of fragments, the * EAP server MUST use increment the Identifier value for each * fragment ACK contained within an EAP-Request, and the peer * MUST include this Identifier value in the subsequent fragment * contained within an EAP- Reponse. * * EAP server sends an ACK when it determines there are More * fragments to receive to make the complete * TLS-record/TLS-Message */static int eaptls_send_ack(EAP_DS *eap_ds, int peap_flag){ EAPTLS_PACKET reply; reply.code = EAPTLS_ACK; reply.length = TLS_HEADER_LEN + 1/*flags*/; reply.flags = peap_flag; reply.data = NULL; reply.dlen = 0; eaptls_compose(eap_ds, &reply); return 1;}/* * The S flag is set only within the EAP-TLS start message sent * from the EAP server to the peer. * * Similarly, when the EAP server receives an EAP-Response with * the M bit set, it MUST respond with an EAP-Request with * EAP-Type=EAP-TLS and no data. This serves as a fragment * ACK. The EAP peer MUST wait. */static eaptls_status_t eaptls_verify(EAP_HANDLER *handler){ EAP_DS *eap_ds = handler->eap_ds; EAP_DS *prev_eap_ds = handler->prev_eapds; eaptls_packet_t *eaptls_packet, *eaptls_prev = NULL; /* * We don't check ANY of the input parameters. It's all * code which works together, so if something is wrong, * we SHOULD core dump. * * e.g. if eap_ds is NULL, of if eap_ds->response is * NULL, of if it's NOT an EAP-Response, or if the packet * is too short. See eap_validation()., in ../../eap.c * * Also, eaptype_select() takes care of selecting the * appropriate type, so we don't need to check * eap_ds->response->type.type == PW_EAP_TLS, or anything * else. */ eaptls_packet = (eaptls_packet_t *)eap_ds->response->type.data; if (prev_eap_ds && prev_eap_ds->response) eaptls_prev = (eaptls_packet_t *)prev_eap_ds->response->type.data; /* * check for ACK * * If there's no TLS data, or there's 1 byte of TLS data, * with the flags set to zero, then it's an ACK. * * Find if this is a reply to the previous request sent */ if ((eaptls_packet == NULL) || ((eap_ds->response->length == EAP_HEADER_LEN + 2) && ((eaptls_packet->flags & 0xc0) == 0x00))) {#if 0 /* * Un-comment this for TLS inside of TTLS/PEAP */ DEBUG2("rlm_eap_tls: Received EAP-TLS ACK message"); return eaptls_ack_handler(handler);#else if (prev_eap_ds->request->id == eap_ds->response->id) { /* * Run the ACK handler directly from here. */ DEBUG2("rlm_eap_tls: Received EAP-TLS ACK message"); return eaptls_ack_handler(handler); } else { radlog(L_ERR, "rlm_eap_tls: Received Invalid EAP-TLS ACK message"); return EAPTLS_INVALID; }#endif } /* * We send TLS_START, but do not receive it. */ if (TLS_START(eaptls_packet->flags)) { radlog(L_ERR, "rlm_eap_tls: Received unexpected EAP-TLS Start message"); return EAPTLS_INVALID; } /* * The L bit (length included) is set to indicate the * presence of the four octet TLS Message Length field, * and MUST be set for the first fragment of a fragmented * TLS message or set of messages. * * The M bit (more fragments) is set on all but the last * fragment. * * The S bit (EAP-TLS start) is set in an EAP-TLS Start * message. This differentiates the EAP-TLS Start message * from a fragment acknowledgement. */ if (TLS_LENGTH_INCLUDED(eaptls_packet->flags)) { DEBUG2(" TLS Length %d", eaptls_packet->data[2] * 256 | eaptls_packet->data[3]); if (TLS_MORE_FRAGMENTS(eaptls_packet->flags)) { /* * FIRST_FRAGMENT is identified * 1. If there is no previous EAP-response received. * 2. If EAP-response received, then its M bit not set. * (It is because Last fragment will not have M bit set) */ if (!prev_eap_ds || (prev_eap_ds->response == NULL) || (eaptls_prev == NULL) || !TLS_MORE_FRAGMENTS(eaptls_prev->flags)) { DEBUG2("rlm_eap_tls: Received EAP-TLS First Fragment of the message"); return EAPTLS_FIRST_FRAGMENT; } else { DEBUG2("rlm_eap_tls: More Fragments with length included"); return EAPTLS_MORE_FRAGMENTS_WITH_LENGTH; } } else { DEBUG2("rlm_eap_tls: Length Included"); return EAPTLS_LENGTH_INCLUDED; } } if (TLS_MORE_FRAGMENTS(eaptls_packet->flags)) { DEBUG2("rlm_eap_tls: More fragments to follow"); return EAPTLS_MORE_FRAGMENTS; } /* * None of the flags are set, but it's still a valid * EAPTLS packet. */ return EAPTLS_OK;}/* * EAPTLS_PACKET * code = EAP-code * id = EAP-id * length = code + id + length + flags + tlsdata * = 1 + 1 + 2 + 1 + X * length = EAP-length - 1(EAP-Type = 1 octet) * flags = EAP-typedata[0] (1 octet) * dlen = EAP-typedata[1-4] (4 octets), if L flag set * = length - 5(code+id+length+flags), otherwise * data = EAP-typedata[5-n], if L flag set * = EAP-typedata[1-n], otherwise * packet = EAP-typedata (complete typedata) * * Points to consider during EAP-TLS data extraction * 1. In the received packet, No data will be present incase of ACK-NAK * 2. Incase if more fragments need to be received then ACK after retreiving this fragment. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -