/*
* Copyright (C) 2011 Andreas Steffen
- * Copyright (C) 2011 HSR Hochschule fuer Technik Rapperswil
+ * HSR Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
*
* 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
*/
#include "eap_peap_server.h"
-#include "eap_peap_avp.h"
+#include "eap_peap.h"
#include <debug.h>
#include <daemon.h>
identification_t *peer;
/**
- * Current EAP-PEAP phase2 state
+ * Do EAP Identity authentication exchange?
*/
- bool start_phase2;
+ bool identity;
/**
- * Current EAP-PEAP phase2 TNC state
+ * Use Microsoft Statement of Health EAP exchange?
*/
- bool start_phase2_tnc;
+ bool soh;
/**
- * Starts phase 2 with EAP Identity request
+ * TLS exchange completed?
*/
- bool start_phase2_id;
+ bool tls_completed;
/**
- * Final EAP-PEAP phase2 result
+ * Result TLV sent?
*/
- eap_code_t phase2_result;
+ bool result_sent;
+
+ /**
+ * EAP-PEAP phase2 authentication result
+ */
+ status_t state;
/**
* Outer phase 1 EAP method
*/
- eap_method_t *ph1_method;
+ eap_method_t *ph1;
/**
* Current phase 2 EAP method
*/
- eap_method_t *ph2_method;
+ eap_method_t *ph2;
/**
* Pending outbound EAP message
*/
eap_payload_t *out;
-
- /**
- * AVP handler
- */
- eap_peap_avp_t *avp;
};
/**
- * Start EAP client authentication protocol
+ * Process a TLV request
*/
-static status_t start_phase2_auth(private_eap_peap_server_t *this)
+static status_t process_tlv(private_eap_peap_server_t *this,
+ bio_reader_t *reader)
{
- char *eap_type_str;
- u_int32_t vendor;
- eap_type_t type;
+ u_int16_t type, length, result;
+ chunk_t value;
+ bool mandatory;
+ status_t status = FAILED;
- eap_type_str = lib->settings->get_str(lib->settings,
- "%s.plugins.eap-peap.phase2_method", "mschapv2",
- charon->name);
- type = eap_type_from_string(eap_type_str, &vendor);
- if (type == 0)
- {
- DBG1(DBG_IKE, "unrecognized phase2 method \"%s\"", eap_type_str);
- return FAILED;
- }
- DBG1(DBG_IKE, "phase2 method %M selected", eap_type_get_names, &vendor, type);
- this->ph2_method = charon->eap->create_instance(charon->eap, type,
- vendor, EAP_SERVER, this->server, this->peer);
- if (this->ph2_method == NULL)
+ while (reader->remaining(reader))
{
- DBG1(DBG_IKE, "%M method not available",
- eap_type_get_names, &vendor, type);
+ if (!reader->read_uint16(reader, &type) ||
+ !reader->read_uint16(reader, &length))
+ {
+ return FAILED;
+ }
+ mandatory = type | MSTLV_MANDATORY;
+ type &= ~MSTLV_MANDATORY;
+ switch (type)
+ {
+ case MSTLV_RESULT:
+ if (length == sizeof(result) &&
+ reader->read_uint16(reader, &result) &&
+ result == MSTLV_RESULT_SUCCESS &&
+ this->state == SUCCESS)
+ {
+ status = SUCCESS;
+ continue;
+ }
+ break;
+ case MSTLV_CRYPTO_BINDING:
+ if (reader->read_data(reader, length, &value))
+ {
+ /* TODO: add crypto binding support */
+ continue;
+ }
+ break;
+ case MSTLV_SOH:
+ case MSTLV_SOH_REQUEST:
+ case MSTLV_VENDOR:
+ default:
+ DBG1(DBG_IKE, "%smandatory PEAP TLV %d",
+ mandatory ? "received " : "ignoring non-", type);
+ if (mandatory || !reader->read_data(reader, length, &value))
+ {
+ break;
+ }
+ continue;
+ }
return FAILED;
}
+ return status;
+}
- /* synchronize EAP message identifiers of inner protocol with outer */
- this->ph2_method->set_identifier(this->ph2_method,
- this->ph1_method->get_identifier(this->ph1_method) + 1);
+/**
+ * Process a full EAP packet, EAP_MSTLV or EAP_EXPANDED
+ */
+static status_t process_eap_with_header(private_eap_peap_server_t *this,
+ bio_reader_t *reader, u_int8_t code, u_int32_t type)
+{
+ u_int32_t vendor;
- if (this->ph2_method->initiate(this->ph2_method, &this->out) == NEED_MORE)
+ if (type != EAP_EXPANDED)
{
- return NEED_MORE;
+ DBG1(DBG_IKE, "received tunneled EAP-PEAP AVP [ EAP/%N/%N ]",
+ eap_code_short_names, code, eap_type_short_names, type);
}
- else
+ switch (type)
{
- DBG1(DBG_IKE, "%M method failed", eap_type_get_names, &vendor, type);
- return FAILED;
+ case EAP_MSTLV:
+ return process_tlv(this, reader);
+ case EAP_EXPANDED:
+ if (!reader->read_uint24(reader, &vendor) ||
+ !reader->read_uint32(reader, &type))
+ {
+ DBG1(DBG_IKE, "parsing PEAP inner expanded EAP header failed");
+ return FAILED;
+ }
+ DBG1(DBG_IKE, "received tunneled EAP-PEAP AVP [ EAP/%N/%M ]",
+ eap_code_short_names, code,
+ eap_type_get_names, &vendor, type);
+ /* TODO: process requested capabilities? */
+ break;
+ default:
+ break;
}
+ DBG1(DBG_IKE, "unsupported PEAP payload");
+ return FAILED;
}
/**
- * If configured, start EAP-TNC protocol
+ * Process EAP-Identity response
*/
-static status_t start_phase2_tnc(private_eap_peap_server_t *this)
+static status_t process_identity(private_eap_peap_server_t *this,
+ eap_payload_t *in)
{
- if (this->start_phase2_tnc && lib->settings->get_bool(lib->settings,
- "%s.plugins.eap-peap.phase2_tnc", FALSE, charon->name))
+ eap_payload_t *out;
+ chunk_t id;
+
+ switch (this->ph2->process(this->ph2, in, &out))
{
- DBG1(DBG_IKE, "phase2 method %N selected", eap_type_names, EAP_TNC);
- this->ph2_method = charon->eap->create_instance(charon->eap, EAP_TNC,
- 0, EAP_SERVER, this->server, this->peer);
- if (this->ph2_method == NULL)
- {
- DBG1(DBG_IKE, "%N method not available", eap_type_names, EAP_TNC);
+ case SUCCESS:
+ break;
+ case NEED_MORE:
+ /* not expected */
+ out->destroy(out);
return FAILED;
- }
- this->start_phase2_tnc = FALSE;
-
- /* synchronize EAP message identifiers of inner protocol with outer */
- this->ph2_method->set_identifier(this->ph2_method,
- this->ph1_method->get_identifier(this->ph1_method) + 1);
-
- if (this->ph2_method->initiate(this->ph2_method, &this->out) == NEED_MORE)
- {
- return NEED_MORE;
- }
- else
- {
- DBG1(DBG_IKE, "%N method failed", eap_type_names, EAP_TNC);
+ default:
return FAILED;
- }
}
- return SUCCESS;
+
+ if (this->ph2->get_msk(this->ph2, &id) == SUCCESS)
+ {
+ this->peer->destroy(this->peer);
+ this->peer = identification_create_from_data(id);
+ DBG1(DBG_IKE, "received tunneled EAP identity '%Y'", this->peer);
+ }
+ in->destroy(in);
+ this->ph2->destroy(this->ph2);
+ this->ph2 = NULL;
+ this->identity = FALSE;
+ return NEED_MORE;
}
-METHOD(tls_application_t, process, status_t,
- private_eap_peap_server_t *this, bio_reader_t *reader)
+/**
+ * Process Statement of Health response
+ */
+static status_t process_soh(private_eap_peap_server_t *this, eap_payload_t *in)
{
- chunk_t data = chunk_empty;
- status_t status;
- payload_t *payload;
- eap_payload_t *in;
- eap_code_t code;
- eap_type_t type = EAP_NAK, received_type;
- u_int32_t vendor, received_vendor;
+ eap_type_t type;
+ u_int32_t vendor;
- status = this->avp->process(this->avp, reader, &data,
- this->ph1_method->get_identifier(this->ph1_method));
- switch (status)
+ type = this->ph2->get_type(this->ph2, &vendor);
+ switch (this->ph2->process(this->ph2, in, &this->out))
{
case SUCCESS:
+ DBG1(DBG_IKE, "%N SoH exchange successful", eap_type_names,
+ EAP_PEAP, this->peer, eap_type_get_names, &vendor, type);
+ this->ph2->destroy(this->ph2);
+ this->ph2 = NULL;
break;
case NEED_MORE:
- return NEED_MORE;
+ break;
case FAILED:
default:
- return FAILED;
+ DBG1(DBG_IKE, "EAP-%M method failed",
+ eap_type_get_names, &vendor, type);
+ break;
}
+ in->destroy(in);
+ this->soh = FALSE;
+ return NEED_MORE;
+}
- in = eap_payload_create_data(data);
- DBG3(DBG_IKE, "%B", &data);
- chunk_free(&data);
- payload = (payload_t*)in;
+/**
+ * Process EAP authentication method response
+ */
+static status_t process_auth(private_eap_peap_server_t *this, eap_payload_t *in)
+{
+ eap_type_t type;
+ u_int32_t vendor;
+ type = this->ph2->get_type(this->ph2, &vendor);
+ switch (this->ph2->process(this->ph2, in, &this->out))
+ {
+ case SUCCESS:
+ DBG1(DBG_IKE, "%N phase2 authentication of '%Y' with %M successful",
+ eap_type_names, EAP_PEAP, this->peer,
+ eap_type_get_names, &vendor, type);
+ this->ph2->destroy(this->ph2);
+ this->ph2 = NULL;
+ this->state = SUCCESS;
+ break;
+ case NEED_MORE:
+ break;
+ case FAILED:
+ default:
+ DBG1(DBG_IKE, "EAP-%M method failed",
+ eap_type_get_names, &vendor, type);
+ this->state = FAILED;
+ break;
+ }
+ in->destroy(in);
+ return NEED_MORE;
+}
+
+/**
+ * Construct an EAP header and append data
+ */
+static eap_payload_t *construct_eap(private_eap_peap_server_t *this,
+ chunk_t data)
+{
+ payload_t *payload;
+ eap_payload_t *eap;
+ eap_hdr_t hdr = {
+ .code = EAP_RESPONSE,
+ .identifier = this->ph1->get_identifier(this->ph1),
+ .length = ntohs(data.len + sizeof(hdr)),
+ };
+
+ data = chunk_cat("cc", chunk_from_thing(hdr), data);
+ eap = eap_payload_create_data_own(data);
+ payload = &eap->payload_interface;
if (payload->verify(payload) != SUCCESS)
{
- in->destroy(in);
- return FAILED;
+ eap->destroy(eap);
+ return NULL;
}
+ return eap;
+}
- code = in->get_code(in);
- if (code == EAP_REQUEST || code == EAP_RESPONSE)
+METHOD(tls_application_t, process, status_t,
+ private_eap_peap_server_t *this, bio_reader_t *reader)
+{
+ u_int8_t code, identifier, type;
+ u_int16_t length;
+ u_int32_t vendor;
+ eap_payload_t *in;
+ chunk_t chunk;
+
+ /* EAP_MSTLV and the capabilities EAP_EXPANDED come with a full EAP header,
+ * identity, SoH and the authentication method with a compressed header.
+ * Try to deduce what we got. */
+ chunk = reader->peek(reader);
+ if (!chunk.len)
{
- received_type = in->get_type(in, &received_vendor);
- DBG1(DBG_IKE, "received tunneled EAP-PEAP AVP [ EAP/%N/%N ]",
- eap_code_short_names, code,
- eap_type_short_names, received_type);
- if (code != EAP_RESPONSE)
- {
- DBG1(DBG_IKE, "%N expected", eap_code_names, EAP_RESPONSE);
- in->destroy(in);
- return FAILED;
- }
+ return NEED_MORE;
}
- else
+ if (chunk.len > sizeof(eap_hdr_t) &&
+ reader->read_uint8(reader, &code) &&
+ reader->read_uint8(reader, &identifier) &&
+ reader->read_uint16(reader, &length) &&
+ reader->read_uint8(reader, &type) &&
+ code == EAP_RESPONSE &&
+ identifier == this->ph1->get_identifier(this->ph1))
{
- DBG1(DBG_IKE, "received tunneled EAP-PEAP AVP [ EAP/%N ]",
- eap_code_short_names, code);
-
- /* if EAP_SUCCESS check if to continue phase2 with EAP-TNC */
- return (this->phase2_result == EAP_SUCCESS && code == EAP_SUCCESS) ?
- start_phase2_tnc(this) : FAILED;
+ return process_eap_with_header(this, reader, code, type);
}
- if (this->ph2_method)
+ if (chunk.ptr[0] == EAP_NAK)
{
- type = this->ph2_method->get_type(this->ph2_method, &vendor);
-
- if (type != received_type || vendor != received_vendor)
- {
- if (received_vendor == 0 && received_type == EAP_NAK)
- {
- DBG1(DBG_IKE, "peer does not support %N", eap_type_names, type);
- }
- else
- {
- DBG1(DBG_IKE, "received invalid EAP response");
- }
- in->destroy(in);
- return FAILED;
- }
+ DBG1(DBG_IKE, "received EAP-NAK within EAP-PEAP, aborting");
+ return FAILED;
}
-
- if (!received_vendor && received_type == EAP_IDENTITY)
+ if (!this->ph2)
{
- chunk_t eap_id;
-
- if (this->ph2_method == NULL)
- {
- /* Received an EAP Identity response without a matching request */
- this->ph2_method = charon->eap->create_instance(charon->eap,
- EAP_IDENTITY, 0, EAP_SERVER,
- this->server, this->peer);
- if (this->ph2_method == NULL)
- {
- DBG1(DBG_IKE, "%N method not available",
- eap_type_names, EAP_IDENTITY);
- return FAILED;
- }
- }
+ return FAILED;
+ }
+ in = construct_eap(this, chunk);
+ /* consume peeked reader bytes */
+ reader->read_data(reader, reader->remaining(reader), &chunk);
+ if (!in)
+ {
+ return FAILED;
+ }
- if (this->ph2_method->process(this->ph2_method, in, &this->out) != SUCCESS)
- {
+ type = in->get_type(in, &vendor);
+ DBG1(DBG_IKE, "received tunneled EAP-PEAP AVP [ EAP/%N/%M ]",
+ eap_code_short_names, EAP_RESPONSE, eap_type_get_names, &vendor, type);
- DBG1(DBG_IKE, "%N method failed", eap_type_names, EAP_IDENTITY);
- return FAILED;
- }
+ if (this->identity)
+ {
+ return process_identity(this, in);
+ }
+ if (this->soh)
+ {
+ return process_soh(this, in);
+ }
+ return process_auth(this, in);
+}
- if (this->ph2_method->get_msk(this->ph2_method, &eap_id) == SUCCESS)
- {
- this->peer->destroy(this->peer);
- this->peer = identification_create_from_data(eap_id);
- DBG1(DBG_IKE, "received EAP identity '%Y'", this->peer);
- }
+/**
+ * Build result TLV
+ */
+static status_t build_result(private_eap_peap_server_t *this,
+ bio_writer_t *writer, eap_mstlv_result_t result)
+{
+ writer->write_uint8(writer, EAP_REQUEST);
+ writer->write_uint8(writer, this->ph1->get_identifier(this->ph1));
+ /* write complete EAP packet length */
+ writer->write_uint16(writer, 11);
+ writer->write_uint8(writer, EAP_MSTLV);
+ /* TLV type: Result */
+ writer->write_uint16(writer, MSTLV_RESULT | MSTLV_MANDATORY);
+ /* TLV length */
+ writer->write_uint16(writer, 2);
+ writer->write_uint16(writer, result);
+
+ DBG1(DBG_IKE, "sending tunneled EAP-PEAP AVP [ EAP/%N/%N ]",
+ eap_code_short_names, EAP_REQUEST, eap_type_short_names, EAP_MSTLV);
+
+ this->result_sent = TRUE;
+
+ return NEED_MORE;
+}
- in->destroy(in);
- this->ph2_method->destroy(this->ph2_method);
- this->ph2_method = NULL;
+/**
+ * Write stored EAP payload to writer
+ */
+static status_t build_eap(private_eap_peap_server_t *this, bio_writer_t *writer)
+{
+ u_int32_t type, vendor;
+ chunk_t data;
- /* Start Phase 2 of EAP-PEAP authentication */
- if (lib->settings->get_bool(lib->settings,
- "%s.plugins.eap-peap.request_peer_auth", FALSE, charon->name))
- {
- return start_phase2_tnc(this);
- }
- else
- {
- return start_phase2_auth(this);
- }
+ if (!this->out)
+ {
+ return INVALID_STATE;
}
+ type = this->out->get_type(this->out, &vendor);
+ DBG1(DBG_IKE, "sending tunneled EAP-PEAP AVP [ EAP/%N/%M ]",
+ eap_code_short_names, this->out->get_code(this->out),
+ eap_type_get_names, &vendor, type);
+
+ data = this->out->get_data(this->out);
- if (this->ph2_method == 0)
+ if (!(vendor == 0 && type == EAP_MSTLV) &&
+ !(vendor == PEN_MICROSOFT && type == EAP_MS_CAPABILITES))
{
- DBG1(DBG_IKE, "no %N phase2 method installed", eap_type_names, EAP_PEAP);
- in->destroy(in);
- return FAILED;
+ /* remove EAP header for compressed types */
+ data = chunk_skip(data, sizeof(eap_hdr_t));
}
+ writer->write_data(writer, data);
- status = this->ph2_method->process(this->ph2_method, in, &this->out);
- in->destroy(in);
+ this->out->destroy(this->out);
+ this->out = NULL;
- switch (status)
+ return NEED_MORE;
+}
+
+/**
+ * Initiate an arbitrary EAP method
+ */
+static status_t initiate_eap(private_eap_peap_server_t *this, eap_type_t type,
+ u_int32_t vendor, bio_writer_t *writer)
+{
+ this->ph2 = charon->eap->create_instance(charon->eap, type,
+ vendor, EAP_SERVER, this->server, this->peer);
+ if (!this->ph2)
{
- case SUCCESS:
- DBG1(DBG_IKE, "%N phase2 authentication of '%Y' with %N successful",
- eap_type_names, EAP_PEAP, this->peer,
- eap_type_names, type);
- this->ph2_method->destroy(this->ph2_method);
- this->ph2_method = NULL;
-
- /* EAP-PEAP requires the sending of an inner EAP_SUCCESS message */
- this->phase2_result = EAP_SUCCESS;
- this->out = eap_payload_create_code(this->phase2_result, 1 +
- this->ph1_method->get_identifier(this->ph1_method));
- return NEED_MORE;
- case NEED_MORE:
- break;
- case FAILED:
- default:
- if (vendor)
- {
- DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed",
- type, vendor);
- }
- else
- {
- DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
- }
- /* EAP-PEAP requires the sending of an inner EAP_FAILURE message */
- this->phase2_result = EAP_FAILURE;
- this->out = eap_payload_create_code(this->phase2_result, 1 +
- this->ph1_method->get_identifier(this->ph1_method));
- return NEED_MORE;
+ DBG1(DBG_IKE, "EAP-%M method not available",
+ eap_type_get_names, &vendor, type);
+ return FAILED;
}
- return status;
+ this->ph2->set_identifier(this->ph2, this->ph1->get_identifier(this->ph1));
+ if (this->ph2->initiate(this->ph2, &this->out) != NEED_MORE)
+ {
+ DBG1(DBG_IKE, "initiating %M within PEAP failed",
+ eap_type_get_names, &vendor, type);
+ return FAILED;
+ }
+ return build_eap(this, writer);
}
-METHOD(tls_application_t, build, status_t,
- private_eap_peap_server_t *this, bio_writer_t *writer)
+/**
+ * Initiate inner authentication method
+ */
+static status_t initiate_auth(private_eap_peap_server_t *this,
+ bio_writer_t *writer)
{
- chunk_t data;
- eap_code_t code;
eap_type_t type;
u_int32_t vendor;
+ char *str;
- if (this->ph2_method == NULL && this->start_phase2 && this->start_phase2_id)
+ str = lib->settings->get_str(lib->settings,
+ "%s.plugins.eap-peap.ph2_method", "mschapv2",
+ charon->name);
+ type = eap_type_from_string(str, &vendor);
+ if (!type)
{
- /*
- * Start Phase 2 with an EAP Identity request either piggybacked right
- * onto the TLS Finished payload or delayed after the reception of an
- * empty EAP Acknowledge message.
- */
- this->ph2_method = charon->eap->create_instance(charon->eap, EAP_IDENTITY,
- 0, EAP_SERVER, this->server, this->peer);
- if (this->ph2_method == NULL)
- {
- DBG1(DBG_IKE, "%N method not available",
- eap_type_names, EAP_IDENTITY);
- return FAILED;
- }
-
- /* synchronize EAP message identifiers of inner protocol with outer */
- this->ph2_method->set_identifier(this->ph2_method,
- this->ph1_method->get_identifier(this->ph1_method));
-
- this->ph2_method->initiate(this->ph2_method, &this->out);
- this->start_phase2 = FALSE;
+ DBG1(DBG_IKE, "unknown EAP method: %s", str);
+ return FAILED;
}
+ DBG1(DBG_IKE, "initiating %N inner authentication with EAP-%M",
+ eap_type_names, EAP_PEAP, eap_type_get_names, &vendor, type);
+ return initiate_eap(this, type, vendor, writer);
+}
- this->start_phase2_id = TRUE;
-
- if (this->out)
+METHOD(tls_application_t, build, status_t,
+ private_eap_peap_server_t *this, bio_writer_t *writer)
+{
+ if (!this->tls_completed)
{
- code = this->out->get_code(this->out);
- type = this->out->get_type(this->out, &vendor);
- if (code == EAP_REQUEST || code == EAP_RESPONSE)
- {
- DBG1(DBG_IKE, "sending tunneled EAP-PEAP AVP [EAP/%N/%N]",
- eap_code_short_names, code, eap_type_short_names, type);
- }
- else
- {
- DBG1(DBG_IKE, "sending tunneled EAP-PEAP AVP [EAP/%N]",
- eap_code_short_names, code);
- }
-
- /* get the raw EAP message data */
- data = this->out->get_data(this->out);
- DBG3(DBG_IKE, "%B", &data);
- this->avp->build(this->avp, writer, data);
+ /* don't piggyback application data to TLS handshake */
+ this->tls_completed = TRUE;
+ return INVALID_STATE;
+ }
- this->out->destroy(this->out);
- this->out = NULL;
+ switch (this->state)
+ {
+ case NEED_MORE:
+ if (this->ph2)
+ {
+ return build_eap(this, writer);
+ }
+ if (this->identity)
+ {
+ return initiate_eap(this, EAP_IDENTITY, 0, writer);
+ }
+ if (this->soh)
+ {
+ return initiate_eap(this, EAP_MS_SOH, PEN_MICROSOFT, writer);
+ }
+ return initiate_auth(this, writer);
+ case SUCCESS:
+ if (this->result_sent)
+ {
+ return INVALID_STATE;
+ }
+ return build_result(this, writer, MSTLV_RESULT_SUCCESS);
+ case FAILED:
+ if (this->result_sent)
+ {
+ return INVALID_STATE;
+ }
+ return build_result(this, writer, MSTLV_RESULT_FAILURE);
+ default:
+ return FAILED;
}
- return INVALID_STATE;
}
METHOD(tls_application_t, destroy, void,
{
this->server->destroy(this->server);
this->peer->destroy(this->peer);
- DESTROY_IF(this->ph2_method);
+ DESTROY_IF(this->ph2);
DESTROY_IF(this->out);
- this->avp->destroy(this->avp);
free(this);
}
},
.server = server->clone(server),
.peer = peer->clone(peer),
- .ph1_method = eap_method,
- .start_phase2 = TRUE,
- .start_phase2_tnc = TRUE,
- .start_phase2_id = lib->settings->get_bool(lib->settings,
- "%s.plugins.eap-peap.phase2_piggyback",
- FALSE, charon->name),
- .phase2_result = EAP_FAILURE,
- .avp = eap_peap_avp_create(TRUE),
+ .ph1 = eap_method,
+ .state = NEED_MORE,
+ .identity = lib->settings->get_bool(lib->settings,
+ "%s.plugins.eap-peap.identity", TRUE, charon->name),
+ .soh = lib->settings->get_bool(lib->settings,
+ "%s.plugins.eap-peap.soh", FALSE, charon->name),
);
return &this->public;