u8 *key_data;
struct wpabuf *pending_phase2_req;
-
+ int chbind_req_sent; /* channel binding request was sent */
#ifdef EAP_TNC
int ready_for_tnc;
int tnc_started;
};
+/* draft-ietf-emu-chbind-13 section 5.3 */
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct chbind_hdr {
+ u16 len;
+ u8 nsid;
+};
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+
static void * eap_ttls_init(struct eap_sm *sm)
{
struct eap_ttls_data *data;
u8 *mschapv2;
u8 *eapdata;
size_t eap_len;
+ u8 *chbind_data;
+ size_t chbind_len;
int mschapv2_error;
};
}
+static int eap_ttls_parse_attr_chbind(const u8 *dpos, size_t dlen,
+ struct ttls_parse_avp *parse)
+{
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - Channel Binding Message");
+
+ if (parse->chbind_data == NULL) {
+ parse->chbind_data = os_malloc(dlen);
+ if (parse->chbind_data == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
+ "memory for Phase 2 channel binding data");
+ return -1;
+ }
+ os_memcpy(parse->chbind_data, dpos, dlen);
+ parse->chbind_len = dlen;
+ } else {
+ /* TODO: can this really happen? maybe just make this an error? */
+ u8 *newchbind = os_realloc(parse->chbind_data,
+ parse->chbind_len + dlen);
+ if (newchbind == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
+ "memory for Phase 2 channel binding data");
+ return -1;
+ }
+ os_memcpy(newchbind + parse->chbind_len, dpos, dlen);
+ parse->chbind_data = newchbind;
+ parse->chbind_len += dlen;
+ }
+
+ return 0;
+}
+
+
static int eap_ttls_parse_avp(u8 *pos, size_t left,
struct ttls_parse_avp *parse)
{
if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) {
if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0)
return -1;
+ } else if (vendor_id == 0 &&
+ avp_code == DIAMETER_ATTR_CHBIND_MESSAGE) {
+ /* message containing channel binding data */
+ if (eap_ttls_parse_attr_chbind(dpos, dlen, parse) < 0)
+ return -1;
} else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) {
/* This is an optional message that can be displayed to
* the user. */
return 0;
}
+static int eap_ttls_add_chbind_request(struct eap_sm *sm,
+ struct eap_ttls_data *data,
+ struct wpabuf **resp)
+{
+ struct wpabuf *chbind_req, *res;
+ int length = 1, i;
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (!config->chbind_config || config->chbind_config_len <= 0)
+ return -1;
+
+ for (i=0; i<config->chbind_config_len; i++) {
+ length += 3 + config->chbind_config[i].req_data_len;
+ }
+
+ chbind_req = wpabuf_alloc(length);
+ if (!chbind_req)
+ return -1;
+
+ wpabuf_put_u8(chbind_req, CHBIND_CODE_REQUEST);
+ for (i=0; i<config->chbind_config_len; i++) {
+ struct eap_peer_chbind_config *chbind_config =
+ &config->chbind_config[i];
+ wpabuf_put_be16(chbind_req, chbind_config->req_data_len);
+ wpabuf_put_u8(chbind_req, chbind_config->nsid);
+ wpabuf_put_data(chbind_req, chbind_config->req_data,
+ chbind_config->req_data_len);
+ }
+ if (eap_ttls_avp_encapsulate(&chbind_req,
+ DIAMETER_ATTR_CHBIND_MESSAGE, 0) < 0)
+ return -1;
+
+ /* bleh. This will free *resp regardless of whether combined buffer
+ alloc succeeds, which is not consistent with the other error
+ condition behavior in this function */
+ *resp = wpabuf_concat(chbind_req, *resp);
+
+ return (*resp) ? 0 : -1;
+}
+
+
+static int eap_ttls_process_chbind(struct eap_sm *sm,
+ struct eap_ttls_data *data,
+ struct eap_method_ret *ret,
+ struct ttls_parse_avp *parse,
+ struct wpabuf **resp)
+{
+ size_t pos=0;
+ u8 code;
+ u16 len;
+ struct chbind_hdr *hdr;
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (parse->chbind_data == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-TTLS: No channel binding message "
+ "in the packet - dropped");
+ return -1;
+ }
+ if (parse->chbind_len < 1 + sizeof(*hdr)) {
+ wpa_printf(MSG_WARNING, "EAP-TTLS: bad channel binding response "
+ "frame (len=%lu, expected %lu or more) - dropped",
+ (unsigned long) parse->chbind_len,
+ (unsigned long) sizeof(*hdr));
+ return -1;
+ }
+ code = parse->chbind_data[pos++];
+ while (pos+sizeof(*hdr) < parse->chbind_len) {
+ hdr = (struct chbind_hdr *)(&parse->chbind_data[pos]);
+ pos += sizeof(*hdr);
+ len = be_to_host16(hdr->len);
+ if (pos + len <= parse->chbind_len) {
+ int i;
+ for (i=0; i<config->chbind_config_len; i++) {
+ struct eap_peer_chbind_config *chbind_config =
+ &config->chbind_config[i];
+ if (chbind_config->nsid == hdr->nsid)
+ chbind_config->response_cb(
+ chbind_config->ctx,
+ code, hdr->nsid,
+ &parse->chbind_data[pos], len);
+ }
+ }
+ pos += len;
+ }
+ if (pos != parse->chbind_len) {
+ wpa_printf(MSG_WARNING, "EAP-TTLS: bad channel binding response "
+ "frame (parsed len=%lu, expected %lu) - dropped",
+ (unsigned long) pos,
+ (unsigned long) parse->chbind_len);
+ return -1;
+ }
+ return 0;
+}
static int eap_ttls_process_phase2_eap(struct eap_sm *sm,
struct eap_ttls_data *data,
#endif /* EAP_TNC */
}
+ if (!resp && (config->pending_req_identity ||
+ config->pending_req_password ||
+ config->pending_req_otp ||
+ config->pending_req_new_password)) {
+ wpabuf_free(data->pending_phase2_req);
+ data->pending_phase2_req = wpabuf_dup(in_decrypted);
+ return 0;
+ }
+
+ /* handle channel binding response here */
+ if (parse->chbind_data) {
+ /* received channel binding repsonse */
+ if (eap_ttls_process_chbind(sm, data, ret, parse, &resp) < 0)
+ return -1;
+ }
+ /* issue channel binding request when appropriate */
+ if (config->chbind_config && config->chbind_config_len > 0 &&
+ !data->chbind_req_sent) {
+ if (eap_ttls_add_chbind_request(sm, data, &resp) < 0)
+ return -1;
+ data->chbind_req_sent = 1;
+ }
+
if (resp) {
if (eap_ttls_encrypt_response(sm, data, resp, identifier,
out_data) < 0)
return -1;
- } else if (config->pending_req_identity ||
- config->pending_req_password ||
- config->pending_req_otp ||
- config->pending_req_new_password) {
- wpabuf_free(data->pending_phase2_req);
- data->pending_phase2_req = wpabuf_dup(in_decrypted);
}
return 0;
--- /dev/null
+/*
+ * RADIUS tlv construction and parsing utilites
+ * Copyright (c) 2012, Painless Security, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+
+#include "radius/radius.h"
+#include "radius_utils.h"
+#include "wpabuf.h"
+
+struct radius_vendor_attr_struct
+{
+ struct wpabuf *buf;
+ u8 *len_pos;
+ size_t start;
+};
+
+radius_vendor_attr radius_vendor_attr_start(struct wpabuf *buf, u32 vendor)
+{
+ radius_vendor_attr attr = (radius_vendor_attr )os_zalloc(sizeof(*attr));
+ if (!attr)
+ return attr;
+ attr->buf = buf;
+ attr->start = wpabuf_len(buf);
+ wpabuf_put_u8(buf, 26);
+ attr->len_pos = (u8*)wpabuf_put(buf, 1);
+ /* @TODO: Verify high 8 bits of vendor are 0? */
+ wpabuf_put_be32(buf, vendor);
+ return attr;
+}
+
+radius_vendor_attr radius_vendor_attr_add_subtype(radius_vendor_attr attr,
+ u8 type,
+ u8 *data,
+ size_t len)
+{
+ if (attr == VENDOR_ATTR_INVALID)
+ return attr;
+ if (len + 2 + (wpabuf_len(attr->buf) - attr->start) > 255) {
+ os_free(attr);
+ return VENDOR_ATTR_INVALID;
+ }
+ wpabuf_put_u8(attr->buf, type);
+ wpabuf_put_u8(attr->buf, len + 2);
+ wpabuf_put_data(attr->buf, data, len);
+ return attr;
+}
+
+radius_vendor_attr radius_vendor_attr_finish(radius_vendor_attr attr)
+{
+ /* poke size into correct place and free attr */
+ size_t len;
+ radius_vendor_attr ret = VENDOR_ATTR_INVALID;
+ if (attr == ret)
+ return ret;
+
+ len = wpabuf_len(attr->buf) - attr->start;
+ if (len < 255) {
+ ret = attr;
+ *(attr->len_pos) = (u8 )len;
+ }
+ os_free(attr);
+ return ret;
+}
+
+struct radius_parser_struct
+{
+ u8 *data;
+ size_t len;
+ size_t pos;
+};
+
+radius_parser radius_parser_start(void *tlvdata, size_t len)
+{
+ radius_parser parser = malloc(sizeof(struct radius_parser_struct));
+ if (parser) {
+ parser->data = (u8 *)tlvdata;
+ parser->len = len;
+ parser->pos = 0;
+ }
+ return parser;
+}
+
+void radius_parser_finish(radius_parser parser)
+{
+ free(parser);
+}
+
+int radius_parser_parse_tlv(radius_parser parser, u8 *type, u32 *vendor_id,
+ void **value, size_t *len)
+{
+ u8 rawtype, rawlen;
+ if (!parser)
+ return -1;
+ if (parser->len < parser->pos + 3)
+ return -1;
+ rawtype = parser->data[parser->pos];
+ rawlen = parser->data[parser->pos+1];
+ if (parser->len < parser->pos + rawlen)
+ return -1;
+
+ if (rawtype == RADIUS_ATTR_VENDOR_SPECIFIC) {
+ if (rawlen < 7)
+ return -1;
+ *vendor_id = WPA_GET_BE24(&parser->data[parser->pos + 3]);
+ *value = &parser->data[parser->pos + 6];
+ *len = rawlen - 6;
+ }
+ else {
+ if (rawlen < 3)
+ return -1;
+
+ *value = &parser->data[parser->pos + 2];
+ *len = rawlen - 2;
+ }
+ *type = rawtype;
+
+ parser->pos += rawlen;
+ return 0;
+}
+
+int radius_parser_parse_vendor_specific(radius_parser parser, u8 *vendor_type,
+ void **value, size_t *len)
+{
+ u8 rawtype, rawlen;
+ if (!parser)
+ return -1;
+ if (parser->len < parser->pos + 3)
+ return -1;
+ rawtype = parser->data[parser->pos];
+ rawlen = parser->data[parser->pos+1];
+ if (parser->len < parser->pos + rawlen)
+ return -1;
+
+ if (rawlen < 3)
+ return -1;
+
+ *value = &parser->data[parser->pos + 2];
+ *len = rawlen - 2;
+ *vendor_type = rawtype;
+
+ parser->pos += rawlen;
+ return 0;
+}
--- /dev/null
+/*
+ * RADIUS tlv construction utilites
+ * Copyright (c) 2012, Painless Security, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef RADIUS_UTILS_H
+#define RADIUS_UTILS_H
+
+struct wpabuf;
+
+struct radius_vendor_attr_struct;
+typedef struct radius_vendor_attr_struct *radius_vendor_attr;
+#define VENDOR_ATTR_INVALID NULL
+radius_vendor_attr radius_vendor_attr_start(struct wpabuf *buf, u32 vendor);
+radius_vendor_attr radius_vendor_attr_add_subtype(radius_vendor_attr attr,
+ u8 type,
+ u8 *data, size_t len);
+radius_vendor_attr radius_vendor_attr_finish(radius_vendor_attr attr);
+
+struct radius_parser_struct;
+typedef struct radius_parser_struct *radius_parser;
+radius_parser radius_parser_start(void *tlvdata, size_t len);
+int radius_parser_parse_tlv(radius_parser parser, u8 *type, u32 *vendor_id,
+ void **value, size_t *len);
+int radius_parser_parse_vendor_specific(radius_parser parser, u8 *vendor_type,
+ void **value, size_t *len);
+void radius_parser_finish(radius_parser parser);
+
+
+#endif /* RADIUS_UTILS_H */
\ No newline at end of file