]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
API changes and preparation for allowing outer TLVs
authorAlan T. DeKok <aland@freeradius.org>
Tue, 30 May 2023 14:41:14 +0000 (10:41 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Tue, 30 May 2023 14:41:14 +0000 (10:41 -0400)
src/modules/rlm_eap/libeap/eap_tls.c
src/modules/rlm_eap/libeap/eap_tls.h
src/modules/rlm_eap/libeap/eap_types.h
src/modules/rlm_eap/libeap/eapcommon.c
src/modules/rlm_eap/libeap/mppe_keys.c
src/modules/rlm_eap/types/rlm_eap_fast/rlm_eap_fast.c
src/modules/rlm_eap/types/rlm_eap_peap/peap.c
src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c
src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c
src/modules/rlm_eap/types/rlm_eap_ttls/rlm_eap_ttls.c
src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c

index 2f37663df142a3e22867a51330d8d05eddb0df00..0ad1c255b7268b5894fd8d4cf907950871b5da73 100644 (file)
@@ -102,29 +102,6 @@ tls_session_t *eaptls_session(eap_handler_t *handler, fr_tls_server_conf_t *tls_
        return talloc_steal(handler, ssn); /* ssn */
 }
 
-/*
-   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 = FR_TLS_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;
-}
-
-
 /** Send an EAP-TLS success
  *
  * Composes an EAP-TLS-Success.  This is a message with code EAP_TLS_ESTABLISHED.
@@ -191,7 +168,7 @@ int eaptls_success(eap_handler_t *handler, int peap_flag)
                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 +207,20 @@ 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;
 
        /* This value determines whether we set (L)ength flag for
                EVERY packet we send and add corresponding
@@ -257,12 +241,31 @@ 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;
+                       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);
 
        /* Send data, NOT more than the FRAGMENT size */
        if (ssn->dirty_out.used > ssn->mtu) {
@@ -278,7 +281,16 @@ int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn)
                ssn->fragment = 0;
        }
 
-       reply.dlen = lbit + size;
+       if (obit) {
+               for (vp = fr_cursor_init(&cursor, &ssn->outer_tlvs);
+                    vp;
+                    vp = fr_cursor_next(&cursor)) {
+                       if (vp->da->type != PW_TYPE_OCTETS) continue;
+                       olen += sizeof(ohdr) + vp->vp_length;
+               }
+       }
+
+       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 +298,58 @@ 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 +485,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 +526,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);
 
@@ -493,6 +564,10 @@ static fr_tls_status_t eaptls_verify(eap_handler_t *handler)
                return FR_TLS_LENGTH_INCLUDED;
        }
 
+       /*
+        *      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 +638,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 +674,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.
-        */
-       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.
+        *      eaptls_verify() ensures that all of the flags are correct.
         */
-       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,30 +687,19 @@ 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;
-               }
+               /* FALL-THROUGH */
+
+       case FR_TLS_LENGTH_INCLUDED:
+       case FR_TLS_MORE_FRAGMENTS_WITH_LENGTH:
+               memcpy(&data_len, &eap_ds->response->type.data[1], 4);
+               data_len = ntohl(data_len);
+               data = eap_ds->response->type.data + 5 + obit;
                break;
 
                /*
@@ -671,8 +707,8 @@ static EAPTLS_PACKET *eaptls_extract(REQUEST *request, EAP_DS *eap_ds, fr_tls_st
                 */
        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 +725,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 +821,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 +927,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;
 
index 8e5fc773d61d3dd219c8af9fdcb867890bd352b4..08713aa0a1c3c2b2d06bb3b1923832ef705beaed 100644 (file)
@@ -59,10 +59,12 @@ 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);
 
 
+void   TLS_PRF(SSL *ssl, unsigned char *sec, size_t seclen, struct iovec *iov, size_t iovcnt, unsigned char *key, size_t keylen);
 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);
@@ -101,7 +103,6 @@ typedef struct tls_packet {
 EAPTLS_PACKET  *eaptls_alloc(void);
 void           eaptls_free(EAPTLS_PACKET **eaptls_packet_ptr);
 tls_session_t  *eaptls_session(eap_handler_t *handler, fr_tls_server_conf_t *tls_conf, bool client_cert, bool allow_tls13);
-int            eaptls_start(EAP_DS *eap_ds, int peap);
 int            eaptls_compose(EAP_DS *eap_ds, EAPTLS_PACKET *reply);
 
 fr_tls_server_conf_t *eaptls_conf_parse(CONF_SECTION *cs, char const *key);
index c6568ffedf26ab895717e9de961ffde82f011224..beee998651bc47d5f11b42d47a06f70f806129e2 100644 (file)
@@ -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)
index 96db30b1441858173116df26abc383a9971da72c..4f85fd3735e965385c0d3e5321de6a729863987e 100644 (file)
@@ -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 > MAX_RECORD_SIZE) {
+                               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;
 }
 
index 385441c62ff409762aefdea20900f7606bbeb05e..4a542909357e0cf32ea25d880e9c9f2b4dd7bbf2 100644 (file)
@@ -26,6 +26,7 @@ RCSID("$Id$")
 USES_APPLE_DEPRECATED_API      /* OpenSSL API has been deprecated by Apple */
 
 #include "eap_tls.h"
+#include <openssl/kdf.h>
 #include <openssl/ssl.h>
 #include <openssl/hmac.h>
 #include <freeradius-devel/openssl3.h>
@@ -34,6 +35,28 @@ USES_APPLE_DEPRECATED_API    /* OpenSSL API has been deprecated by Apple */
 #include <openssl/provider.h>
 #endif
 
+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_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_TLS1_PRF, NULL);
+
+       EVP_PKEY_derive_init(pctx);
+       EVP_PKEY_CTX_set_tls1_prf_md(pctx, 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);
+}
+
 /*
  *     TLS P_hash from RFC 2246/5246 section 5
  */
@@ -210,23 +233,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 +275,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 +299,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"
 
 /*
index 093dc868cd0c32e487d442da21f5ba84f7ab2d09..d1f45b7976b006f8cee77555bc8e130862eacdbb 100644 (file)
@@ -479,7 +479,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
        case PW_CODE_ACCESS_CHALLENGE:
                RDEBUG("Challenge");
                tls_handshake_send(request, tls_session);
-               eaptls_request(handler->eap_ds, tls_session);
+               eaptls_request(handler->eap_ds, tls_session, false);
                ret = 1;
                goto done;
 
index a8589aeaea4dc61370cc6d6d5ef44743bd295183..bf842430373b10dcadbb5576e101c0ba105192c0 100644 (file)
@@ -591,8 +591,6 @@ static int CC_HINT(nonnull) eappeap_postproxy(eap_handler_t *handler, void *data
                        fprintf(fr_log_fp, "server %s {\n", fake->server);
                }
 
-               fake->reply->code = PW_CODE_ACCESS_ACCEPT;
-
                /*
                 *      Perform a post-auth stage, which will get the EAP
                 *      handler, too...
@@ -667,7 +665,7 @@ static int CC_HINT(nonnull) eappeap_postproxy(eap_handler_t *handler, void *data
 
        case RLM_MODULE_HANDLED:
                RDEBUG2("Reply was handled");
-               eaptls_request(handler->eap_ds, tls_session);
+               eaptls_request(handler->eap_ds, tls_session, false);
                request->proxy_reply->code = PW_CODE_ACCESS_CHALLENGE;
                return 1;
 
index d9f850cef27441dabc04c99040466741e2f7fe19..704b86c2629d2e62c1fdf45f092e51e328a91de2 100644 (file)
@@ -233,7 +233,7 @@ static int mod_session_init(void *type_arg, eap_handler_t *handler)
         *      TLS session initialization is over.  Now handle TLS
         *      related handshaking or application data.
         */
-       status = eaptls_start(handler->eap_ds, ssn->peap_flag);
+       status = eaptls_request(handler->eap_ds, ssn, true);
        if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
                REDEBUG("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
        } else {
@@ -357,7 +357,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
                goto done;
 
        case RLM_MODULE_HANDLED:
-               eaptls_request(handler->eap_ds, tls_session);
+               eaptls_request(handler->eap_ds, tls_session, false);
                ret = 1;
                goto done;
 
index d327c575fc8ff204e9f980cd64ee8bb22e716c8a..7a78fb6f5dae1c955eb528040e1a9ede512def6a 100644 (file)
@@ -135,7 +135,7 @@ static int mod_session_init(void *type_arg, eap_handler_t *handler)
         *      TLS session initialization is over.  Now handle TLS
         *      related handshaking or application data.
         */
-       status = eaptls_start(handler->eap_ds, ssn->peap_flag);
+       status = eaptls_request(handler->eap_ds, ssn, true);
        if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
                REDEBUG("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
        } else {
index 4e53c92244bae998879ceed27a1b4e192ff2568c..035a1f6044ad121939682c237862515c0c794b05 100644 (file)
@@ -204,7 +204,7 @@ static int mod_session_init(void *type_arg, eap_handler_t *handler)
         *      TLS session initialization is over.  Now handle TLS
         *      related handshaking or application data.
         */
-       status = eaptls_start(handler->eap_ds, ssn->peap_flag);
+       status = eaptls_request(handler->eap_ds, ssn, true);
        if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
                REDEBUG("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
        } else {
@@ -284,7 +284,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
                        ret = eaptls_success(handler, 0);
                        goto done;
                } else {
-                       eaptls_request(handler->eap_ds, tls_session);
+                       eaptls_request(handler->eap_ds, tls_session, false);
                }
                ret = 1;
                goto done;
@@ -341,7 +341,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
                 *      Access-Challenge, continue tunneled conversation.
                 */
        case PW_CODE_ACCESS_CHALLENGE:
-               eaptls_request(handler->eap_ds, tls_session);
+               eaptls_request(handler->eap_ds, tls_session, false);
                ret = 1;
                goto done;
 
index cbe423951a7a27f5da1ded6eb12fd7e9587ccaed..f4d28660cfb812233c0ad7a96517d5c14944b546 100644 (file)
@@ -914,7 +914,7 @@ static int CC_HINT(nonnull) eapttls_postproxy(eap_handler_t *handler, void *data
 
        case RLM_MODULE_HANDLED:
                RDEBUG("Reply was handled");
-               eaptls_request(handler->eap_ds, tls_session);
+               eaptls_request(handler->eap_ds, tls_session, false);
                request->proxy_reply->code = PW_CODE_ACCESS_CHALLENGE;
                return 1;