u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level, u8 description, size_t *out_len) { u8 *alert, *pos, *length; wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description); *out_len = 0; alert = os_malloc(10); if (alert == NULL) return NULL; pos = alert; /* TLSPlaintext */ /* ContentType type */ *pos++ = TLS_CONTENT_TYPE_ALERT; /* ProtocolVersion version */ WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version : TLS_VERSION); pos += 2; /* uint16 length (to be filled) */ length = pos; pos += 2; /* opaque fragment[TLSPlaintext.length] */ /* Alert */ /* AlertLevel level */ *pos++ = level; /* AlertDescription description */ *pos++ = description; WPA_PUT_BE16(length, pos - length - 2); *out_len = pos - alert; return alert; }
static struct wpabuf * wifi_display_build_go_ie(struct p2p_group *group) { struct wpabuf *wfd_subelems, *wfd_ie; struct p2p_group_member *m; u8 *len; unsigned int count = 0; if (!group->p2p->wfd_ie_probe_resp) return NULL; wfd_subelems = wpabuf_alloc(wpabuf_len(group->p2p->wfd_ie_probe_resp) + group->num_members * 24 + 100); if (wfd_subelems == NULL) return NULL; if (group->p2p->wfd_dev_info) wpabuf_put_buf(wfd_subelems, group->p2p->wfd_dev_info); if (group->p2p->wfd_assoc_bssid) wpabuf_put_buf(wfd_subelems, group->p2p->wfd_assoc_bssid); if (group->p2p->wfd_coupled_sink_info) wpabuf_put_buf(wfd_subelems, group->p2p->wfd_coupled_sink_info); /* Build WFD Session Info */ wpabuf_put_u8(wfd_subelems, WFD_SUBELEM_SESSION_INFO); len = wpabuf_put(wfd_subelems, 2); m = group->members; while (m) { if (wifi_display_add_dev_info_descr(wfd_subelems, m)) count++; m = m->next; } if (count == 0) { /* No Wi-Fi Display clients - do not include subelement */ wfd_subelems->used -= 3; } else { WPA_PUT_BE16(len, (u8 *) wpabuf_put(wfd_subelems, 0) - len - 2); wpa_printf(MSG_DEBUG, "WFD: WFD Session Info: %u descriptors", count); } wfd_ie = wifi_display_encaps(wfd_subelems); wpabuf_free(wfd_subelems); return wfd_ie; }
int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll, const u8 *auth_macs, size_t auth_macs_count) { #ifdef CONFIG_WPS2 u8 *len; wpabuf_put_be16(msg, ATTR_VENDOR_EXT); len = wpabuf_put(msg, 2); /* to be filled */ wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA); wpa_printf(MSG_DEBUG, "WPS: * Version2 (0x%x)", WPS_VERSION); wpabuf_put_u8(msg, WFA_ELEM_VERSION2); wpabuf_put_u8(msg, 1); wpabuf_put_u8(msg, WPS_VERSION); if (req_to_enroll) { wpa_printf(MSG_DEBUG, "WPS: * Request to Enroll (1)"); wpabuf_put_u8(msg, WFA_ELEM_REQUEST_TO_ENROLL); wpabuf_put_u8(msg, 1); wpabuf_put_u8(msg, 1); } if (auth_macs && auth_macs_count) { size_t i; wpa_printf(MSG_DEBUG, "WPS: * AuthorizedMACs (count=%d)", (int) auth_macs_count); wpabuf_put_u8(msg, WFA_ELEM_AUTHORIZEDMACS); wpabuf_put_u8(msg, auth_macs_count * ETH_ALEN); wpabuf_put_data(msg, auth_macs, auth_macs_count * ETH_ALEN); for (i = 0; i < auth_macs_count; i++) wpa_printf(MSG_DEBUG, "WPS: AuthorizedMAC: " MACSTR, MAC2STR(&auth_macs[i * ETH_ALEN])); } WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2); #endif /* CONFIG_WPS2 */ #ifdef CONFIG_WPS_TESTING if (WPS_VERSION > 0x20) { wpa_printf(MSG_DEBUG, "WPS: * Extensibility Testing - extra " "attribute"); wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST); wpabuf_put_be16(msg, 1); wpabuf_put_u8(msg, 42); } #endif /* CONFIG_WPS_TESTING */ return 0; }
static int ikev2_build_nr(struct ikev2_responder_data *data, struct wpabuf *msg, u8 next_payload) { struct ikev2_payload_hdr *phdr; size_t plen; wpa_printf(MSG_DEBUG, "IKEV2: Adding Nr payload"); /* Nr - RFC 4306, Sect. 3.9 */ phdr = wpabuf_put(msg, sizeof(*phdr)); phdr->next_payload = next_payload; phdr->flags = 0; wpabuf_put_data(msg, data->r_nonce, data->r_nonce_len); plen = (u8 *)wpabuf_put(msg, 0) - (u8 *)phdr; WPA_PUT_BE16(phdr->payload_length, plen); return 0; }
static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm, struct eap_gpsk_data *data, u8 id) { u8 *pos, *start; size_t len, miclen; struct eap_gpsk_csuite *csuite; struct wpabuf *req; wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3"); miclen = eap_gpsk_mic_len(data->vendor, data->specifier); len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->server_id_len + sizeof(struct eap_gpsk_csuite) + 2 + miclen; req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, EAP_CODE_REQUEST, id); if (req == NULL) { wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory " "for request/GPSK-3"); eap_gpsk_state(data, FAILURE); return NULL; } wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_3); start = wpabuf_put(req, 0); wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN); wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN); wpabuf_put_be16(req, sm->server_id_len); wpabuf_put_data(req, sm->server_id, sm->server_id_len); csuite = wpabuf_put(req, sizeof(*csuite)); WPA_PUT_BE32(csuite->vendor, data->vendor); WPA_PUT_BE16(csuite->specifier, data->specifier); /* no PD_Payload_2 */ wpabuf_put_be16(req, 0); pos = wpabuf_put(req, miclen); if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, data->specifier, start, pos - start, pos) < 0) { os_free(req); eap_gpsk_state(data, FAILURE); return NULL; } return req; }
/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, struct wpa_eapol_key *key, u16 ver) { u16 keydatalen = WPA_GET_BE16(key->key_data_length); wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",(u8 *) (key + 1), keydatalen); if (!sm->ptk_set) //wpa_supplicant_verify_eapol_key_mic ÖÐÉèÖÃ { lwip_log("WPA: PTK not available, cannot decrypt EAPOL-Key key data.\n"); return -1; } /* Decrypt key data here so that this operation does not need * to be implemented separately for each message type. */ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { u8 ek[32]; os_memcpy(ek, key->key_iv, 16); os_memcpy(ek + 16, sm->ptk.kek, 16); rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen); } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { u8 buf[512]; if (keydatalen % 8) { lwip_log("WPA: Unsupported AES-WRAP len %d\n", keydatalen); return -1; } keydatalen -= 8; /* AES-WRAP adds 8 bytes */ if (buf == NULL) { lwip_log("WPA: No memory for AES-UNWRAP buffer\n"); return -1; } if (aes_unwrap(sm->ptk.kek, keydatalen / 8, (u8 *)(key + 1), buf)) { lwip_log("WPA: AES unwrap failed - could not decrypt EAPOL-Key key data\n"); return -1; } os_memcpy(key + 1, buf, keydatalen); WPA_PUT_BE16(key->key_data_length, keydatalen); } wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data", (u8*)(key + 1), keydatalen); return 0; }
static int ikev2_build_notification(struct ikev2_responder_data *data, struct wpabuf *msg, u8 next_payload) { struct ikev2_payload_hdr *phdr; size_t plen; wpa_printf(MSG_DEBUG, "IKEV2: Adding Notification payload"); if (data->error_type == 0) { wpa_printf(MSG_INFO, "IKEV2: No Notify Message Type " "available"); return -1; } /* Notify - RFC 4306, Sect. 3.10 */ phdr = wpabuf_put(msg, sizeof(*phdr)); phdr->next_payload = next_payload; phdr->flags = 0; wpabuf_put_u8(msg, 0); /* Protocol ID: no existing SA */ wpabuf_put_u8(msg, 0); /* SPI Size */ wpabuf_put_be16(msg, data->error_type); switch (data->error_type) { case INVALID_KE_PAYLOAD: if (data->proposal.dh == -1) { wpa_printf(MSG_INFO, "IKEV2: No DH Group selected for " "INVALID_KE_PAYLOAD notifications"); return -1; } wpabuf_put_be16(msg, data->proposal.dh); wpa_printf(MSG_DEBUG, "IKEV2: INVALID_KE_PAYLOAD - request " "DH Group #%d", data->proposal.dh); break; case AUTHENTICATION_FAILED: /* no associated data */ break; default: wpa_printf(MSG_INFO, "IKEV2: Unsupported Notify Message Type " "%d", data->error_type); return -1; } plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; WPA_PUT_BE16(phdr->payload_length, plen); return 0; }
static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, const u8 *req_authenticator, const u8 *secret, size_t secret_len, u8 *ebuf, size_t *elen) { int i, len, first = 1; u8 hash[MD5_MAC_LEN], saltbuf[2], *pos; const u8 *addr[3]; size_t _len[3]; WPA_PUT_BE16(saltbuf, salt); len = 1 + key_len; if (len & 0x0f) { len = (len & 0xf0) + 16; } os_memset(ebuf, 0, len); ebuf[0] = key_len; os_memcpy(ebuf + 1, key, key_len); *elen = len; pos = ebuf; while (len > 0) { /* b(1) = MD5(Secret + Request-Authenticator + Salt) * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ addr[0] = secret; _len[0] = secret_len; if (first) { addr[1] = req_authenticator; _len[1] = MD5_MAC_LEN; addr[2] = saltbuf; _len[2] = sizeof(saltbuf); } else { addr[1] = pos - MD5_MAC_LEN; _len[1] = MD5_MAC_LEN; } md5_vector(first ? 3 : 2, addr, _len, hash); first = 0; for (i = 0; i < MD5_MAC_LEN; i++) *pos++ ^= hash[i]; len -= MD5_MAC_LEN; } }
static int ikev2_build_ni(struct ikev2_initiator_data *data, struct wpabuf *msg, u8 next_payload) { struct ikev2_payload_hdr *phdr; size_t plen; asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: Adding Ni payload"); /* Ni - RFC 4306, Sect. 3.9 */ phdr = wpabuf_put(msg, sizeof(*phdr)); phdr->next_payload = next_payload; phdr->flags = 0; wpabuf_put_data(msg, data->i_nonce, data->i_nonce_len); plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; WPA_PUT_BE16(phdr->payload_length, plen); return 0; }
static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end) { u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN]; size_t clen; int res; if (tls_derive_pre_master_secret(pre_master_secret) < 0 || tls_derive_keys(conn, pre_master_secret, TLS_PRE_MASTER_SECRET_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } /* EncryptedPreMasterSecret */ if (conn->server_rsa_key == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to " "use for encrypting pre-master secret"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } /* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */ *pos += 2; clen = end - *pos; res = crypto_public_key_encrypt_pkcs1_v15( conn->server_rsa_key, pre_master_secret, TLS_PRE_MASTER_SECRET_LEN, *pos, &clen); os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN); if (res < 0) { wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } WPA_PUT_BE16(*pos - 2, clen); wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret", *pos, clen); *pos += clen; return 0; }
static u8 * eap_mschapv2_build_success_req(struct eap_sm *sm, struct eap_mschapv2_data *data, int id, size_t *reqDataLen) { struct eap_hdr *req; struct eap_mschapv2_hdr *ms; u8 *pos, *msg; char *message = "OK"; size_t ms_len; ms_len = sizeof(*ms) + 2 + 2 * sizeof(data->auth_response) + 1 + 2 + strlen(message); req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqDataLen, ms_len, EAP_CODE_REQUEST, id, &pos); if (req == NULL) { wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory" " for request"); data->state = FAILURE; return NULL; } ms = (struct eap_mschapv2_hdr *) pos; ms->op_code = MSCHAPV2_OP_SUCCESS; ms->mschapv2_id = data->resp_mschapv2_id; WPA_PUT_BE16(ms->ms_length, ms_len); msg = pos = (u8 *) (ms + 1); *pos++ = 'S'; *pos++ = '='; pos += wpa_snprintf_hex_uppercase((char *) pos, sizeof(data->auth_response) * 2 + 1, data->auth_response, sizeof(data->auth_response)); *pos++ = ' '; *pos++ = 'M'; *pos++ = '='; memcpy(pos, message, strlen(message)); wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Success Request Message", msg, ms_len - sizeof(*ms)); return (u8 *) req; }
static struct wpabuf * eap_mschapv2_build_challenge( struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id) { struct wpabuf *req; struct eap_mschapv2_hdr *ms; char *name = "hostapd"; /* TODO: make this configurable */ size_t ms_len; if (!data->auth_challenge_from_tls && os_get_random(data->auth_challenge, CHALLENGE_LEN)) { wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random " "data"); data->state = FAILURE; return NULL; } ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + os_strlen(name); req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, EAP_CODE_REQUEST, id); if (req == NULL) { wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory" " for request"); data->state = FAILURE; return NULL; } ms = wpabuf_put(req, sizeof(*ms)); ms->op_code = MSCHAPV2_OP_CHALLENGE; ms->mschapv2_id = id; WPA_PUT_BE16(ms->ms_length, ms_len); wpabuf_put_u8(req, CHALLENGE_LEN); if (!data->auth_challenge_from_tls) wpabuf_put_data(req, data->auth_challenge, CHALLENGE_LEN); else wpabuf_put(req, CHALLENGE_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge", data->auth_challenge, CHALLENGE_LEN); wpabuf_put_data(req, name, os_strlen(name)); return req; }
static struct wpabuf * eap_mschapv2_build_success_req( struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id) { struct wpabuf *req; struct eap_mschapv2_hdr *ms; u8 *msg; char *message = "OK"; size_t ms_len; ms_len = sizeof(*ms) + 2 + 2 * sizeof(data->auth_response) + 1 + 2 + os_strlen(message); req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, EAP_CODE_REQUEST, id); if (req == NULL) { wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory" " for request"); data->state = FAILURE; return NULL; } ms = wpabuf_put(req, sizeof(*ms)); ms->op_code = MSCHAPV2_OP_SUCCESS; ms->mschapv2_id = data->resp_mschapv2_id; WPA_PUT_BE16(ms->ms_length, ms_len); msg = (u8 *) (ms + 1); wpabuf_put_u8(req, 'S'); wpabuf_put_u8(req, '='); wpa_snprintf_hex_uppercase( wpabuf_put(req, sizeof(data->auth_response) * 2), sizeof(data->auth_response) * 2 + 1, data->auth_response, sizeof(data->auth_response)); wpabuf_put_u8(req, ' '); wpabuf_put_u8(req, 'M'); wpabuf_put_u8(req, '='); wpabuf_put_data(req, message, os_strlen(message)); wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Success Request Message", msg, ms_len - sizeof(*ms)); return req; }
static u8 * eap_mschapv2_build_challenge(struct eap_sm *sm, struct eap_mschapv2_data *data, int id, size_t *reqDataLen) { struct eap_hdr *req; struct eap_mschapv2_hdr *ms; u8 *pos; char *name = "hostapd"; /* TODO: make this configurable */ size_t ms_len; if (hostapd_get_rand(data->auth_challenge, CHALLENGE_LEN)) { wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random " "data"); data->state = FAILURE; return NULL; } ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + strlen(name); req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqDataLen, ms_len, EAP_CODE_REQUEST, id, &pos); if (req == NULL) { wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory" " for request"); data->state = FAILURE; return NULL; } ms = (struct eap_mschapv2_hdr *) pos; ms->op_code = MSCHAPV2_OP_CHALLENGE; ms->mschapv2_id = id; WPA_PUT_BE16(ms->ms_length, ms_len); pos = (u8 *) (ms + 1); *pos++ = CHALLENGE_LEN; memcpy(pos, data->auth_challenge, CHALLENGE_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge", pos, CHALLENGE_LEN); pos += CHALLENGE_LEN; memcpy(pos, name, strlen(name)); return (u8 *) req; }
u8 * eap_tlv_build_result(int id, u16 status, size_t *resp_len) { struct eap_hdr *hdr; u8 *pos; hdr = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, resp_len, 6, EAP_CODE_RESPONSE, id, &pos); if (hdr == NULL) return NULL; *pos++ = 0x80; /* Mandatory */ *pos++ = EAP_TLV_RESULT_TLV; /* Length */ *pos++ = 0; *pos++ = 2; /* Status */ WPA_PUT_BE16(pos, status); return (u8 *) hdr; }
/* IEEE Std 802.1X-2010, 6.2.1 KDF */ static int aes_kdf_128(const u8 *kdk, const char *label, const u8 *context, int ctx_bits, int ret_bits, u8 *ret) { const int h = 128; const int r = 8; int i, n; int lab_len, ctx_len, ret_len, buf_len; u8 *buf; lab_len = os_strlen(label); ctx_len = (ctx_bits + 7) / 8; ret_len = ((ret_bits & 0xffff) + 7) / 8; buf_len = lab_len + ctx_len + 4; os_memset(ret, 0, ret_len); n = (ret_bits + h - 1) / h; if (n > ((0x1 << r) - 1)) return -1; buf = os_zalloc(buf_len); if (buf == NULL) return -1; os_memcpy(buf + 1, label, lab_len); os_memcpy(buf + lab_len + 2, context, ctx_len); WPA_PUT_BE16(&buf[buf_len - 2], ret_bits); for (i = 0; i < n; i++) { buf[0] = (u8) (i + 1); if (omac1_aes_128(kdk, buf, buf_len, ret)) { os_free(buf); return -1; } ret = ret + h / 8; } os_free(buf); return 0; }
struct wpabuf * wps_build_nfc_handover_sel(struct wps_context *ctx, struct wpabuf *nfc_dh_pubkey, const u8 *bssid, int freq) { struct wpabuf *msg; void *len; if (ctx == NULL) return NULL; wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection " "handover select"); if (nfc_dh_pubkey == NULL) { wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password " "configured"); return NULL; } msg = wpabuf_alloc(1000); if (msg == NULL) return msg; len = wpabuf_put(msg, 2); if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER, nfc_dh_pubkey, NULL, 0) || wps_build_ssid(msg, ctx) || wps_build_ap_freq(msg, freq) || (bssid && wps_build_mac_addr(msg, bssid)) || wps_build_wfa_ext(msg, 0, NULL, 0)) { wpabuf_free(msg); return NULL; } WPA_PUT_BE16(len, wpabuf_len(msg) - 2); return msg; }
static int ikev2_build_auth(struct ikev2_responder_data *data, struct wpabuf *msg, u8 next_payload) { struct ikev2_payload_hdr *phdr; size_t plen; const struct ikev2_prf_alg *prf; wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload"); prf = ikev2_get_prf(data->proposal.prf); if (prf == NULL) return -1; /* Authentication - RFC 4306, Sect. 3.8 */ phdr = wpabuf_put(msg, sizeof(*phdr)); phdr->next_payload = next_payload; phdr->flags = 0; wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC); wpabuf_put(msg, 3); /* RESERVED */ /* msg | Ni | prf(SK_pr,IDr') */ if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg, data->IDr, data->IDr_len, ID_KEY_ID, &data->keys, 0, data->shared_secret, data->shared_secret_len, data->i_nonce, data->i_nonce_len, data->key_pad, data->key_pad_len, wpabuf_put(msg, prf->hash_len)) < 0) { wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); return -1; } wpabuf_free(data->r_sign_msg); data->r_sign_msg = NULL; plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; WPA_PUT_BE16(phdr->payload_length, plen); return 0; }
static int ikev2_build_idr(struct ikev2_responder_data *data, struct wpabuf *msg, u8 next_payload) { struct ikev2_payload_hdr *phdr; size_t plen; wpa_printf(MSG_DEBUG, "IKEV2: Adding IDr payload"); if (data->IDr == NULL) { wpa_printf(MSG_INFO, "IKEV2: No IDr available"); return -1; } /* IDr - RFC 4306, Sect. 3.5 */ phdr = wpabuf_put(msg, sizeof(*phdr)); phdr->next_payload = next_payload; phdr->flags = 0; wpabuf_put_u8(msg, ID_KEY_ID); wpabuf_put(msg, 3); /* RESERVED */ wpabuf_put_data(msg, data->IDr, data->IDr_len); plen = (u8 *)wpabuf_put(msg, 0) - (u8 *)phdr; WPA_PUT_BE16(phdr->payload_length, plen); return 0; }
static void eap_sim_derive_mk(struct eap_sim_data *data, const u8 *identity, size_t identity_len) { u8 sel_ver[2]; const unsigned char *addr[5]; size_t len[5]; addr[0] = identity; len[0] = identity_len; addr[1] = (u8 *) data->kc; len[1] = data->num_chal * KC_LEN; addr[2] = data->nonce_mt; len[2] = EAP_SIM_NONCE_MT_LEN; addr[3] = data->ver_list; len[3] = data->ver_list_len; addr[4] = sel_ver; len[4] = 2; WPA_PUT_BE16(sel_ver, data->selected_version); /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */ sha1_vector(5, addr, len, data->mk); wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", data->mk, EAP_SIM_MK_LEN); }
static int ikev2_build_idi(struct ikev2_initiator_data *data, struct wpabuf *msg, u8 next_payload) { struct ikev2_payload_hdr *phdr; size_t plen; asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: Adding IDi payload"); if (data->IDi == NULL) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: No IDi available"); return -1; } /* IDi - RFC 4306, Sect. 3.5 */ phdr = wpabuf_put(msg, sizeof(*phdr)); phdr->next_payload = next_payload; phdr->flags = 0; wpabuf_put_u8(msg, ID_KEY_ID); wpabuf_put(msg, 3); /* RESERVED */ wpabuf_put_data(msg, data->IDi, data->IDi_len); plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; WPA_PUT_BE16(phdr->payload_length, plen); return 0; }
int ccx_send_report (void *ctx) { struct wpa_supplicant *wpa_s = ctx; u8 data[128]; struct os_time t; u32 length; struct ccx_report *rep = (struct ccx_report *)data; struct ccx_apinfo *apinfo = &wpa_s->apinfo; os_memcpy(rep->aironet_snap, aironet_snap, sizeof(aironet_snap)); rep->type = 0x30; // REPORT FRAME rep->function_type = 0x00; os_memcpy(rep->destination, wpa_s->bssid, ETH_ALEN); os_memcpy(rep->source, wpa_s->own_addr, ETH_ALEN); WPA_PUT_BE16(rep->tlv_tag, 0x009b); os_memcpy(rep->aironet_oui, aironet_oui, sizeof(aironet_oui)); os_memcpy(rep->bssid, apinfo->bssid, ETH_ALEN); WPA_PUT_BE16(rep->channel, apinfo->channel); WPA_PUT_BE16(rep->ssid_len, apinfo->ssid_len); length = sizeof(struct ccx_report); os_memcpy(&data[length], apinfo->ssid, apinfo->ssid_len); length += apinfo->ssid_len; os_get_time(&t); if (apinfo->disconnect_time) WPA_PUT_BE16(&data[length], (t.sec - apinfo->disconnect_time)); else WPA_PUT_BE16(&data[length], 0); length += 2; WPA_PUT_BE16(rep->tlv_len, (apinfo->ssid_len + 16)); WPA_PUT_BE16(rep->length, (length - sizeof(aironet_snap))); wpa_sm_ether_send(wpa_s->wpa, wpa_s->bssid, 0, data, length); wpa_hexdump(MSG_DEBUG, "CCX REPORT", data, length); return 0; }
/** * wpa_sm_stkstart - Send EAPOL-Key Request for STK handshake (STK M1) * @sm: Pointer to WPA state machine data from wpa_sm_init() * @peer: MAC address of the peer STA * Returns: 0 on success, or -1 on failure * * Send an EAPOL-Key Request to the current authenticator to start STK * handshake with the peer. */ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer) { size_t rlen, kde_len; struct wpa_eapol_key *req; int key_info, ver; u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos; u16 count; struct rsn_ie_hdr *hdr; struct wpa_peerkey *peerkey; struct wpa_ie_data ie; if (sm->proto != WPA_PROTO_RSN || !sm->ptk_set || !sm->peerkey_enabled) return -1; if (sm->ap_rsn_ie && wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &ie) == 0 && !(ie.capabilities & WPA_CAPABILITY_PEERKEY_ENABLED)) { wpa_printf(MSG_DEBUG, "RSN: Current AP does not support STK"); return -1; } if (sm->pairwise_cipher == WPA_CIPHER_CCMP) ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; else ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; if (wpa_sm_get_bssid(sm, bssid) < 0) { wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key " "SMK M1"); return -1; } /* TODO: find existing entry and if found, use that instead of adding * a new one */ peerkey = os_zalloc(sizeof(*peerkey)); if (peerkey == NULL) return -1; peerkey->initiator = 1; os_memcpy(peerkey->addr, peer, ETH_ALEN); #ifdef CONFIG_IEEE80211W if (wpa_key_mgmt_sha256(sm->key_mgmt)) peerkey->use_sha256 = 1; #endif /* CONFIG_IEEE80211W */ /* SMK M1: * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce, * MIC=MIC, DataKDs=(RSNIE_I, MAC_P KDE)) */ hdr = (struct rsn_ie_hdr *) peerkey->rsnie_i; hdr->elem_id = WLAN_EID_RSN; WPA_PUT_LE16(hdr->version, RSN_VERSION); pos = (u8 *) (hdr + 1); /* Group Suite can be anything for SMK RSN IE; receiver will just * ignore it. */ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; count_pos = pos; pos += 2; count = 0; if (sm->allowed_pairwise_cipher & WPA_CIPHER_CCMP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; count++; } if (sm->allowed_pairwise_cipher & WPA_CIPHER_TKIP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); pos += RSN_SELECTOR_LEN; count++; } WPA_PUT_LE16(count_pos, count); hdr->len = (pos - peerkey->rsnie_i) - 2; peerkey->rsnie_i_len = pos - peerkey->rsnie_i; wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake", peerkey->rsnie_i, peerkey->rsnie_i_len); kde_len = peerkey->rsnie_i_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN; rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, sizeof(*req) + kde_len, &rlen, (void *) &req); if (rbuf == NULL) { wpa_supplicant_peerkey_free(sm, peerkey); return -1; } req->type = EAPOL_KEY_TYPE_RSN; key_info = WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE | WPA_KEY_INFO_REQUEST | ver; WPA_PUT_BE16(req->key_info, key_info); WPA_PUT_BE16(req->key_length, 0); os_memcpy(req->replay_counter, sm->request_counter, WPA_REPLAY_COUNTER_LEN); inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to get random data for INonce"); os_free(rbuf); wpa_supplicant_peerkey_free(sm, peerkey); return -1; } os_memcpy(req->key_nonce, peerkey->inonce, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "WPA: INonce for SMK handshake", req->key_nonce, WPA_NONCE_LEN); WPA_PUT_BE16(req->key_data_length, (u16) kde_len); pos = (u8 *) (req + 1); /* Initiator RSN IE */ pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len); /* Peer MAC address KDE */ wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN); wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer " MACSTR ")", MAC2STR(peer)); wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL, rbuf, rlen, req->key_mic); peerkey->next = sm->peerkey; sm->peerkey = peerkey; return 0; }
static int tls_write_server_certificate_request(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length; size_t rlen; if (!conn->verify_peer) { wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed"); return 0; } pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - CertificateRequest */ /* * enum { * rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), * (255) * } ClientCertificateType; * ClientCertificateType certificate_types<1..2^8-1> */ *pos++ = 1; *pos++ = 1; /* rsa_sign */ /* * opaque DistinguishedName<1..2^16-1> * DistinguishedName certificate_authorities<3..2^16-1> */ /* TODO: add support for listing DNs for trusted CAs */ WPA_PUT_BE16(pos, 0); pos += 2; WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); *msgpos = pos; return 0; }
int radius_msg_add_mppe_keys(struct radius_msg *msg, const u8 *req_authenticator, const u8 *secret, size_t secret_len, const u8 *send_key, size_t send_key_len, const u8 *recv_key, size_t recv_key_len) { struct radius_attr_hdr *attr; u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT); u8 *buf; struct radius_attr_vendor *vhdr; u8 *pos; size_t elen; int hlen; u16 salt; hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2; /* MS-MPPE-Send-Key */ buf = os_malloc(hlen + send_key_len + 16); if (buf == NULL) { return 0; } pos = buf; os_memcpy(pos, &vendor_id, sizeof(vendor_id)); pos += sizeof(vendor_id); vhdr = (struct radius_attr_vendor *) pos; vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY; pos = (u8 *) (vhdr + 1); salt = os_random() | 0x8000; WPA_PUT_BE16(pos, salt); pos += 2; encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret, secret_len, pos, &elen); vhdr->vendor_length = hlen + elen - sizeof(vendor_id); attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, buf, hlen + elen); os_free(buf); if (attr == NULL) { return 0; } /* MS-MPPE-Recv-Key */ buf = os_malloc(hlen + send_key_len + 16); if (buf == NULL) { return 0; } pos = buf; os_memcpy(pos, &vendor_id, sizeof(vendor_id)); pos += sizeof(vendor_id); vhdr = (struct radius_attr_vendor *) pos; vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY; pos = (u8 *) (vhdr + 1); salt ^= 1; WPA_PUT_BE16(pos, salt); pos += 2; encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret, secret_len, pos, &elen); vhdr->vendor_length = hlen + elen - sizeof(vendor_id); attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, buf, hlen + elen); os_free(buf); if (attr == NULL) { return 0; } return 1; }
static int tls_write_server_hello(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length; struct os_time now; size_t rlen; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; os_get_time(&now); WPA_PUT_BE32(conn->server_random, now.sec); if (os_get_random(conn->server_random + 4, TLS_RANDOM_LEN - 4)) { wpa_printf(MSG_ERROR, "TLSv1: Could not generate " "server_random"); return -1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random", conn->server_random, TLS_RANDOM_LEN); conn->session_id_len = TLS_SESSION_ID_MAX_LEN; if (os_get_random(conn->session_id, conn->session_id_len)) { wpa_printf(MSG_ERROR, "TLSv1: Could not generate " "session_id"); return -1; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id", conn->session_id, conn->session_id_len); /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - ServerHello */ /* ProtocolVersion server_version */ WPA_PUT_BE16(pos, TLS_VERSION); pos += 2; /* Random random: uint32 gmt_unix_time, opaque random_bytes */ os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN); pos += TLS_RANDOM_LEN; /* SessionID session_id */ *pos++ = conn->session_id_len; os_memcpy(pos, conn->session_id, conn->session_id_len); pos += conn->session_id_len; /* CipherSuite cipher_suite */ WPA_PUT_BE16(pos, conn->cipher_suite); pos += 2; /* CompressionMethod compression_method */ *pos++ = TLS_COMPRESSION_NULL; if (conn->session_ticket && conn->session_ticket_cb) { int res = conn->session_ticket_cb( conn->session_ticket_cb_ctx, conn->session_ticket, conn->session_ticket_len, conn->client_random, conn->server_random, conn->master_secret); if (res < 0) { wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback " "indicated failure"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_HANDSHAKE_FAILURE); return -1; } conn->use_session_ticket = res; if (conn->use_session_ticket) { if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to " "derive keys"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } } /* * RFC 4507 specifies that server would include an empty * SessionTicket extension in ServerHello and a * NewSessionTicket message after the ServerHello. However, * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket * extension at the moment, does not use such extensions. * * TODO: Add support for configuring RFC 4507 behavior and make * EAP-FAST disable it. */ } WPA_PUT_BE24(hs_length, pos - hs_length - 3); tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; *msgpos = pos; return 0; }
static int tls_write_server_key_exchange(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { tls_key_exchange keyx; const struct tls_cipher_suite *suite; #ifdef EAP_FAST u8 *pos, *rhdr, *hs_start, *hs_length; size_t rlen; u8 *dh_ys; size_t dh_ys_len; #endif /* EAP_FAST */ suite = tls_get_cipher_suite(conn->rl.cipher_suite); if (suite == NULL) keyx = TLS_KEY_X_NULL; else keyx = suite->key_exchange; if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) { wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed"); return 0; } if (keyx != TLS_KEY_X_DH_anon) { /* TODO? */ wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet " "supported with key exchange type %d", keyx); return -1; } #ifdef EAP_FAST if (conn->cred == NULL || conn->cred->dh_p == NULL || conn->cred->dh_g == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for " "ServerKeyExhcange"); return -1; } os_free(conn->dh_secret); conn->dh_secret_len = conn->cred->dh_p_len; conn->dh_secret = os_malloc(conn->dh_secret_len); if (conn->dh_secret == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " "memory for secret (Diffie-Hellman)"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } if (os_get_random(conn->dh_secret, conn->dh_secret_len)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " "data for Diffie-Hellman"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(conn->dh_secret); conn->dh_secret = NULL; return -1; } if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) > 0) conn->dh_secret[0] = 0; /* make sure secret < p */ pos = conn->dh_secret; while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0) pos++; if (pos != conn->dh_secret) { os_memmove(conn->dh_secret, pos, conn->dh_secret_len - (pos - conn->dh_secret)); conn->dh_secret_len -= pos - conn->dh_secret; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value", conn->dh_secret, conn->dh_secret_len); /* Ys = g^secret mod p */ dh_ys_len = conn->cred->dh_p_len; dh_ys = os_malloc(dh_ys_len); if (dh_ys == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for " "Diffie-Hellman"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len, conn->dh_secret, conn->dh_secret_len, conn->cred->dh_p, conn->cred->dh_p_len, dh_ys, &dh_ys_len)) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(dh_ys); return -1; } wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)", dh_ys, dh_ys_len); /* * struct { * select (KeyExchangeAlgorithm) { * case diffie_hellman: * ServerDHParams params; * Signature signed_params; * case rsa: * ServerRSAParams params; * Signature signed_params; * }; * } ServerKeyExchange; * * struct { * opaque dh_p<1..2^16-1>; * opaque dh_g<1..2^16-1>; * opaque dh_Ys<1..2^16-1>; * } ServerDHParams; */ pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - ServerDHParams */ /* dh_p */ if (pos + 2 + conn->cred->dh_p_len > end) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " "dh_p"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(dh_ys); return -1; } WPA_PUT_BE16(pos, conn->cred->dh_p_len); pos += 2; os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len); pos += conn->cred->dh_p_len; /* dh_g */ if (pos + 2 + conn->cred->dh_g_len > end) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " "dh_g"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(dh_ys); return -1; } WPA_PUT_BE16(pos, conn->cred->dh_g_len); pos += 2; os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len); pos += conn->cred->dh_g_len; /* dh_Ys */ if (pos + 2 + dh_ys_len > end) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " "dh_Ys"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(dh_ys); return -1; } WPA_PUT_BE16(pos, dh_ys_len); pos += 2; os_memcpy(pos, dh_ys, dh_ys_len); pos += dh_ys_len; os_free(dh_ys); WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); *msgpos = pos; return 0; #else /* EAP_FAST */ return -1; #endif /* EAP_FAST */ }
u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len) { u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr; struct os_time now; size_t len, i; wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello"); *out_len = 0; os_get_time(&now); WPA_PUT_BE32(conn->client_random, now.sec); if (os_get_random(conn->client_random + 4, TLS_RANDOM_LEN - 4)) { wpa_printf(MSG_ERROR, "TLSv1: Could not generate " "client_random"); return NULL; } wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random", conn->client_random, TLS_RANDOM_LEN); len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len; hello = os_malloc(len); if (hello == NULL) return NULL; end = hello + len; rhdr = hello; pos = rhdr + TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - ClientHello */ /* ProtocolVersion client_version */ WPA_PUT_BE16(pos, TLS_VERSION); pos += 2; /* Random random: uint32 gmt_unix_time, opaque random_bytes */ os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN); pos += TLS_RANDOM_LEN; /* SessionID session_id */ *pos++ = conn->session_id_len; os_memcpy(pos, conn->session_id, conn->session_id_len); pos += conn->session_id_len; /* CipherSuite cipher_suites<2..2^16-1> */ WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites); pos += 2; for (i = 0; i < conn->num_cipher_suites; i++) { WPA_PUT_BE16(pos, conn->cipher_suites[i]); pos += 2; } /* CompressionMethod compression_methods<1..2^8-1> */ *pos++ = 1; *pos++ = TLS_COMPRESSION_NULL; if (conn->client_hello_ext) { os_memcpy(pos, conn->client_hello_ext, conn->client_hello_ext_len); pos += conn->client_hello_ext_len; } WPA_PUT_BE24(hs_length, pos - hs_length - 3); tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, out_len) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(hello); return NULL; } conn->state = SERVER_HELLO; return hello; }
static int tls_write_client_certificate_verify(struct tlsv1_client *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start; size_t rlen, hlen, clen; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos; enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* * RFC 2246: 7.4.3 and 7.4.8: * Signature signature * * RSA: * digitally-signed struct { * opaque md5_hash[16]; * opaque sha_hash[20]; * }; * * DSA: * digitally-signed struct { * opaque sha_hash[20]; * }; * * The hash values are calculated over all handshake messages sent or * received starting at ClientHello up to, but not including, this * CertificateVerify message, including the type and length fields of * the handshake messages. */ 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) { tls_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; tls_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); /* * RFC 2246, 4.7: * In digital signing, one-way hash functions are used as input for a * signing algorithm. A digitally-signed element is encoded as an * opaque vector <0..2^16-1>, where the length is specified by the * signing algorithm and key. * * In RSA signing, a 36-byte structure of two hashes (one SHA and one * MD5) is signed (encrypted with the private key). It is encoded with * PKCS #1 block type 0 or type 1 as described in [PKCS1]. */ signed_start = pos; /* length to be filled */ pos += 2; clen = end - pos; if (conn->cred == NULL || crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen, pos, &clen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } WPA_PUT_BE16(signed_start, clen); pos += clen; WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } pos = rhdr + rlen; tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); *msgpos = pos; return 0; }
static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end) { #ifdef EAP_FAST /* ClientDiffieHellmanPublic */ u8 *csecret, *csecret_start, *dh_yc, *shared; size_t csecret_len, dh_yc_len, shared_len; csecret_len = conn->dh_p_len; csecret = os_malloc(csecret_len); if (csecret == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " "memory for Yc (Diffie-Hellman)"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } if (os_get_random(csecret, csecret_len)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " "data for Diffie-Hellman"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(csecret); return -1; } if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0) csecret[0] = 0; /* make sure Yc < p */ csecret_start = csecret; while (csecret_len > 1 && *csecret_start == 0) { csecret_start++; csecret_len--; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value", csecret_start, csecret_len); /* Yc = g^csecret mod p */ dh_yc_len = conn->dh_p_len; dh_yc = os_malloc(dh_yc_len); if (dh_yc == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " "memory for Diffie-Hellman"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(csecret); return -1; } if (crypto_mod_exp(conn->dh_g, conn->dh_g_len, csecret_start, csecret_len, conn->dh_p, conn->dh_p_len, dh_yc, &dh_yc_len)) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(csecret); os_free(dh_yc); return -1; } wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)", dh_yc, dh_yc_len); WPA_PUT_BE16(*pos, dh_yc_len); *pos += 2; if (*pos + dh_yc_len > end) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the " "message buffer for Yc"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(csecret); os_free(dh_yc); return -1; } os_memcpy(*pos, dh_yc, dh_yc_len); *pos += dh_yc_len; os_free(dh_yc); shared_len = conn->dh_p_len; shared = os_malloc(shared_len); if (shared == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for " "DH"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(csecret); return -1; } /* shared = Ys^csecret mod p */ if (crypto_mod_exp(conn->dh_ys, conn->dh_ys_len, csecret_start, csecret_len, conn->dh_p, conn->dh_p_len, shared, &shared_len)) { tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(csecret); os_free(shared); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange", shared, shared_len); os_memset(csecret_start, 0, csecret_len); os_free(csecret); if (tls_derive_keys(conn, shared, shared_len)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(shared); return -1; } os_memset(shared, 0, shared_len); os_free(shared); tlsv1_client_free_dh(conn); return 0; #else /* EAP_FAST */ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; #endif /* EAP_FAST */ }