📄 eap_tls.c
字号:
/* * eap_tls.c * * Version: $Id: eap_tls.c,v 1.13 2003/04/04 20:06:12 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com> *//* * * 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 "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){ EAPTLS_PACKET reply; reply.code = EAPTLS_START; reply.length = TLS_HEADER_LEN + 1/*flags*/; reply.flags = 0x00; 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){ EAPTLS_PACKET reply; reply.code = EAPTLS_SUCCESS; reply.length = TLS_HEADER_LEN; reply.flags = 0x00; reply.data = NULL; reply.dlen = 0; eaptls_compose(eap_ds, &reply); return 1;}int eaptls_fail(EAP_DS *eap_ds){ EAPTLS_PACKET reply; reply.code = EAPTLS_FAIL; reply.length = TLS_HEADER_LEN; reply.flags = 0x00; 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. * Handles 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 = 0x00; /* 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); } 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 * * After Success/Failure, We are done with the Session, free all the resources */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) || (tls_session->info.origin == 0)) { radlog(L_ERR, "rlm_eap_tls: Unexpected ACK received"); return EAPTLS_NOOP; } switch (tls_session->info.content_type) { case alert: eaptls_fail(handler->eap_ds); session_free(&handler->opaque); return EAPTLS_FAIL; case handshake: if (tls_session->info.handshake_type == finished) { eaptls_success(handler->eap_ds); eaptls_gen_mppe_keys(handler->reply_vps, tls_session->ssl); session_free(&handler->opaque); return EAPTLS_SUCCESS; } else if (tls_session->fragment > 0) { /* Fragmentation handler, send next fragment */ eaptls_request(handler->eap_ds, tls_session); return EAPTLS_REQUEST; } /* * For the rest of the conditions, * switch over to the default section below. */ default: radlog(L_ERR, "rlm_eap_tls: Invalid ACK received"); session_free(&handler->opaque); return EAPTLS_NOOP; }}/* 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 */int eaptls_send_ack(EAP_DS *eap_ds){ EAPTLS_PACKET reply; reply.code = EAPTLS_ACK; reply.length = TLS_HEADER_LEN + 1/*flags*/; reply.flags = 0x00; 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 */eaptls_status_t eaptls_verify(EAP_DS *eap_ds, EAP_DS *prev_eap_ds){ eaptls_packet_t *eaptls_packet, *eaptls_prev = NULL; if ((eap_ds == NULL) || (eap_ds->response == NULL) || (eap_ds->response->code != PW_EAP_RESPONSE) || (eap_ds->response->length <= EAP_HEADER_LEN + 1/*EAP-Type*/) || (eap_ds->response->type.type != PW_EAP_TLS)) { radlog(L_ERR, "rlm_eap_tls: corrupted data"); return EAPTLS_INVALID; } 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 * 1. Find if this is a reply to the previous request sent * 2. If typedata[0] == NULL && length == EAP_HEADER_LEN && ALLTLSFLAGS == 0 */ if ((eap_ds->response->length == EAP_HEADER_LEN + 2/*EAPtype+flags*/) && ((eaptls_packet != NULL) && (eaptls_packet->flags == 0x00))) { if (prev_eap_ds->request->id == eap_ds->response->id) { radlog(L_INFO, "rlm_eap_tls: Received EAP-TLS ACK message"); return EAPTLS_ACK; } else { radlog(L_ERR, "rlm_eap_tls: Received Invalid EAP-TLS ACK message"); return EAPTLS_INVALID;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -