/** * wpa_parse_vendor_specific - Parse Vendor Specific IEs * @pos: Pointer to the IE header * @end: Pointer to the end of the Key Data buffer * @ie: Pointer to parsed IE data * Returns: 0 on success, 1 if end mark is found, -1 on failure */ static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end, struct wpa_eapol_ie_parse *ie) { unsigned int oui; if (pos[1] < 4) { wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)", pos[1]); return 1; } oui = WPA_GET_BE24(&pos[2]); if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) { if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) { ie->wmm = &pos[2]; ie->wmm_len = pos[1]; wpa_hexdump(MSG_DEBUG, "WPA: WMM IE", ie->wmm, ie->wmm_len); } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) { ie->wmm = &pos[2]; ie->wmm_len = pos[1]; wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element", ie->wmm, ie->wmm_len); } } return 0; }
static Boolean eap_vendor_test_check(struct eap_sm *sm, void *priv, u8 *respData, size_t respDataLen) { struct eap_hdr *resp; u8 *pos; size_t len; int vendor; u32 method; resp = (struct eap_hdr *) respData; pos = (u8 *) (resp + 1); if (respDataLen < sizeof(*resp)) return TRUE; len = ntohs(resp->length); if (len > respDataLen) return TRUE; if (len < sizeof(*resp) + 8 || *pos != EAP_TYPE_EXPANDED) { wpa_printf(MSG_INFO, "EAP-VENDOR-TEST: Invalid frame"); return TRUE; } pos++; vendor = WPA_GET_BE24(pos); pos += 3; method = WPA_GET_BE32(pos); pos++; if (vendor != EAP_VENDOR_ID || method != EAP_VENDOR_TYPE) return TRUE; return FALSE; }
static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len; u8 type; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerHelloDone " "(left=%lu)", (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } type = *pos++; len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerHelloDone " "length (len=%lu != left=%lu)", (unsigned long) len, (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (type != TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected ServerHelloDone)", type); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone"); *in_len = end - in_data; conn->state = CLIENT_KEY_EXCHANGE; return 0; }
static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp) { const struct eap_hdr *hdr; size_t plen; /* parse rxResp, respId, respMethod */ sm->rxResp = FALSE; sm->respId = -1; sm->respMethod = EAP_TYPE_NONE; sm->respVendor = EAP_VENDOR_IETF; sm->respVendorMethod = EAP_TYPE_NONE; if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) { wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p " "len=%lu", resp, resp ? (unsigned long) wpabuf_len(resp) : 0); return; } hdr = wpabuf_head(resp); plen = be_to_host16(hdr->length); if (plen > wpabuf_len(resp)) { wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet " "(len=%lu plen=%lu)", (unsigned long) wpabuf_len(resp), (unsigned long) plen); return; } sm->respId = hdr->identifier; if (hdr->code == EAP_CODE_RESPONSE) sm->rxResp = TRUE; if (plen > sizeof(*hdr)) { u8 *pos = (u8 *) (hdr + 1); sm->respMethod = *pos++; if (sm->respMethod == EAP_TYPE_EXPANDED) { if (plen < sizeof(*hdr) + 8) { wpa_printf(MSG_DEBUG, "EAP: Ignored truncated " "expanded EAP-Packet (plen=%lu)", (unsigned long) plen); return; } sm->respVendor = WPA_GET_BE24(pos); pos += 3; sm->respVendorMethod = WPA_GET_BE32(pos); } } wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d " "respMethod=%u respVendor=%u respVendorMethod=%u", sm->rxResp, sm->respId, sm->respMethod, sm->respVendor, sm->respVendorMethod); }
const u8 * eap_hdr_validate(int vendor, EapType eap_type, const struct wpabuf *msg, size_t *plen) { const struct eap_hdr *hdr; const u8 *pos; size_t len; hdr = wpabuf_head(msg); if (wpabuf_len(msg) < sizeof(*hdr)) { wpa_printf(MSG_INFO, "EAP: Too short EAP frame"); return NULL; } len = be_to_host16(hdr->length); if (len < sizeof(*hdr) + 1 || len > wpabuf_len(msg)) { wpa_printf(MSG_INFO, "EAP: Invalid EAP length"); return NULL; } pos = (const u8 *) (hdr + 1); if (*pos == EAP_TYPE_EXPANDED) { int exp_vendor; u32 exp_type; if (len < sizeof(*hdr) + 8) { wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP " "length"); return NULL; } pos++; exp_vendor = WPA_GET_BE24(pos); pos += 3; exp_type = WPA_GET_BE32(pos); pos += 4; if (exp_vendor != vendor || exp_type != (u32) eap_type) { wpa_printf(MSG_INFO, "EAP: Invalid expanded frame " "type"); return NULL; } *plen = len - sizeof(*hdr) - 8; return pos; } else { if (vendor != EAP_VENDOR_IETF || *pos != eap_type) { wpa_printf(MSG_INFO, "EAP: Invalid frame type"); return NULL; } *plen = len - sizeof(*hdr) - 1; return pos + 1; } }
static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len) { struct eap_hdr *hdr; size_t plen; /* parse rxResp, respId, respMethod */ sm->rxResp = FALSE; sm->respId = -1; sm->respMethod = EAP_TYPE_NONE; sm->respVendor = EAP_VENDOR_IETF; sm->respVendorMethod = EAP_TYPE_NONE; if (resp == NULL || len < sizeof(*hdr)) return; hdr = (struct eap_hdr *) resp; plen = ntohs(hdr->length); if (plen > len) { wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet " "(len=%lu plen=%lu)", (unsigned long) len, (unsigned long) plen); return; } sm->respId = hdr->identifier; if (hdr->code == EAP_CODE_RESPONSE) sm->rxResp = TRUE; if (plen > sizeof(*hdr)) { u8 *pos = (u8 *) (hdr + 1); sm->respMethod = *pos++; if (sm->respMethod == EAP_TYPE_EXPANDED) { if (plen < sizeof(*hdr) + 8) { wpa_printf(MSG_DEBUG, "EAP: Ignored truncated " "expanded EAP-Packet (plen=%lu)", (unsigned long) plen); return; } sm->respVendor = WPA_GET_BE24(pos); pos += 3; sm->respVendorMethod = WPA_GET_BE32(pos); } } wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d " "respMethod=%u respVendor=%u respVendorMethod=%u", sm->rxResp, sm->respId, sm->respMethod, sm->respVendor, sm->respVendorMethod); }
static void rx_anqp_vendor_specific(struct hostapd_data *hapd, const u8 *pos, const u8 *end, struct anqp_query_info *qi) { u32 oui; u8 subtype; if (pos + 4 > end) { wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP " "Query element"); return; } oui = WPA_GET_BE24(pos); pos += 3; if (oui != OUI_WFA) { wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x", oui); return; } if (*pos != HS20_ANQP_OUI_TYPE) { wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u", *pos); return; } pos++; if (pos + 1 >= end) return; subtype = *pos++; pos++; /* Reserved */ switch (subtype) { case HS20_STYPE_QUERY_LIST: wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List"); while (pos < end) { rx_anqp_hs_query_list(hapd, *pos, qi); pos++; } break; case HS20_STYPE_NAI_HOME_REALM_QUERY: rx_anqp_hs_nai_home_realm(hapd, pos, end, qi); break; default: wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype " "%u", subtype); break; } }
static int wps_parse_vendor_ext(struct wps_parse_attr *attr, const u8 *pos, u16 len) { u32 vendor_id; if (len < 3) { wpa_printf(MSG_DEBUG, "WPS: Skip invalid Vendor Extension"); return 0; } vendor_id = WPA_GET_BE24(pos); switch (vendor_id) { case WPS_VENDOR_ID_WFA: return wps_parse_vendor_ext_wfa(attr, pos + 3, len - 3); } /* Handle unknown vendor extensions */ wpa_printf(MSG_MSGDUMP, "WPS: Unknown Vendor Extension (Vendor ID %u)", vendor_id); if (len > WPS_MAX_VENDOR_EXT_LEN) { wpa_printf(MSG_DEBUG, "WPS: Too long Vendor Extension (%u)", len); return -1; } if (attr->num_vendor_ext >= MAX_WPS_PARSE_VENDOR_EXT) { wpa_printf(MSG_DEBUG, "WPS: Skipped Vendor Extension " "attribute (max %d vendor extensions)", MAX_WPS_PARSE_VENDOR_EXT); return -1; } attr->vendor_ext[attr->num_vendor_ext] = pos; attr->vendor_ext_len[attr->num_vendor_ext] = len; attr->num_vendor_ext++; return 0; }
void mbo_ap_wnm_notification_req(struct hostapd_data *hapd, const u8 *addr, const u8 *buf, size_t len) { const u8 *pos, *end; u8 ie_len; struct sta_info *sta; int first_non_pref_chan = 1; if (!hapd->conf->mbo_enabled) return; sta = ap_get_sta(hapd, addr); if (!sta) return; pos = buf; end = buf + len; while (end - pos > 1) { ie_len = pos[1]; if (2 + ie_len > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 4 && WPA_GET_BE24(pos + 2) == OUI_WFA) mbo_ap_wnm_notif_req_elem(sta, pos[5], pos + 6, ie_len - 4, &first_non_pref_chan); else wpa_printf(MSG_DEBUG, "MBO: Ignore unknown WNM Notification element %u (len=%u)", pos[0], pos[1]); pos += 2 + pos[1]; } }
static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end, *c; size_t left, len, i, j; u16 cipher_suite; u16 num_suites; int compr_null_found; u16 ext_type, ext_len; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) goto decode_error; /* HandshakeType msg_type */ if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected ClientHello)", *pos); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello"); pos++; /* uint24 length */ len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) goto decode_error; /* body - ClientHello */ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len); end = pos + len; /* ProtocolVersion client_version */ if (end - pos < 2) goto decode_error; conn->client_version = WPA_GET_BE16(pos); wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d", conn->client_version >> 8, conn->client_version & 0xff); if (conn->client_version < TLS_VERSION) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in " "ClientHello"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_PROTOCOL_VERSION); return -1; } pos += 2; /* Random random */ if (end - pos < TLS_RANDOM_LEN) goto decode_error; os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN); pos += TLS_RANDOM_LEN; wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random", conn->client_random, TLS_RANDOM_LEN); /* SessionID session_id */ if (end - pos < 1) goto decode_error; if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN) goto decode_error; wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos); pos += 1 + *pos; /* TODO: add support for session resumption */ /* CipherSuite cipher_suites<2..2^16-1> */ if (end - pos < 2) goto decode_error; num_suites = WPA_GET_BE16(pos); pos += 2; if (end - pos < num_suites) goto decode_error; wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites", pos, num_suites); if (num_suites & 1) goto decode_error; num_suites /= 2; cipher_suite = 0; for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) { c = pos; for (j = 0; j < num_suites; j++) { u16 tmp = WPA_GET_BE16(c); c += 2; if (!cipher_suite && tmp == conn->cipher_suites[i]) { cipher_suite = tmp; break; } } } pos += num_suites * 2; if (!cipher_suite) { wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite " "available"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_ILLEGAL_PARAMETER); return -1; } if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for " "record layer"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->cipher_suite = cipher_suite; /* CompressionMethod compression_methods<1..2^8-1> */ if (end - pos < 1) goto decode_error; num_suites = *pos++; if (end - pos < num_suites) goto decode_error; wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods", pos, num_suites); compr_null_found = 0; for (i = 0; i < num_suites; i++) { if (*pos++ == TLS_COMPRESSION_NULL) compr_null_found = 1; } if (!compr_null_found) { wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL " "compression"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_ILLEGAL_PARAMETER); return -1; } if (end - pos == 1) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the " "end of ClientHello: 0x%02x", *pos); goto decode_error; } if (end - pos >= 2) { /* Extension client_hello_extension_list<0..2^16-1> */ ext_len = WPA_GET_BE16(pos); pos += 2; wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello " "extensions", ext_len); if (end - pos != ext_len) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello " "extension list length %u (expected %u)", ext_len, (unsigned int) (end - pos)); goto decode_error; } /* * struct { * ExtensionType extension_type (0..65535) * opaque extension_data<0..2^16-1> * } Extension; */ while (pos < end) { if (end - pos < 2) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid " "extension_type field"); goto decode_error; } ext_type = WPA_GET_BE16(pos); pos += 2; if (end - pos < 2) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid " "extension_data length field"); goto decode_error; } ext_len = WPA_GET_BE16(pos); pos += 2; if (end - pos < ext_len) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid " "extension_data field"); goto decode_error; } wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension " "type %u", ext_type); wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello " "Extension data", pos, ext_len); if (ext_type == TLS_EXT_SESSION_TICKET) { os_free(conn->session_ticket); conn->session_ticket = os_malloc(ext_len); if (conn->session_ticket) { os_memcpy(conn->session_ticket, pos, ext_len); conn->session_ticket_len = ext_len; } } pos += ext_len; } } *in_len = end - in_data; wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to " "ServerHello"); conn->state = SERVER_HELLO; return 0; decode_error: wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; }
static int tls_process_certificate(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len, list_len, cert_len, idx; u8 type; struct x509_certificate *chain = NULL, *last = NULL, *cert; int reason; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message " "(len=%lu)", (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } type = *pos++; len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message " "length (len=%lu != left=%lu)", (unsigned long) len, (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) { if (conn->verify_peer) { wpa_printf(MSG_DEBUG, "TLSv1: Client did not include " "Certificate"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } return tls_process_client_key_exchange(conn, ct, in_data, in_len); } if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected Certificate/" "ClientKeyExchange)", type); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received Certificate (certificate_list len %lu)", (unsigned long) len); /* * opaque ASN.1Cert<2^24-1>; * * struct { * ASN.1Cert certificate_list<1..2^24-1>; * } Certificate; */ end = pos + len; if (end - pos < 3) { wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate " "(left=%lu)", (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } list_len = WPA_GET_BE24(pos); pos += 3; if ((size_t) (end - pos) != list_len) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list " "length (len=%lu left=%lu)", (unsigned long) list_len, (unsigned long) (end - pos)); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } idx = 0; while (pos < end) { if (end - pos < 3) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " "certificate_list"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); x509_certificate_chain_free(chain); return -1; } cert_len = WPA_GET_BE24(pos); pos += 3; if ((size_t) (end - pos) < cert_len) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate " "length (len=%lu left=%lu)", (unsigned long) cert_len, (unsigned long) (end - pos)); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); x509_certificate_chain_free(chain); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)", (unsigned long) idx, (unsigned long) cert_len); if (idx == 0) { crypto_public_key_free(conn->client_rsa_key); if (tls_parse_cert(pos, cert_len, &conn->client_rsa_key)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " "the certificate"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_BAD_CERTIFICATE); x509_certificate_chain_free(chain); return -1; } } cert = x509_certificate_parse(pos, cert_len); if (cert == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " "the certificate"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_BAD_CERTIFICATE); x509_certificate_chain_free(chain); return -1; } if (last == NULL) chain = cert; else last->next = cert; last = cert; idx++; pos += cert_len; } if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain, &reason) < 0) { int tls_reason; wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain " "validation failed (reason=%d)", reason); switch (reason) { case X509_VALIDATE_BAD_CERTIFICATE: tls_reason = TLS_ALERT_BAD_CERTIFICATE; break; case X509_VALIDATE_UNSUPPORTED_CERTIFICATE: tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE; break; case X509_VALIDATE_CERTIFICATE_REVOKED: tls_reason = TLS_ALERT_CERTIFICATE_REVOKED; break; case X509_VALIDATE_CERTIFICATE_EXPIRED: tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED; break; case X509_VALIDATE_CERTIFICATE_UNKNOWN: tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN; break; case X509_VALIDATE_UNKNOWN_CA: tls_reason = TLS_ALERT_UNKNOWN_CA; break; default: tls_reason = TLS_ALERT_BAD_CERTIFICATE; break; } tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason); x509_certificate_chain_free(chain); return -1; } x509_certificate_chain_free(chain); *in_len = end - in_data; conn->state = CLIENT_KEY_EXCHANGE; return 0; }
void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq) { const u8 *pos = data; const u8 *end = data + len; const u8 *next; u8 dialog_token; u16 status_code; u8 frag_id; u8 more_frags; u16 comeback_delay; u16 slen; wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len); if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL || os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore unexpected GAS Comeback Response from " MACSTR, MAC2STR(sa)); return; } p2p->cfg->send_action_done(p2p->cfg->cb_ctx); p2p_clear_timeout(p2p); wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Received GAS Comeback Response from " MACSTR " (len=%d)", MAC2STR(sa), (int) len); if (len < 6 + 2) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too short GAS Comeback Response frame"); return; } dialog_token = *pos++; /* TODO: check dialog_token match */ status_code = WPA_GET_LE16(pos); pos += 2; frag_id = *pos & 0x7f; more_frags = (*pos & 0x80) >> 7; pos++; comeback_delay = WPA_GET_LE16(pos); pos += 2; wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: dialog_token=%u status_code=%u frag_id=%d more_frags=%d " "comeback_delay=%u", dialog_token, status_code, frag_id, more_frags, comeback_delay); /* TODO: check frag_id match */ if (status_code) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Service Discovery failed: status code %u", status_code); return; } if (*pos != WLAN_EID_ADV_PROTO) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unexpected IE in GAS Comeback Response: %u", *pos); return; } pos++; slen = *pos++; next = pos + slen; if (next > end || slen < 2) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Invalid IE in GAS Comeback Response"); return; } pos++; /* skip QueryRespLenLimit and PAME-BI */ if (*pos != NATIVE_QUERY_PROTOCOL) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported GAS advertisement protocol id %u", *pos); return; } pos = next; /* Query Response */ if (pos + 2 > end) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too short Query " "Response"); return; } slen = WPA_GET_LE16(pos); pos += 2; wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Query Response Length: %d", slen); if (pos + slen > end) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Not enough Query " "Response data"); return; } if (slen == 0) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No Query Response " "data"); return; } end = pos + slen; if (p2p->sd_rx_resp) { /* * NQP header is only included in the first fragment; rest of * the fragments start with continue TLVs. */ goto skip_nqp_header; } /* NQP Query Response */ if (pos + 4 > end) return; if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos)); return; } pos += 2; slen = WPA_GET_LE16(pos); pos += 2; wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: NQP Query Response " "length: %u", slen); if (slen < 3 + 1) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Invalid NQP Query Response length"); return; } if (pos + 4 > end) return; if (WPA_GET_BE24(pos) != OUI_WFA) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos)); return; } pos += 3; if (*pos != P2P_OUI_TYPE) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported NQP vendor type %u", *pos); return; } pos++; if (pos + 2 > end) return; p2p->sd_rx_update_indic = WPA_GET_LE16(pos); wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Service Update Indicator: %u", p2p->sd_rx_update_indic); pos += 2; skip_nqp_header: if (wpabuf_resize(&p2p->sd_rx_resp, end - pos) < 0) return; wpabuf_put_data(p2p->sd_rx_resp, pos, end - pos); wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Current SD reassembly " "buffer length: %u", (unsigned int) wpabuf_len(p2p->sd_rx_resp)); if (more_frags) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: More fragments " "remains"); /* TODO: what would be a good size limit? */ if (wpabuf_len(p2p->sd_rx_resp) > 64000) { wpabuf_free(p2p->sd_rx_resp); p2p->sd_rx_resp = NULL; wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too long " "SD response - drop it"); return; } p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq); return; } p2p->sd_peer->flags |= P2P_DEV_SD_INFO; p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE; p2p->sd_peer = NULL; if (p2p->sd_query) { if (!p2p->sd_query->for_all_peers) { struct p2p_sd_query *q; wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Remove completed SD query %p", p2p->sd_query); q = p2p->sd_query; p2p_unlink_sd_query(p2p, p2p->sd_query); p2p_free_sd_query(q); } p2p->sd_query = NULL; } if (p2p->cfg->sd_response) p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, p2p->sd_rx_update_indic, wpabuf_head(p2p->sd_rx_resp), wpabuf_len(p2p->sd_rx_resp)); wpabuf_free(p2p->sd_rx_resp); p2p->sd_rx_resp = NULL; p2p_continue_find(p2p); }
void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq) { const u8 *pos = data; const u8 *end = data + len; const u8 *next; u8 dialog_token; u16 status_code; u16 comeback_delay; u16 slen; u16 update_indic; if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL || os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore unexpected GAS Initial Response from " MACSTR, MAC2STR(sa)); return; } p2p->cfg->send_action_done(p2p->cfg->cb_ctx); p2p_clear_timeout(p2p); wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Received GAS Initial Response from " MACSTR " (len=%d)", MAC2STR(sa), (int) len); if (len < 5 + 2) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too short GAS Initial Response frame"); return; } dialog_token = *pos++; /* TODO: check dialog_token match */ status_code = WPA_GET_LE16(pos); pos += 2; comeback_delay = WPA_GET_LE16(pos); pos += 2; wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: dialog_token=%u status_code=%u comeback_delay=%u", dialog_token, status_code, comeback_delay); if (status_code) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Service Discovery failed: status code %u", status_code); return; } if (*pos != WLAN_EID_ADV_PROTO) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unexpected IE in GAS Initial Response: %u", *pos); return; } pos++; slen = *pos++; next = pos + slen; if (next > end || slen < 2) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Invalid IE in GAS Initial Response"); return; } pos++; /* skip QueryRespLenLimit and PAME-BI */ if (*pos != NATIVE_QUERY_PROTOCOL) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported GAS advertisement protocol id %u", *pos); return; } pos = next; /* Query Response */ if (pos + 2 > end) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too short Query " "Response"); return; } slen = WPA_GET_LE16(pos); pos += 2; wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Query Response Length: %d", slen); if (pos + slen > end) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Not enough Query " "Response data"); return; } end = pos + slen; if (comeback_delay) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Fragmented " "response - request fragments"); if (p2p->sd_rx_resp) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Drop " "old SD reassembly buffer"); wpabuf_free(p2p->sd_rx_resp); p2p->sd_rx_resp = NULL; } p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq); return; } /* NQP Query Response */ if (pos + 4 > end) return; if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos)); return; } pos += 2; slen = WPA_GET_LE16(pos); pos += 2; if (pos + slen > end || slen < 3 + 1) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Invalid NQP Query Response length"); return; } if (WPA_GET_BE24(pos) != OUI_WFA) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos)); return; } pos += 3; if (*pos != P2P_OUI_TYPE) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported NQP vendor type %u", *pos); return; } pos++; if (pos + 2 > end) return; update_indic = WPA_GET_LE16(pos); wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Service Update Indicator: %u", update_indic); pos += 2; p2p->sd_peer->flags |= P2P_DEV_SD_INFO; p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE; p2p->sd_peer = NULL; if (p2p->sd_query) { if (!p2p->sd_query->for_all_peers) { struct p2p_sd_query *q; wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Remove completed SD query %p", p2p->sd_query); q = p2p->sd_query; p2p_unlink_sd_query(p2p, p2p->sd_query); p2p_free_sd_query(q); } p2p->sd_query = NULL; } if (p2p->cfg->sd_response) p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, update_indic, pos, end - pos); p2p_continue_find(p2p); }
void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq) { const u8 *pos = data; const u8 *end = data + len; const u8 *next; u8 dialog_token; u16 slen; int freq; u16 update_indic; if (p2p->cfg->sd_request == NULL) return; if (rx_freq > 0) freq = rx_freq; else freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class, p2p->cfg->channel); if (freq < 0) return; if (len < 1 + 2) return; dialog_token = *pos++; wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: GAS Initial Request from " MACSTR " (dialog token %u, " "freq %d)", MAC2STR(sa), dialog_token, rx_freq); if (*pos != WLAN_EID_ADV_PROTO) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unexpected IE in GAS Initial Request: %u", *pos); return; } pos++; slen = *pos++; next = pos + slen; if (next > end || slen < 2) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Invalid IE in GAS Initial Request"); return; } pos++; /* skip QueryRespLenLimit and PAME-BI */ if (*pos != NATIVE_QUERY_PROTOCOL) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported GAS advertisement protocol id %u", *pos); return; } pos = next; /* Query Request */ if (pos + 2 > end) return; slen = WPA_GET_LE16(pos); pos += 2; if (pos + slen > end) return; end = pos + slen; /* NQP Query Request */ if (pos + 4 > end) return; if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos)); return; } pos += 2; slen = WPA_GET_LE16(pos); pos += 2; if (pos + slen > end || slen < 3 + 1) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Invalid NQP Query Request length"); return; } if (WPA_GET_BE24(pos) != OUI_WFA) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos)); return; } pos += 3; if (*pos != P2P_OUI_TYPE) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported NQP vendor type %u", *pos); return; } pos++; if (pos + 2 > end) return; update_indic = WPA_GET_LE16(pos); wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Service Update Indicator: %u", update_indic); pos += 2; p2p->cfg->sd_request(p2p->cfg->cb_ctx, freq, sa, dialog_token, update_indic, pos, end - pos); /* the response will be indicated with a call to p2p_sd_response() */ }
static void rx_anqp_vendor_specific(struct hostapd_data *hapd, const u8 *pos, const u8 *end, struct anqp_query_info *qi) { u32 oui; u8 subtype; if (end - pos < 4) { wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP " "Query element"); return; } oui = WPA_GET_BE24(pos); pos += 3; if (oui != OUI_WFA) { wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x", oui); return; } #ifdef CONFIG_P2P if (*pos == P2P_OUI_TYPE) { /* * This is for P2P SD and will be taken care of by the P2P * implementation. This query needs to be ignored in the generic * GAS server to avoid duplicated response. */ wpa_printf(MSG_DEBUG, "ANQP: Ignore WFA vendor type %u (P2P SD) in generic GAS server", *pos); qi->p2p_sd = 1; return; } #endif /* CONFIG_P2P */ if (*pos != HS20_ANQP_OUI_TYPE) { wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u", *pos); return; } pos++; if (end - pos <= 1) return; subtype = *pos++; pos++; /* Reserved */ switch (subtype) { case HS20_STYPE_QUERY_LIST: wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List"); while (pos < end) { rx_anqp_hs_query_list(hapd, *pos, qi); pos++; } break; case HS20_STYPE_NAI_HOME_REALM_QUERY: rx_anqp_hs_nai_home_realm(hapd, pos, end, qi); break; case HS20_STYPE_ICON_REQUEST: rx_anqp_hs_icon_request(hapd, pos, end, qi); break; default: wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype " "%u", subtype); break; } }
static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *data, int len) { const u8 *pos, *end, *next; u8 ie, ie_len; pos = data; end = data + len; while (end - pos > 1) { ie = *pos++; ie_len = *pos++; wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u", ie, ie_len); if (ie_len > end - pos) { wpa_printf(MSG_DEBUG, "WNM: Not enough room for " "subelement"); break; } next = pos + ie_len; if (ie_len < 4) { pos = next; continue; } wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u", WPA_GET_BE24(pos), pos[3]); #ifdef CONFIG_HS20 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && WPA_GET_BE24(pos) == OUI_WFA && pos[3] == HS20_WNM_SUB_REM_NEEDED) { /* Subscription Remediation subelement */ const u8 *ie_end; u8 url_len; char *url; u8 osu_method; wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation " "subelement"); ie_end = pos + ie_len; pos += 4; url_len = *pos++; if (url_len == 0) { wpa_printf(MSG_DEBUG, "WNM: No Server URL included"); url = NULL; osu_method = 1; } else { if (url_len + 1 > ie_end - pos) { wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)", url_len, (int) (ie_end - pos)); break; } url = os_malloc(url_len + 1); if (url == NULL) break; os_memcpy(url, pos, url_len); url[url_len] = '\0'; osu_method = pos[url_len]; } hs20_rx_subscription_remediation(wpa_s, url, osu_method); os_free(url); pos = next; continue; } if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 && WPA_GET_BE24(pos) == OUI_WFA && pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) { const u8 *ie_end; u8 url_len; char *url; u8 code; u16 reauth_delay; ie_end = pos + ie_len; pos += 4; code = *pos++; reauth_delay = WPA_GET_LE16(pos); pos += 2; url_len = *pos++; wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication " "Imminent - Reason Code %u " "Re-Auth Delay %u URL Length %u", code, reauth_delay, url_len); if (url_len > ie_end - pos) break; url = os_malloc(url_len + 1); if (url == NULL) break; os_memcpy(url, pos, url_len); url[url_len] = '\0'; hs20_rx_deauth_imminent_notice(wpa_s, code, reauth_delay, url); os_free(url); pos = next; continue; } #endif /* CONFIG_HS20 */ pos = next; } }
static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len, hlen; u8 verify_data[TLS_VERIFY_DATA_LEN]; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; " "received content type 0x%x", ct); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for " "Finished", (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received " "type 0x%x", pos[0]); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } len = WPA_GET_BE24(pos + 1); pos += 4; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished " "(len=%lu > left=%lu)", (unsigned long) len, (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (len != TLS_VERIFY_DATA_LEN) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length " "in Finished: %lu (expected %d)", (unsigned long) len, TLS_VERIFY_DATA_LEN); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished", pos, TLS_VERIFY_DATA_LEN); hlen = MD5_MAC_LEN; if (conn->verify.md5_client == NULL || crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.md5_client = NULL; crypto_hash_finish(conn->verify.sha1_client, NULL, NULL); conn->verify.sha1_client = NULL; return -1; } conn->verify.md5_client = NULL; hlen = SHA1_MAC_LEN; if (conn->verify.sha1_client == NULL || crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN, &hlen) < 0) { conn->verify.sha1_client = NULL; tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha1_client = NULL; if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, verify_data, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECRYPT_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)", verify_data, TLS_VERIFY_DATA_LEN); if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data"); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received Finished"); *in_len = end - in_data; if (conn->use_session_ticket) { /* Abbreviated handshake using session ticket; RFC 4507 */ wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed " "successfully"); conn->state = ESTABLISHED; } else { /* Full handshake */ conn->state = SERVER_CHANGE_CIPHER_SPEC; } return 0; }
static u8 * eap_gpsk_process_gpsk_3(struct eap_sm *sm, struct eap_gpsk_data *data, struct eap_method_ret *ret, const u8 *reqData, size_t reqDataLen, const u8 *payload, size_t payload_len, size_t *respDataLen) { size_t len, miclen; struct eap_hdr *resp; u8 *rpos, *start; const struct eap_hdr *req; const u8 *pos, *end; u16 alen; int vendor, specifier; const struct eap_gpsk_csuite *csuite; u8 mic[EAP_GPSK_MAX_MIC_LEN]; if (data->state != GPSK_3) { ret->ignore = TRUE; return NULL; } wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3"); req = (const struct eap_hdr *) reqData; pos = payload; end = payload + payload_len; if (end - pos < EAP_GPSK_RAND_LEN) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " "RAND_Client"); return NULL; } if (os_memcmp(pos, data->rand_client, EAP_GPSK_RAND_LEN) != 0) { wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Client in GPSK-2 and " "GPSK-3 did not match"); wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Client in GPSK-2", data->rand_client, EAP_GPSK_RAND_LEN); wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Client in GPSK-3", pos, EAP_GPSK_RAND_LEN); eap_gpsk_state(data, FAILURE); return NULL; } pos += EAP_GPSK_RAND_LEN; if (end - pos < EAP_GPSK_RAND_LEN) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " "RAND_Server"); return NULL; } if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) { wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and " "GPSK-3 did not match"); wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1", data->rand_server, EAP_GPSK_RAND_LEN); wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3", pos, EAP_GPSK_RAND_LEN); eap_gpsk_state(data, FAILURE); return NULL; } pos += EAP_GPSK_RAND_LEN; if (end - pos < (int) sizeof(*csuite)) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " "CSuite_Sel"); return NULL; } csuite = (const struct eap_gpsk_csuite *) pos; vendor = WPA_GET_BE24(csuite->vendor); specifier = WPA_GET_BE24(csuite->specifier); pos += sizeof(*csuite); if (vendor != data->vendor || specifier != data->specifier) { wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not " "match with the one sent in GPSK-2 (%d:%d)", vendor, specifier, data->vendor, data->specifier); eap_gpsk_state(data, FAILURE); return NULL; } if (end - pos < 2) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " "PD_Payload_2 length"); eap_gpsk_state(data, FAILURE); return NULL; } alen = WPA_GET_BE16(pos); pos += 2; if (end - pos < alen) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " "%d-octet PD_Payload_2", alen); eap_gpsk_state(data, FAILURE); return NULL; } wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen); pos += alen; miclen = eap_gpsk_mic_len(data->vendor, data->specifier); if (end - pos < (int) miclen) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " "(left=%d miclen=%d)", end - pos, miclen); eap_gpsk_state(data, FAILURE); return NULL; } if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, data->specifier, payload, pos - payload, mic) < 0) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); eap_gpsk_state(data, FAILURE); return NULL; } if (os_memcmp(mic, pos, miclen) != 0) { wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3"); wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); eap_gpsk_state(data, FAILURE); return NULL; } pos += miclen; if (pos != end) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %d bytes of extra " "data in the end of GPSK-2", end - pos); } wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4"); len = 1 + 2 + miclen; resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respDataLen, len, EAP_CODE_RESPONSE, req->identifier, &rpos); if (resp == NULL) return NULL; *rpos++ = EAP_GPSK_OPCODE_GPSK_4; start = rpos; /* No PD_Payload_3 */ WPA_PUT_BE16(rpos, 0); rpos += 2; if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, data->specifier, start, rpos - start, rpos) < 0) { eap_gpsk_state(data, FAILURE); os_free(resp); return NULL; } eap_gpsk_state(data, SUCCESS); ret->methodState = METHOD_DONE; ret->decision = DECISION_UNCOND_SUCC; return (u8 *) resp; }
static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len; u8 type; const struct tls_cipher_suite *suite; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerKeyExchange " "(Left=%lu)", (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } type = *pos++; len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerKeyExchange " "length (len=%lu != left=%lu)", (unsigned long) len, (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) return tls_process_certificate_request(conn, ct, in_data, in_len); if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) return tls_process_server_hello_done(conn, ct, in_data, in_len); if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected ServerKeyExchange/" "CertificateRequest/ServerHelloDone)", type); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received ServerKeyExchange"); if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) { wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not allowed " "with the selected cipher suite"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len); suite = tls_get_cipher_suite(conn->rl.cipher_suite); if (suite && (suite->key_exchange == TLS_KEY_X_DH_anon || suite->key_exchange == TLS_KEY_X_DHE_RSA)) { if (tlsv1_process_diffie_hellman(conn, pos, len, suite->key_exchange) < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } } else { wpa_printf(MSG_DEBUG, "TLSv1: UnexpectedServerKeyExchange"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } *in_len = end - in_data; conn->state = SERVER_CERTIFICATE_REQUEST; return 0; }
static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len, i; u16 cipher_suite; u16 tls_version; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) goto decode_error; /* HandshakeType msg_type */ if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected ServerHello)", *pos); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello"); pos++; /* uint24 length */ len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) goto decode_error; /* body - ServerHello */ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len); end = pos + len; /* ProtocolVersion server_version */ if (end - pos < 2) goto decode_error; tls_version = WPA_GET_BE16(pos); if (!tls_version_ok(tls_version)) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in " "ServerHello %u.%u", pos[0], pos[1]); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_PROTOCOL_VERSION); return -1; } pos += 2; wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s", tls_version_str(tls_version)); conn->rl.tls_version = tls_version; /* Random random */ if (end - pos < TLS_RANDOM_LEN) goto decode_error; os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN); pos += TLS_RANDOM_LEN; wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random", conn->server_random, TLS_RANDOM_LEN); /* SessionID session_id */ if (end - pos < 1) goto decode_error; if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN) goto decode_error; if (conn->session_id_len && conn->session_id_len == *pos && os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) { pos += 1 + conn->session_id_len; wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session"); conn->session_resumed = 1; } else { conn->session_id_len = *pos; pos++; os_memcpy(conn->session_id, pos, conn->session_id_len); pos += conn->session_id_len; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id", conn->session_id, conn->session_id_len); /* CipherSuite cipher_suite */ if (end - pos < 2) goto decode_error; cipher_suite = WPA_GET_BE16(pos); pos += 2; for (i = 0; i < conn->num_cipher_suites; i++) { if (cipher_suite == conn->cipher_suites[i]) break; } if (i == conn->num_cipher_suites) { wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected " "cipher suite 0x%04x", cipher_suite); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_ILLEGAL_PARAMETER); return -1; } if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) { wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different " "cipher suite for a resumed connection (0x%04x != " "0x%04x)", cipher_suite, conn->prev_cipher_suite); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_ILLEGAL_PARAMETER); return -1; } if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for " "record layer"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->prev_cipher_suite = cipher_suite; /* CompressionMethod compression_method */ if (end - pos < 1) goto decode_error; if (*pos != TLS_COMPRESSION_NULL) { wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected " "compression 0x%02x", *pos); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_ILLEGAL_PARAMETER); return -1; } pos++; if (end != pos) { /* TODO: ServerHello extensions */ wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the " "end of ServerHello", pos, end - pos); goto decode_error; } if (conn->session_ticket_included && conn->session_ticket_cb) { /* TODO: include SessionTicket extension if one was included in * ServerHello */ int res = conn->session_ticket_cb( conn->session_ticket_cb_ctx, NULL, 0, conn->client_random, conn->server_random, conn->master_secret); if (res < 0) { wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback " "indicated failure"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_HANDSHAKE_FAILURE); return -1; } conn->use_session_ticket = !!res; } if ((conn->session_resumed || conn->use_session_ticket) && tls_derive_keys(conn, NULL, 0)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } *in_len = end - in_data; conn->state = (conn->session_resumed || conn->use_session_ticket) ? SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE; return 0; decode_error: wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; }
int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct, const u8 *buf, size_t *len, u8 **out_data, size_t *out_len) { if (ct == TLS_CONTENT_TYPE_ALERT) { if (*len < 2) { wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d", buf[0], buf[1]); *len = 2; conn->state = FAILED; return -1; } if (ct == TLS_CONTENT_TYPE_HANDSHAKE && *len >= 4 && buf[0] == TLS_HANDSHAKE_TYPE_HELLO_REQUEST) { size_t hr_len = WPA_GET_BE24(buf + 1); if (hr_len > *len - 4) { wpa_printf(MSG_DEBUG, "TLSv1: HelloRequest underflow"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Ignored HelloRequest"); *len = 4 + hr_len; return 0; } switch (conn->state) { case SERVER_HELLO: if (tls_process_server_hello(conn, ct, buf, len)) return -1; break; case SERVER_CERTIFICATE: if (tls_process_certificate(conn, ct, buf, len)) return -1; break; case SERVER_KEY_EXCHANGE: if (tls_process_server_key_exchange(conn, ct, buf, len)) return -1; break; case SERVER_CERTIFICATE_REQUEST: if (tls_process_certificate_request(conn, ct, buf, len)) return -1; break; case SERVER_HELLO_DONE: if (tls_process_server_hello_done(conn, ct, buf, len)) return -1; break; case SERVER_CHANGE_CIPHER_SPEC: if (tls_process_server_change_cipher_spec(conn, ct, buf, len)) return -1; break; case SERVER_FINISHED: if (tls_process_server_finished(conn, ct, buf, len)) return -1; break; case ACK_FINISHED: if (out_data && tls_process_application_data(conn, ct, buf, len, out_data, out_len)) return -1; break; default: wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d " "while processing received message", conn->state); return -1; } if (ct == TLS_CONTENT_TYPE_HANDSHAKE) tls_verify_hash_add(&conn->verify, buf, *len); return 0; }
/** * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information * The k tagged vlans found are sorted by vlan_id and stored in the first k * items of tagged. * * @msg: RADIUS message * @untagged: Pointer to store untagged vid * @numtagged: Size of tagged * @tagged: Pointer to store tagged list * * Returns: 0 if neither tagged nor untagged configuration is found, 1 otherwise */ int radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int numtagged, int *tagged) { struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun; size_t i; struct radius_attr_hdr *attr = NULL; const u8 *data; char buf[10]; size_t dlen; int j, taggedidx = 0, vlan_id; os_memset(&tunnel, 0, sizeof(tunnel)); for (j = 0; j < numtagged; j++) tagged[j] = 0; *untagged = 0; for (i = 0; i < msg->attr_used; i++) { attr = radius_get_attr_hdr(msg, i); if (attr->length < sizeof(*attr)) return -1; data = (const u8 *) (attr + 1); dlen = attr->length - sizeof(*attr); if (attr->length < 3) continue; if (data[0] >= RADIUS_TUNNEL_TAGS) tun = &tunnel[0]; else tun = &tunnel[data[0]]; switch (attr->type) { case RADIUS_ATTR_TUNNEL_TYPE: if (attr->length != 6) break; tun->tag_used++; tun->type = WPA_GET_BE24(data + 1); break; case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE: if (attr->length != 6) break; tun->tag_used++; tun->medium_type = WPA_GET_BE24(data + 1); break; case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID: if (data[0] < RADIUS_TUNNEL_TAGS) { data++; dlen--; } if (dlen >= sizeof(buf)) break; os_memcpy(buf, data, dlen); buf[dlen] = '\0'; vlan_id = atoi(buf); if (vlan_id <= 0) break; tun->tag_used++; tun->vlanid = vlan_id; break; case RADIUS_ATTR_EGRESS_VLANID: /* RFC 4675 */ if (attr->length != 6) break; vlan_id = WPA_GET_BE24(data + 1); if (vlan_id <= 0) break; if (data[0] == 0x32) *untagged = vlan_id; else if (data[0] == 0x31 && tagged && taggedidx < numtagged) tagged[taggedidx++] = vlan_id; break; } } /* Use tunnel with the lowest tag for untagged VLAN id */ for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) { tun = &tunnel[i]; if (tun->tag_used && tun->type == RADIUS_TUNNEL_TYPE_VLAN && tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 && tun->vlanid > 0) { *untagged = tun->vlanid; break; } } if (taggedidx) qsort(tagged, taggedidx, sizeof(int), cmp_int); if (*untagged > 0 || taggedidx) return 1; return 0; }
static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len; u8 type; tls_key_exchange keyx; const struct tls_cipher_suite *suite; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short ClientKeyExchange " "(Left=%lu)", (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } type = *pos++; len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ClientKeyExchange " "length (len=%lu != left=%lu)", (unsigned long) len, (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected ClientKeyExchange)", type); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange"); wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len); suite = tls_get_cipher_suite(conn->rl.cipher_suite); if (suite == NULL) keyx = TLS_KEY_X_NULL; else keyx = suite->key_exchange; if (keyx == TLS_KEY_X_DH_anon && tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0) return -1; if (keyx != TLS_KEY_X_DH_anon && tls_process_client_key_exchange_rsa(conn, pos, end) < 0) return -1; *in_len = end - in_data; conn->state = CERTIFICATE_VERIFY; return 0; }
static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen, struct ieee802_11_elems *elems, int show_errors) { #define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ ((u32) (a)[2])) unsigned int oui; /* first 3 bytes in vendor specific information element are the IEEE * OUI of the vendor. The following byte is used a vendor specific * sub-type. */ if (elen < 4) { if (show_errors) { DBG_871X("short vendor specific " "information element ignored (len=%lu)\n", (unsigned long) elen); } return -1; } oui = WPA_GET_BE24(pos); switch (oui) { case OUI_MICROSOFT: /* Microsoft/Wi-Fi information elements are further typed and * subtyped */ switch (pos[3]) { case 1: /* Microsoft OUI (00:50:F2) with OUI Type 1: * real WPA information element */ elems->wpa_ie = pos; elems->wpa_ie_len = elen; break; case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */ if (elen < 5) { DBG_871X("short WME " "information element ignored " "(len=%lu)\n", (unsigned long) elen); return -1; } switch (pos[4]) { case WME_OUI_SUBTYPE_INFORMATION_ELEMENT: case WME_OUI_SUBTYPE_PARAMETER_ELEMENT: elems->wme = pos; elems->wme_len = elen; break; case WME_OUI_SUBTYPE_TSPEC_ELEMENT: elems->wme_tspec = pos; elems->wme_tspec_len = elen; break; default: DBG_871X("unknown WME " "information element ignored " "(subtype=%d len=%lu)\n", pos[4], (unsigned long) elen); return -1; } break; case 4: /* Wi-Fi Protected Setup (WPS) IE */ elems->wps_ie = pos; elems->wps_ie_len = elen; break; default: DBG_871X("Unknown Microsoft " "information element ignored " "(type=%d len=%lu)\n", pos[3], (unsigned long) elen); return -1; } break; case OUI_BROADCOM: switch (pos[3]) { case VENDOR_HT_CAPAB_OUI_TYPE: elems->vendor_ht_cap = pos; elems->vendor_ht_cap_len = elen; break; default: DBG_871X("Unknown Broadcom " "information element ignored " "(type=%d len=%lu)\n", pos[3], (unsigned long) elen); return -1; } break; default: DBG_871X("unknown vendor specific information " "element ignored (vendor OUI %02x:%02x:%02x " "len=%lu)\n", pos[0], pos[1], pos[2], (unsigned long) elen); return -1; } return 0; }
static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len; u8 type; size_t hlen, buflen; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf; enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; u16 slen; if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) { if (conn->verify_peer) { wpa_printf(MSG_DEBUG, "TLSv1: Client did not include " "CertificateVerify"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } return tls_process_change_cipher_spec(conn, ct, in_data, in_len); } if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " "received content type 0x%x", ct); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify " "message (len=%lu)", (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } type = *pos++; len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify " "message length (len=%lu != left=%lu)", (unsigned long) len, (unsigned long) left); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) { wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " "message %d (expected CertificateVerify)", type); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify"); /* * struct { * Signature signature; * } CertificateVerify; */ hpos = hash; if (alg == SIGN_ALG_RSA) { hlen = MD5_MAC_LEN; if (conn->verify.md5_cert == NULL || crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.md5_cert = NULL; crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL); conn->verify.sha1_cert = NULL; return -1; } hpos += MD5_MAC_LEN; } else crypto_hash_finish(conn->verify.md5_cert, NULL, NULL); conn->verify.md5_cert = NULL; hlen = SHA1_MAC_LEN; if (conn->verify.sha1_cert == NULL || crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) { conn->verify.sha1_cert = NULL; tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha1_cert = NULL; if (alg == SIGN_ALG_RSA) hlen += MD5_MAC_LEN; wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen); if (end - pos < 2) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } slen = WPA_GET_BE16(pos); pos += 2; if (end - pos < slen) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos); if (conn->client_rsa_key == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify " "signature"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } buflen = end - pos; buf = os_malloc(end - pos); if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key, pos, end - pos, buf, &buflen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature"); os_free(buf); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECRYPT_ERROR); return -1; } wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature", buf, buflen); if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in " "CertificateVerify - did not match with calculated " "hash"); os_free(buf); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECRYPT_ERROR); return -1; } os_free(buf); *in_len = end - in_data; conn->state = CHANGE_CIPHER_SPEC; return 0; }
static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, const u8 *sa, u16 info_id, const u8 *data, size_t slen) { const u8 *pos = data; struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa); switch (info_id) { case ANQP_CAPABILITY_LIST: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " ANQP Capability list", MAC2STR(sa)); break; case ANQP_VENUE_NAME: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " Venue Name", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen); if (bss) { wpabuf_free(bss->anqp_venue_name); bss->anqp_venue_name = wpabuf_alloc_copy(pos, slen); } break; case ANQP_NETWORK_AUTH_TYPE: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " Network Authentication Type information", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication " "Type", pos, slen); if (bss) { wpabuf_free(bss->anqp_network_auth_type); bss->anqp_network_auth_type = wpabuf_alloc_copy(pos, slen); } break; case ANQP_ROAMING_CONSORTIUM: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " Roaming Consortium list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium", pos, slen); if (bss) { wpabuf_free(bss->anqp_roaming_consortium); bss->anqp_roaming_consortium = wpabuf_alloc_copy(pos, slen); } break; case ANQP_IP_ADDR_TYPE_AVAILABILITY: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " IP Address Type Availability information", MAC2STR(sa)); wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability", pos, slen); if (bss) { wpabuf_free(bss->anqp_ip_addr_type_availability); bss->anqp_ip_addr_type_availability = wpabuf_alloc_copy(pos, slen); } break; case ANQP_NAI_REALM: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " NAI Realm list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen); if (bss) { wpabuf_free(bss->anqp_nai_realm); bss->anqp_nai_realm = wpabuf_alloc_copy(pos, slen); } break; case ANQP_3GPP_CELLULAR_NETWORK: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " 3GPP Cellular Network information", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network", pos, slen); if (bss) { wpabuf_free(bss->anqp_3gpp); bss->anqp_3gpp = wpabuf_alloc_copy(pos, slen); } break; case ANQP_DOMAIN_NAME: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " Domain Name list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen); if (bss) { wpabuf_free(bss->anqp_domain_name); bss->anqp_domain_name = wpabuf_alloc_copy(pos, slen); } break; case ANQP_VENDOR_SPECIFIC: if (slen < 3) return; switch (WPA_GET_BE24(pos)) { default: wpa_printf(MSG_DEBUG, "Interworking: Unsupported " "vendor-specific ANQP OUI %06x", WPA_GET_BE24(pos)); return; } break; default: wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID " "%u", info_id); break; } }
/** * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information * @msg: RADIUS message * Returns: VLAN ID for the first tunnel configuration of -1 if none is found */ int radius_msg_get_vlanid(struct radius_msg *msg) { struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun; size_t i; struct radius_attr_hdr *attr = NULL; const u8 *data; char buf[10]; size_t dlen; os_memset(&tunnel, 0, sizeof(tunnel)); for (i = 0; i < msg->attr_used; i++) { attr = radius_get_attr_hdr(msg, i); data = (const u8 *) (attr + 1); dlen = attr->length - sizeof(*attr); if (attr->length < 3) continue; if (data[0] >= RADIUS_TUNNEL_TAGS) tun = &tunnel[0]; else tun = &tunnel[data[0]]; switch (attr->type) { case RADIUS_ATTR_TUNNEL_TYPE: if (attr->length != 6) break; tun->tag_used++; tun->type = WPA_GET_BE24(data + 1); break; case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE: if (attr->length != 6) break; tun->tag_used++; tun->medium_type = WPA_GET_BE24(data + 1); break; case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID: if (data[0] < RADIUS_TUNNEL_TAGS) { data++; dlen--; } if (dlen >= sizeof(buf)) break; os_memcpy(buf, data, dlen); buf[dlen] = '\0'; tun->tag_used++; tun->vlanid = atoi(buf); break; } } for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) { tun = &tunnel[i]; if (tun->tag_used && tun->type == RADIUS_TUNNEL_TYPE_VLAN && tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 && tun->vlanid > 0) return tun->vlanid; } return -1; }
static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end, *c; size_t left, len, i, j; u16 cipher_suite; u16 num_suites; int compr_null_found; u16 ext_type, ext_len; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { tlsv1_server_log(conn, "Expected Handshake; received content type 0x%x", ct); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) goto decode_error; /* HandshakeType msg_type */ if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) { tlsv1_server_log(conn, "Received unexpected handshake message %d (expected ClientHello)", *pos); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } tlsv1_server_log(conn, "Received ClientHello"); pos++; /* uint24 length */ len = WPA_GET_BE24(pos); pos += 3; left -= 4; if (len > left) goto decode_error; /* body - ClientHello */ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len); end = pos + len; /* ProtocolVersion client_version */ if (end - pos < 2) goto decode_error; conn->client_version = WPA_GET_BE16(pos); tlsv1_server_log(conn, "Client version %d.%d", conn->client_version >> 8, conn->client_version & 0xff); if (conn->client_version < TLS_VERSION_1) { tlsv1_server_log(conn, "Unexpected protocol version in ClientHello %u.%u", conn->client_version >> 8, conn->client_version & 0xff); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_PROTOCOL_VERSION); return -1; }
static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct, const u8 *in_data, size_t *in_len) { const u8 *pos, *end; size_t left, len, hlen; u8 verify_data[TLS_VERIFY_DATA_LEN]; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; " "received content type 0x%x", ct); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } pos = in_data; left = *in_len; if (left < 4) { wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for " "Finished", (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) { wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received " "type 0x%x", pos[0]); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_UNEXPECTED_MESSAGE); return -1; } len = WPA_GET_BE24(pos + 1); pos += 4; left -= 4; if (len > left) { wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished " "(len=%lu > left=%lu)", (unsigned long) len, (unsigned long) left); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } end = pos + len; if (len != TLS_VERIFY_DATA_LEN) { wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length " "in Finished: %lu (expected %d)", (unsigned long) len, TLS_VERIFY_DATA_LEN); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); return -1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished", pos, TLS_VERIFY_DATA_LEN); #ifdef CONFIG_TLSV12 if (conn->rl.tls_version >= TLS_VERSION_1_2) { hlen = SHA256_MAC_LEN; if (conn->verify.sha256_server == NULL || crypto_hash_finish(conn->verify.sha256_server, hash, &hlen) < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.sha256_server = NULL; return -1; } conn->verify.sha256_server = NULL; } else { #endif /* CONFIG_TLSV12 */ hlen = MD5_MAC_LEN; if (conn->verify.md5_server == NULL || crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); conn->verify.md5_server = NULL; crypto_hash_finish(conn->verify.sha1_server, NULL, NULL); conn->verify.sha1_server = NULL; return -1; } conn->verify.md5_server = NULL; hlen = SHA1_MAC_LEN; if (conn->verify.sha1_server == NULL || crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN, &hlen) < 0) { conn->verify.sha1_server = NULL; tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha1_server = NULL; hlen = MD5_MAC_LEN + SHA1_MAC_LEN; #ifdef CONFIG_TLSV12 } #endif /* CONFIG_TLSV12 */ if (tls_prf(conn->rl.tls_version, conn->master_secret, TLS_MASTER_SECRET_LEN, "server finished", hash, hlen, verify_data, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECRYPT_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)", verify_data, TLS_VERIFY_DATA_LEN); if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECRYPT_ERROR); return -1; } wpa_printf(MSG_DEBUG, "TLSv1: Received Finished"); *in_len = end - in_data; conn->state = (conn->session_resumed || conn->use_session_ticket) ? CHANGE_CIPHER_SPEC : ACK_FINISHED; return 0; }
static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, struct ieee802_11_elems *elems, int show_errors) { unsigned int oui; /* first 3 bytes in vendor specific information element are the IEEE * OUI of the vendor. The following byte is used a vendor specific * sub-type. */ if (elen < 4) { if (show_errors) { wpa_printf(MSG_MSGDUMP, "short vendor specific " "information element ignored (len=%lu)", (unsigned long) elen); } return -1; } oui = WPA_GET_BE24(pos); switch (oui) { case OUI_MICROSOFT: /* Microsoft/Wi-Fi information elements are further typed and * subtyped */ switch (pos[3]) { case 1: /* Microsoft OUI (00:50:F2) with OUI Type 1: * real WPA information element */ elems->wpa_ie = pos; elems->wpa_ie_len = elen; break; case WMM_OUI_TYPE: /* WMM information element */ if (elen < 5) { wpa_printf(MSG_MSGDUMP, "short WMM " "information element ignored " "(len=%lu)", (unsigned long) elen); return -1; } switch (pos[4]) { case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT: case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT: /* * Share same pointer since only one of these * is used and they start with same data. * Length field can be used to distinguish the * IEs. */ elems->wmm = pos; elems->wmm_len = elen; break; case WMM_OUI_SUBTYPE_TSPEC_ELEMENT: elems->wmm_tspec = pos; elems->wmm_tspec_len = elen; break; default: wpa_printf(MSG_EXCESSIVE, "unknown WMM " "information element ignored " "(subtype=%d len=%lu)", pos[4], (unsigned long) elen); return -1; } break; case 4: /* Wi-Fi Protected Setup (WPS) IE */ elems->wps_ie = pos; elems->wps_ie_len = elen; break; default: wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft " "information element ignored " "(type=%d len=%lu)", pos[3], (unsigned long) elen); return -1; } break; case OUI_WFA: switch (pos[3]) { case P2P_OUI_TYPE: /* Wi-Fi Alliance - P2P IE */ elems->p2p = pos; elems->p2p_len = elen; break; default: wpa_printf(MSG_MSGDUMP, "Unknown WFA " "information element ignored " "(type=%d len=%lu)\n", pos[3], (unsigned long) elen); return -1; } break; case OUI_BROADCOM: switch (pos[3]) { case VENDOR_HT_CAPAB_OUI_TYPE: elems->vendor_ht_cap = pos; elems->vendor_ht_cap_len = elen; break; default: wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom " "information element ignored " "(type=%d len=%lu)", pos[3], (unsigned long) elen); return -1; } break; default: wpa_printf(MSG_EXCESSIVE, "unknown vendor specific " "information element ignored (vendor OUI " "%02x:%02x:%02x len=%lu)", pos[0], pos[1], pos[2], (unsigned long) elen); return -1; } return 0; }