diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c index c9e6db5d2..44c619d62 100644 --- a/src/eap_peer/eap_peap.c +++ b/src/eap_peer/eap_peap.c @@ -21,6 +21,7 @@ #include "eap_config.h" #include "tls.h" #include "eap_common/eap_tlv_common.h" +#include "tncc.h" /* Maximum supported PEAP version @@ -65,6 +66,8 @@ struct eap_peap_data { int crypto_binding_used; u8 ipmk[40]; u8 cmk[20]; + int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP) + * is enabled. */ }; @@ -112,6 +115,13 @@ static int eap_peap_parse_phase1(struct eap_peap_data *data, wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding"); } +#ifdef EAP_TNC + if (os_strstr(phase1, "tnc=soh")) { + data->soh = 1; + wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH enabled"); + } +#endif /* EAP_TNC */ + return 0; } @@ -697,6 +707,38 @@ static int eap_peap_phase2_request(struct eap_sm *sm, data->phase2_success = 1; } break; + case EAP_TYPE_EXPANDED: +#ifdef EAP_TNC + if (data->soh) { + const u8 *epos; + size_t eleft; + + epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, + req, &eleft); + if (epos) { + struct wpabuf *buf; + wpa_printf(MSG_DEBUG, + "EAP-PEAP: SoH EAP Extensions"); + buf = tncc_process_soh_request(epos, eleft); + if (buf) { + *resp = eap_msg_alloc( + EAP_VENDOR_MICROSOFT, 0x21, + wpabuf_len(buf), + EAP_CODE_RESPONSE, + hdr->identifier); + if (*resp == NULL) { + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + return -1; + } + wpabuf_put_buf(*resp, buf); + wpabuf_free(buf); + break; + } + } + } +#endif /* EAP_TNC */ + /* fall through */ default: if (data->phase2_type.vendor == EAP_VENDOR_IETF && data->phase2_type.method == EAP_TYPE_NONE) { diff --git a/src/eap_peer/tncc.c b/src/eap_peer/tncc.c index 2f95b5376..cdbfc6388 100644 --- a/src/eap_peer/tncc.c +++ b/src/eap_peer/tncc.c @@ -20,6 +20,8 @@ #include "common.h" #include "base64.h" #include "tncc.h" +#include "eap_common/eap_tlv_common.h" +#include "eap_common/eap_defs.h" #ifdef UNICODE @@ -1202,3 +1204,116 @@ void tncc_deinit(struct tncc_data *tncc) os_free(tncc); } + + +static struct wpabuf * tncc_build_soh(void) +{ + struct wpabuf *buf; + u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end; + u8 correlation_id[24]; + int ver = 2; + + if (os_get_random(correlation_id, sizeof(correlation_id))) + return NULL; + wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID", + correlation_id, sizeof(correlation_id)); + + buf = wpabuf_alloc(200); + if (buf == NULL) + return NULL; + + /* Vendor-Specific TLV (Microsoft) - SoH */ + wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */ + tlv_len = wpabuf_put(buf, 2); /* Length */ + wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */ + wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */ + tlv_len2 = wpabuf_put(buf, 2); /* Length */ + + /* SoH Header */ + wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */ + outer_len = wpabuf_put(buf, 2); + wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ + wpabuf_put_be16(buf, ver); /* Inner Type */ + inner_len = wpabuf_put(buf, 2); + + if (ver == 2) { + /* SoH Mode Sub-Header */ + /* Outer Type */ + wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); + wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */ + wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ + /* Value: */ + wpabuf_put_data(buf, correlation_id, sizeof(correlation_id)); + wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */ + wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */ + } + + /* SSoH TLV */ + /* System-Health-Id */ + wpabuf_put_be16(buf, 0x0002); /* Type */ + wpabuf_put_be16(buf, 4); /* Length */ + wpabuf_put_be32(buf, 79616); + /* Vendor-Specific Attribute */ + wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); + ssoh_len = wpabuf_put(buf, 2); + wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ + /* TODO: MS-Machine-Inventory */ + /* TODO: MS-Quarantine-State */ + /* MS-Packet-Info */ + wpabuf_put_u8(buf, 0x03); + wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */ + /* TODO: MS-MachineName */ + /* MS-CorrelationId */ + wpabuf_put_u8(buf, 0x06); + wpabuf_put_data(buf, correlation_id, sizeof(correlation_id)); + end = wpabuf_put(buf, 0); + WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2); + + /* TODO: SoHReportEntry TLV (zero or more) */ + + /* Update length fields */ + end = wpabuf_put(buf, 0); + WPA_PUT_BE16(tlv_len, end - tlv_len - 2); + WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2); + WPA_PUT_BE16(outer_len, end - outer_len - 2); + WPA_PUT_BE16(inner_len, end - inner_len - 2); + + return buf; +} + + +struct wpabuf * tncc_process_soh_request(const u8 *data, size_t len) +{ + const u8 *pos; + + wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len); + + if (len < 12) + return NULL; + + /* SoH Request */ + pos = data; + + /* TLV Type */ + if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV) + return NULL; + pos += 2; + + /* Length */ + if (WPA_GET_BE16(pos) < 8) + return NULL; + pos += 2; + + /* Vendor_Id */ + if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT) + return NULL; + pos += 4; + + /* TLV Type */ + if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */) + return NULL; + + wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received"); + + return tncc_build_soh(); +} diff --git a/src/eap_peer/tncc.h b/src/eap_peer/tncc.h index b73738f0a..984721233 100644 --- a/src/eap_peer/tncc.h +++ b/src/eap_peer/tncc.h @@ -37,4 +37,6 @@ enum tncc_process_res { enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc, const u8 *msg, size_t len); +struct wpabuf * tncc_process_soh_request(const u8 *data, size_t len); + #endif /* TNCC_H */