summaryrefslogtreecommitdiffstats
path: root/src/modules/rlm_eap/libeap
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-26 10:41:52 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-26 10:41:52 +0000
commit44eafeee62e6982131c62df6f74335114ca53024 (patch)
tree1cdf833b0a76e52630d717202398ced5900e11e9 /src/modules/rlm_eap/libeap
parentAdding upstream version 3.2.3+dfsg. (diff)
downloadfreeradius-upstream.tar.xz
freeradius-upstream.zip
Adding upstream version 3.2.5+dfsg.upstream/3.2.5+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/modules/rlm_eap/libeap/eap_tls.c215
-rw-r--r--src/modules/rlm_eap/libeap/eap_tls.h6
-rw-r--r--src/modules/rlm_eap/libeap/eap_types.h4
-rw-r--r--src/modules/rlm_eap/libeap/eapcommon.c126
-rw-r--r--src/modules/rlm_eap/libeap/mppe_keys.c56
5 files changed, 317 insertions, 90 deletions
diff --git a/src/modules/rlm_eap/libeap/eap_tls.c b/src/modules/rlm_eap/libeap/eap_tls.c
index 2f37663..3a915bc 100644
--- a/src/modules/rlm_eap/libeap/eap_tls.c
+++ b/src/modules/rlm_eap/libeap/eap_tls.c
@@ -69,6 +69,9 @@ tls_session_t *eaptls_session(eap_handler_t *handler, fr_tls_server_conf_t *tls_
handler->tls = true;
+ tls_conf->name = dict_valnamebyattr(PW_EAP_TYPE, 0, handler->type);
+ if (!tls_conf->name) tls_conf->name = "???";
+
/*
* Every new session is started only from EAP-TLS-START.
* Before Sending EAP-TLS-START, open a new SSL session.
@@ -108,23 +111,22 @@ tls_session_t *eaptls_session(eap_handler_t *handler, fr_tls_server_conf_t *tls_
*/
int eaptls_start(EAP_DS *eap_ds, int peap_flag)
{
- EAPTLS_PACKET reply;
+ EAPTLS_PACKET reply;
- reply.code = FR_TLS_START;
- reply.length = TLS_HEADER_LEN + 1/*flags*/;
+ reply.code = FR_TLS_START;
+ reply.length = TLS_HEADER_LEN + 1/*flags*/;
- reply.flags = peap_flag;
- reply.flags = SET_START(reply.flags);
+ reply.flags = peap_flag;
+ reply.flags = SET_START(reply.flags);
- reply.data = NULL;
- reply.dlen = 0;
+ reply.data = NULL;
+ reply.dlen = 0;
- eaptls_compose(eap_ds, &reply);
+ eaptls_compose(eap_ds, &reply);
- return 1;
+ return 1;
}
-
/** Send an EAP-TLS success
*
* Composes an EAP-TLS-Success. This is a message with code EAP_TLS_ESTABLISHED.
@@ -186,12 +188,11 @@ int eaptls_success(eap_handler_t *handler, int peap_flag)
/* Should never happen */
rad_assert(0);
return 0;
- break;
}
eaptls_gen_mppe_keys(request,
tls_session->ssl, tls_session->label,
context, context_size);
- } else if (handler->type != PW_EAP_FAST) {
+ } else if ((handler->type != PW_EAP_FAST) && (handler->type != PW_EAP_TEAP)) {
RWDEBUG("(TLS) EAP Not adding MPPE keys because there is no PRF label");
}
@@ -230,13 +231,21 @@ int eaptls_fail(eap_handler_t *handler, int peap_flag)
* 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.
+ *
+ * FIXME: support fragmented start due to TEAP outer tlvs
*/
-int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn)
+int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn, bool start)
{
EAPTLS_PACKET reply;
unsigned int size;
- unsigned int nlen;
unsigned int lbit = 0;
+ unsigned int obit = 0;
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+ uint32_t nlen;
+ uint16_t ohdr[2];
+ uint32_t olen = 0;
+ uint32_t tls_mtu;
/* This value determines whether we set (L)ength flag for
EVERY packet we send and add corresponding
@@ -257,16 +266,46 @@ int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn)
if (ssn->length_flag) {
lbit = 4;
}
+
+ /*
+ * This is included in the first fragment, and then never
+ * afterwards.
+ */
+ if (start && ssn->outer_tlvs) {
+ for (vp = fr_cursor_init(&cursor, &ssn->outer_tlvs);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (vp->da->type != PW_TYPE_OCTETS) {
+ DEBUG("FIXME Outer-TLV %s is of not type octets", vp->da->name);
+ continue;
+ }
+ obit = 4;
+ olen += sizeof(ohdr) + vp->vp_length;
+ break;
+ }
+ }
+
if (ssn->fragment == 0) {
ssn->tls_msg_len = ssn->dirty_out.used;
}
- reply.code = FR_TLS_REQUEST;
+ reply.code = start ? FR_TLS_START : FR_TLS_REQUEST;
reply.flags = ssn->peap_flag;
+ if (start) reply.flags = SET_START(reply.flags);
+
+ /*
+ * This is only true for TEAP, so only TEAP has to check the return value of this function.
+ */
+ if (lbit + obit + olen >= ssn->mtu) {
+ ERROR("fragment_size is too small for outer TLVs");
+ return -1;
+ }
+
+ tls_mtu = ssn->mtu - lbit - obit - olen;
/* Send data, NOT more than the FRAGMENT size */
- if (ssn->dirty_out.used > ssn->mtu) {
- size = ssn->mtu;
+ if (ssn->dirty_out.used > tls_mtu) {
+ size = tls_mtu;
reply.flags = SET_MORE_FRAGMENTS(reply.flags);
/* Length MUST be included if it is the First Fragment */
if (ssn->fragment == 0) {
@@ -278,7 +317,7 @@ int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn)
ssn->fragment = 0;
}
- reply.dlen = lbit + size;
+ reply.dlen = lbit + obit + size + olen;
reply.length = TLS_HEADER_LEN + 1/*flags*/ + reply.dlen;
reply.data = talloc_array(eap_ds, uint8_t, reply.length);
@@ -286,10 +325,59 @@ int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn)
if (lbit) {
nlen = htonl(ssn->tls_msg_len);
- memcpy(reply.data, &nlen, lbit);
+ memcpy(reply.data, &nlen, sizeof(nlen));
reply.flags = SET_LENGTH_INCLUDED(reply.flags);
}
- (ssn->record_minus)(&ssn->dirty_out, reply.data + lbit, size);
+
+ if (obit) {
+ nlen = 0;
+ for (vp = fr_cursor_init(&cursor, &ssn->outer_tlvs);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (vp->da->type != PW_TYPE_OCTETS) continue;
+ nlen += sizeof(ohdr) + vp->vp_length;
+ }
+
+ ssn->outer_tlvs_octets = talloc_array(ssn, uint8_t, olen);
+ if (!ssn->outer_tlvs_octets) return 0;
+
+ nlen = htonl(nlen);
+ memcpy(reply.data + lbit, &nlen, sizeof(nlen));
+ reply.flags = SET_OUTER_TLV_INCLUDED(reply.flags);
+ }
+
+ (ssn->record_minus)(&ssn->dirty_out, reply.data + lbit + obit, size);
+
+ /*
+ * Tack on the outer TLVs after the TLS data.
+ */
+ if (obit) {
+ olen = 0;
+ for (vp = fr_cursor_init(&cursor, &ssn->outer_tlvs);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (vp->da->type != PW_TYPE_OCTETS) continue;
+
+ /* FIXME duplicates eap_teap_tlv_append */
+
+ /*
+ * RFC7170, Section 4.3.1 - Outer TLVs must be marked optional
+ */
+ ohdr[0] = htons((vp->da->attr >> fr_attr_shift[1]) & fr_attr_mask[1]);
+ ohdr[1] = htons(vp->vp_length);
+
+ /* use by Crypto-Binding TLV */
+ memcpy(ssn->outer_tlvs_octets + olen, ohdr, sizeof(ohdr));
+ olen += sizeof(ohdr);
+ memcpy(ssn->outer_tlvs_octets + olen, vp->vp_octets, vp->vp_length);
+ olen += vp->vp_length;
+
+ memcpy(reply.data + lbit + obit + size, ohdr, sizeof(ohdr));
+ size += sizeof(ohdr);
+ memcpy(reply.data + lbit + obit + size, vp->vp_octets, vp->vp_length);
+ size += vp->vp_length;
+ }
+ }
eaptls_compose(eap_ds, &reply);
talloc_free(reply.data);
@@ -425,6 +513,9 @@ static fr_tls_status_t eaptls_verify(eap_handler_t *handler)
* from a fragment acknowledgement.
*/
if (TLS_LENGTH_INCLUDED(eaptls_packet->flags)) {
+ /*
+ * data[0] and data[1] are always zero, vi eap_vp2packet()
+ */
size_t total_len = eaptls_packet->data[2] * 256 | eaptls_packet->data[3];
if (frag_len > total_len) {
@@ -463,6 +554,14 @@ static fr_tls_status_t eaptls_verify(eap_handler_t *handler)
return FR_TLS_FIRST_FRAGMENT;
}
+ /*
+ * The "O" bit is only allowed for the first fragment.
+ */
+ if (TLS_OUTER_TLV_INCLUDED(eaptls_packet->flags)) {
+ REDEBUG("(TLS) EAP Peer set 'O' bit after initial fragment");
+ return FR_TLS_INVALID;
+ }
+
RDEBUG2("(TLS) EAP Got additional fragment with length (%zu bytes). "
"Peer says more fragments will follow", frag_len);
@@ -494,6 +593,10 @@ static fr_tls_status_t eaptls_verify(eap_handler_t *handler)
}
/*
+ * eap_vp2packet() ensures that the 'O' bit is not set here.
+ */
+
+ /*
* The previous packet had the M flags set, but this one doesn't,
* this must be the final record fragment
*/
@@ -563,7 +666,7 @@ static EAPTLS_PACKET *eaptls_extract(REQUEST *request, EAP_DS *eap_ds, fr_tls_st
{
EAPTLS_PACKET *tlspacket;
uint32_t data_len = 0;
- uint32_t len = 0;
+ uint32_t obit = 0;
uint8_t *data = NULL;
if (status == FR_TLS_INVALID) return NULL;
@@ -599,36 +702,8 @@ static EAPTLS_PACKET *eaptls_extract(REQUEST *request, EAP_DS *eap_ds, fr_tls_st
tlspacket->flags = eap_ds->response->type.data[0];
/*
- * A quick sanity check of the flags. If we've been told
- * that there's a length, and there isn't one, then stop.
+ * eaptls_verify() ensures that all of the flags are correct.
*/
- if (TLS_LENGTH_INCLUDED(tlspacket->flags) &&
- (tlspacket->length < 5)) { /* flags + TLS message length */
- REDEBUG("(TLS) EAP Invalid packet received: Length bit is set,"
- "but packet too short to contain length field");
- talloc_free(tlspacket);
- return NULL;
- }
-
- /*
- * If the final TLS packet is larger than we can handle, die
- * now.
- *
- * Likewise, if the EAP packet says N bytes, and the TLS
- * packet says there's fewer bytes, it's a problem.
- */
- if (TLS_LENGTH_INCLUDED(tlspacket->flags)) {
- memcpy(&data_len, &eap_ds->response->type.data[1], 4);
- data_len = ntohl(data_len);
- if (data_len > MAX_RECORD_SIZE) {
- REDEBUG("(TLS) EAP Reassembled data will be %u bytes, "
- "greater than the size that we can handle (" STRINGIFY(MAX_RECORD_SIZE) " bytes)",
- data_len);
- talloc_free(tlspacket);
- return NULL;
- }
- }
-
switch (status) {
/*
* The TLS Message Length field is four octets, and
@@ -640,39 +715,28 @@ static EAPTLS_PACKET *eaptls_extract(REQUEST *request, EAP_DS *eap_ds, fr_tls_st
* length should solve the problem.
*/
case FR_TLS_FIRST_FRAGMENT:
- case FR_TLS_LENGTH_INCLUDED:
- case FR_TLS_MORE_FRAGMENTS_WITH_LENGTH:
- if (tlspacket->length < 5) { /* flags + TLS message length */
- REDEBUG("(TLS) EAP Invalid packet received: Expected length, got none");
- talloc_free(tlspacket);
- return NULL;
- }
+ obit = TLS_OUTER_TLV_INCLUDED(tlspacket->flags) << 2;
/*
- * Extract all the TLS fragments from the
- * previous eap_ds Start appending this
- * fragment to the above ds
+ * @todo - decode outer TLVs, too
*/
- memcpy(&data_len, &eap_ds->response->type.data[1], sizeof(uint32_t));
- data_len = ntohl(data_len);
- data = (eap_ds->response->type.data + 5/*flags+TLS-Length*/);
- len = eap_ds->response->type.length - 5/*flags+TLS-Length*/;
- /*
- * Hmm... this should be an error, too.
- */
- if (data_len > len) {
- data_len = len;
- }
- break;
+ /* FALL-THROUGH */
+
+ case FR_TLS_LENGTH_INCLUDED:
+ case FR_TLS_MORE_FRAGMENTS_WITH_LENGTH:
+ eap_ds->response->type.data += 4 + obit;
+ eap_ds->response->type.length -= 4 + obit;
+
+ /* FALL-THROUGH */
/*
* Data length is implicit, from the EAP header.
*/
case FR_TLS_MORE_FRAGMENTS:
case FR_TLS_OK:
- data_len = eap_ds->response->type.length - 1/*flags*/;
- data = eap_ds->response->type.data + 1/*flags*/;
+ data_len = eap_ds->response->type.length - 1;
+ data = eap_ds->response->type.data + 1;
break;
default:
@@ -689,6 +753,7 @@ static EAPTLS_PACKET *eaptls_extract(REQUEST *request, EAP_DS *eap_ds, fr_tls_st
talloc_free(tlspacket);
return NULL;
}
+
memcpy(tlspacket->data, data, data_len);
}
@@ -784,7 +849,7 @@ static fr_tls_status_t eaptls_operation(fr_tls_status_t status, eap_handler_t *h
* TLS proper can decide what to do, then.
*/
if (tls_session->dirty_out.used > 0) {
- eaptls_request(handler->eap_ds, tls_session);
+ eaptls_request(handler->eap_ds, tls_session, false);
return FR_TLS_HANDLED;
}
@@ -890,7 +955,7 @@ fr_tls_status_t eaptls_process(eap_handler_t *handler)
* of fragments" phase.
*/
case FR_TLS_REQUEST:
- eaptls_request(handler->eap_ds, tls_session);
+ eaptls_request(handler->eap_ds, tls_session, false);
status = FR_TLS_HANDLED;
goto done;
diff --git a/src/modules/rlm_eap/libeap/eap_tls.h b/src/modules/rlm_eap/libeap/eap_tls.h
index 8e5fc77..1112bcb 100644
--- a/src/modules/rlm_eap/libeap/eap_tls.h
+++ b/src/modules/rlm_eap/libeap/eap_tls.h
@@ -59,10 +59,14 @@ fr_tls_status_t eaptls_process(eap_handler_t *handler);
int eaptls_success(eap_handler_t *handler, int peap_flag) CC_HINT(nonnull);
int eaptls_fail(eap_handler_t *handler, int peap_flag) CC_HINT(nonnull);
-int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn) CC_HINT(nonnull);
+int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn, bool start) CC_HINT(nonnull);
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+void TLS_PRF(SSL *ssl, unsigned char *sec, size_t seclen, struct iovec *iov, size_t iovcnt, unsigned char *key, size_t keylen);
+#endif
void T_PRF(unsigned char const *secret, unsigned int secret_len, char const *prf_label, unsigned char const *seed, unsigned int seed_len, unsigned char *out, unsigned int out_len) CC_HINT(nonnull(1,3,6));
+void eaptls_gen_keys_only(REQUEST *request, SSL *s, char const *label, uint8_t const *context, UNUSED size_t context_size, uint8_t *out, size_t outlen);
void eaptls_gen_mppe_keys(REQUEST *request, SSL *s, char const *label, uint8_t const *context, size_t context_size);
void eapttls_gen_challenge(SSL *s, uint8_t *buffer, size_t size);
void eaptls_gen_eap_key(eap_handler_t *handler);
diff --git a/src/modules/rlm_eap/libeap/eap_types.h b/src/modules/rlm_eap/libeap/eap_types.h
index c6568ff..beee998 100644
--- a/src/modules/rlm_eap/libeap/eap_types.h
+++ b/src/modules/rlm_eap/libeap/eap_types.h
@@ -98,7 +98,9 @@ typedef enum eap_method {
PW_EAP_GPSK, /* 51 */
PW_EAP_PWD, /* 52 */
PW_EAP_EKE, /* 53 */
- PW_EAP_MAX_TYPES /* 54 - for validation */
+ PW_EAP_PT_EAP, /* 54 */
+ PW_EAP_TEAP, /* 55 */
+ PW_EAP_MAX_TYPES /* 56 - for validation */
} eap_type_t;
#define PW_EAP_EXPANDED_TYPE (254)
diff --git a/src/modules/rlm_eap/libeap/eapcommon.c b/src/modules/rlm_eap/libeap/eapcommon.c
index 96db30b..5abe47a 100644
--- a/src/modules/rlm_eap/libeap/eapcommon.c
+++ b/src/modules/rlm_eap/libeap/eapcommon.c
@@ -302,6 +302,7 @@ eap_packet_raw_t *eap_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps)
uint16_t len;
int total_len;
vp_cursor_t cursor;
+ bool allow_o = false;
/*
* Get only EAP-Message attribute list
@@ -315,7 +316,7 @@ eap_packet_raw_t *eap_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps)
/*
* Sanity check the length before doing anything.
*/
- if (first->vp_length < 4) {
+ if (first->vp_length < 5) {
fr_strerror_printf("EAP packet is too short");
return NULL;
}
@@ -330,8 +331,8 @@ eap_packet_raw_t *eap_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps)
/*
* Take out even more weird things.
*/
- if (len < 4) {
- fr_strerror_printf("EAP packet has invalid length (less than 4 bytes)");
+ if (len < 5) {
+ fr_strerror_printf("EAP packet has invalid length (less than 5 bytes)");
return NULL;
}
@@ -379,6 +380,125 @@ eap_packet_raw_t *eap_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps)
ptr += i->vp_length;
}
+ /*
+ * Do additional sanity check for TLS-based EAP types, so
+ * that we don't have to do any of that later.
+ */
+ switch (eap_packet->data[0]) {
+ /*
+ * 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 | Ver | Message Length :
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * : Message Length |
+ *
+ * Flags are:
+ *
+ * 7 6 5 4 3 2 1 0
+ * +-+-+-+-+-+-+-+-+
+ * |L M S O R R R R|
+ * +-+-+-+-+-+-+-+-+
+ *
+ * L = Length included
+ * M = More fragments
+ * S = EAP-TLS start
+ * O = outer TLV length included (4 octets, only for TEAP)
+ * R = Reserved
+ */
+ case PW_EAP_TEAP:
+ allow_o = true;
+ /* FALL-THROUGH */
+
+ case PW_EAP_TLS:
+ case PW_EAP_TTLS:
+ case PW_EAP_PEAP:
+ case PW_EAP_FAST:
+ if (len < 2) {
+ fr_strerror_printf("Malformed EAP packet - packet is too small to contain TLS flags");
+ talloc_free(eap_packet);
+ return NULL;
+ }
+
+ /*
+ * L bit set means we have 4 octets of Length
+ * following the flags field.
+ */
+ if ((eap_packet->data[1] & 0x80) != 0) {
+ uint32_t tls_len;
+
+ if (len <= (2 + 4)) {
+ fr_strerror_printf("Malformed EAP packet - TLS 'L' bit is set, but packet is too small to contain 'length' field");
+ talloc_free(eap_packet);
+ return NULL;
+ }
+
+ /*
+ * This is arguably wrong... a single TLS
+ * record is max 16K in length. But a
+ * TLS message may span multiple TLS
+ * records.
+ */
+ memcpy(&tls_len, eap_packet->data + 2, 4);
+ tls_len = ntohl(tls_len);
+ if (tls_len > 16384) {
+ fr_strerror_printf("Malformed EAP packet - TLS reassembled data length %u (%08x) (will be greater than the TLS maximum record size of 16384 bytes", tls_len, tls_len);
+ talloc_free(eap_packet);
+ return NULL;
+ }
+
+ /*
+ * O bit set means we have 4 octets of Outer TLV Length
+ * following the Length field.
+ */
+ if ((eap_packet->data[1] & 0x10) != 0) {
+ uint32_t tlv_len;
+
+ if (!allow_o) {
+ fr_strerror_printf("Malformed EAP packet - TLS 'O' bit is set, but EAP method does not use it.");
+ talloc_free(eap_packet);
+ return NULL;
+ }
+
+ if (len <= (2 + 4 + 4)) {
+ fr_strerror_printf("Malformed EAP packet - TLS 'O' bit is set, but packet is too small to contain 'outer tlv length' field");
+ talloc_free(eap_packet);
+ return NULL;
+ }
+
+ memcpy(&tlv_len, eap_packet->data + 2 + 4, 4);
+ tlv_len = ntohl(tlv_len);
+
+ /*
+ * The EAP header includes all of
+ * the data in the packet. The
+ * outer TLV length cannot
+ * include the EAP header, type,
+ * flags, length field, or outer
+ * tlv length field.
+ */
+ if ((int)tlv_len > (len - (2 + 4 + 4))) {
+ fr_strerror_printf("Malformed EAP packet - TLS 'O' bit is set, but 'outer tlv length' field is larger than the current fragment");
+ talloc_free(eap_packet);
+ return NULL;
+ }
+ }
+ } else {
+ if ((eap_packet->data[1] & 0x10) != 0) {
+ fr_strerror_printf("Malformed EAP packet - TLS 'O' bit is set, but 'L' bit is not set.");
+ talloc_free(eap_packet);
+ return NULL;
+ }
+
+ }
+ break;
+
+ default:
+ break;
+ }
+
return eap_packet;
}
diff --git a/src/modules/rlm_eap/libeap/mppe_keys.c b/src/modules/rlm_eap/libeap/mppe_keys.c
index 385441c..4356164 100644
--- a/src/modules/rlm_eap/libeap/mppe_keys.c
+++ b/src/modules/rlm_eap/libeap/mppe_keys.c
@@ -34,6 +34,35 @@ USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
#include <openssl/provider.h>
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+#include <openssl/kdf.h>
+
+void TLS_PRF(SSL *ssl,
+ unsigned char *sec, size_t seclen,
+ struct iovec *iov, size_t iovcnt,
+ unsigned char *key, size_t keylen)
+{
+ const EVP_MD *md = SSL_CIPHER_get_handshake_digest(SSL_get_current_cipher(ssl));
+ EVP_MD *unconst_md;
+ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_TLS1_PRF, NULL);
+
+ EVP_PKEY_derive_init(pctx);
+
+ memcpy(&unconst_md, &md, sizeof(md)); /* const issues */
+ EVP_PKEY_CTX_set_tls1_prf_md(pctx, unconst_md);
+
+ EVP_PKEY_CTX_set1_tls1_prf_secret(pctx, sec, seclen);
+
+ for (unsigned int i = 0; i < iovcnt; i++) {
+ EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, iov[i].iov_base, iov[i].iov_len);
+ }
+
+ EVP_PKEY_derive(pctx, key, &keylen);
+
+ EVP_PKEY_CTX_free(pctx);
+}
+#endif
+
/*
* TLS P_hash from RFC 2246/5246 section 5
*/
@@ -210,23 +239,20 @@ void T_PRF(unsigned char const *secret, unsigned int secret_len,
#define EAPTLS_MPPE_KEY_LEN 32
/*
- * Generate keys according to RFC 2716 and add to reply
+ * Generate keys according to RFC 5216 (section 2.3)
*/
-void eaptls_gen_mppe_keys(REQUEST *request, SSL *s, char const *label, uint8_t const *context, UNUSED size_t context_size)
+void eaptls_gen_keys_only(UNUSED REQUEST *request, SSL *s, char const *label, uint8_t const *context, UNUSED size_t context_size, uint8_t *out, size_t outlen)
{
- uint8_t out[4 * EAPTLS_MPPE_KEY_LEN];
- uint8_t *p;
- size_t len;
-
- len = strlen(label);
+ size_t len = strlen(label);
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
- if (SSL_export_keying_material(s, out, sizeof(out), label, len, context, context_size, context != NULL) != 1) {
+ if (SSL_export_keying_material(s, out, outlen, label, len, context, context_size, context != NULL) != 1) {
ERROR("Failed generating keying material");
return;
}
#else
{
+ uint8_t *p;
uint8_t seed[64 + (2 * SSL3_RANDOM_SIZE) + (context ? 2 + context_size : 0)];
uint8_t buf[4 * EAPTLS_MPPE_KEY_LEN];
@@ -255,9 +281,20 @@ void eaptls_gen_mppe_keys(REQUEST *request, SSL *s, char const *label, uint8_t c
}
PRF(s->session->master_key, s->session->master_key_length,
- seed, len, out, buf, sizeof(out));
+ seed, len, out, buf, outlen);
}
#endif
+}
+
+/*
+ * Generate keys according to RFC 5216 (section 2.3) and add to reply
+ */
+void eaptls_gen_mppe_keys(REQUEST *request, SSL *s, char const *label, uint8_t const *context, UNUSED size_t context_size)
+{
+ uint8_t out[4 * EAPTLS_MPPE_KEY_LEN];
+ uint8_t *p;
+
+ eaptls_gen_keys_only(request, s, label, context, context_size, out, sizeof(out));
p = out;
eap_add_reply(request, "MS-MPPE-Recv-Key", p, EAPTLS_MPPE_KEY_LEN);
@@ -268,7 +305,6 @@ void eaptls_gen_mppe_keys(REQUEST *request, SSL *s, char const *label, uint8_t c
eap_add_reply(request, "EAP-EMSK", out + 64, 64);
}
-
#define FR_TLS_PRF_CHALLENGE "ttls challenge"
/*