/** * eap_msg_alloc - Allocate a buffer for an EAP message * @vendor: Vendor-Id (0 = IETF) * @type: EAP type * @len: Buffer for returning message length * @payload_len: Payload length in bytes (data after Type) * @code: Message Code (EAP_CODE_*) * @identifier: Identifier * @payload: Pointer to payload pointer that will be set to point to the * beginning of the payload or %NULL if payload pointer is not needed * Returns: Pointer to the allocated message buffer or %NULL on error * * This function can be used to allocate a buffer for an EAP message and fill * in the EAP header. This function is automatically using expanded EAP header * if the selected Vendor-Id is not IETF. In other words, most EAP methods do * not need to separately select which header type to use when using this * function to allocate the message buffers. */ struct eap_hdr * eap_msg_alloc(int vendor, EapType type, size_t *len, size_t payload_len, u8 code, u8 identifier, u8 **payload) { struct eap_hdr *hdr; u8 *pos; *len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) + payload_len; hdr = malloc(*len); if (hdr) { hdr->code = code; hdr->identifier = identifier; hdr->length = host_to_be16(*len); pos = (u8 *) (hdr + 1); if (vendor == EAP_VENDOR_IETF) { *pos++ = type; } else { *pos++ = EAP_TYPE_EXPANDED; WPA_PUT_BE24(pos, vendor); pos += 3; WPA_PUT_BE32(pos, type); pos += 4; } if (payload) *payload = pos; } return hdr; }
static u8 * eap_vendor_test_buildReq(struct eap_sm *sm, void *priv, int id, size_t *reqDataLen) { struct eap_vendor_test_data *data = priv; struct eap_hdr *req; u8 *pos; *reqDataLen = sizeof(*req) + 8 + 1; req = VM_MALLOC(*reqDataLen); if (req == NULL) { wpa_printf(MSG_ERROR, "EAP-VENDOR-TEST: Failed to allocate " "memory for request"); return NULL; } req->code = EAP_CODE_REQUEST; req->identifier = id; req->length = htons(*reqDataLen); pos = (u8 *) (req + 1); *pos++ = EAP_TYPE_EXPANDED; WPA_PUT_BE24(pos, EAP_VENDOR_ID); pos += 3; WPA_PUT_BE32(pos, EAP_VENDOR_TYPE); pos += 4; *pos = data->state == INIT ? 1 : 3; return (u8 *) req; }
static int tls_write_client_key_exchange(struct tlsv1_client *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length; size_t rlen; tls_key_exchange keyx; const struct tls_cipher_suite *suite; suite = tls_get_cipher_suite(conn->rl.cipher_suite); if (suite == NULL) keyx = TLS_KEY_X_NULL; else keyx = suite->key_exchange; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - ClientKeyExchange */ if (keyx == TLS_KEY_X_DH_anon) { if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0) return -1; } else { if (tlsv1_key_x_rsa(conn, &pos, end) < 0) return -1; } WPA_PUT_BE24(hs_length, pos - hs_length - 3); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, rhdr, end - rhdr, hs_start, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create 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 wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len, int pairwise_cipher, int group_cipher, int key_mgmt) { u8 *pos, *len; u32 suite; if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN) return -1; pos = wpa_ie; *pos++ = WLAN_EID_VENDOR_SPECIFIC; len = pos++; /* to be filled */ WPA_PUT_BE24(pos, OUI_WFA); pos += 3; *pos++ = HS20_OSEN_OUI_TYPE; /* Group Data Cipher Suite */ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher); if (suite == 0) { wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", group_cipher); return -1; } RSN_SELECTOR_PUT(pos, suite); pos += RSN_SELECTOR_LEN; /* Pairwise Cipher Suite Count and List */ WPA_PUT_LE16(pos, 1); pos += 2; suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher); if (suite == 0 || (!wpa_cipher_valid_pairwise(pairwise_cipher) && pairwise_cipher != WPA_CIPHER_NONE)) { wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", pairwise_cipher); return -1; } RSN_SELECTOR_PUT(pos, suite); pos += RSN_SELECTOR_LEN; /* AKM Suite Count and List */ WPA_PUT_LE16(pos, 1); pos += 2; RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN); pos += RSN_SELECTOR_LEN; *len = pos - len - 1; WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); return pos - wpa_ie; }
u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid) { u8 *len; u16 capab; if (!hapd->conf->osen) return eid; *eid++ = WLAN_EID_VENDOR_SPECIFIC; len = eid++; /* to be filled */ WPA_PUT_BE24(eid, OUI_WFA); eid += 3; *eid++ = HS20_OSEN_OUI_TYPE; /* Group Data Cipher Suite */ RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); eid += RSN_SELECTOR_LEN; /* Pairwise Cipher Suite Count and List */ WPA_PUT_LE16(eid, 1); eid += 2; RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP); eid += RSN_SELECTOR_LEN; /* AKM Suite Count and List */ WPA_PUT_LE16(eid, 1); eid += 2; RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN); eid += RSN_SELECTOR_LEN; /* RSN Capabilities */ capab = 0; if (hapd->conf->wmm_enabled) { /* 4 PTKSA replay counters when using WMM */ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); } #ifdef CONFIG_IEEE80211W if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { capab |= WPA_CAPABILITY_MFPC; if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) capab |= WPA_CAPABILITY_MFPR; } #endif /* CONFIG_IEEE80211W */ WPA_PUT_LE16(eid, capab); eid += 2; *len = eid - len - 1; return eid; }
static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype, u8 minor_reason_code, const u8 *addr) { struct ieee80211_mgmt *mgmt; int ret; u8 *pos; if (hapd->driver->send_frame == NULL) return -1; mgmt = os_zalloc(sizeof(*mgmt) + 100); if (mgmt == NULL) return -1; wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR " with minor reason code %u (stype=%u)", MAC2STR(addr), minor_reason_code, stype); mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype); os_memcpy(mgmt->da, addr, ETH_ALEN); os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); if (stype == WLAN_FC_STYPE_DEAUTH) { mgmt->u.deauth.reason_code = host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); pos = (u8 *) (&mgmt->u.deauth.reason_code + 1); } else { mgmt->u.disassoc.reason_code = host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1); } *pos++ = WLAN_EID_VENDOR_SPECIFIC; *pos++ = 4 + 3 + 1; WPA_PUT_BE24(pos, OUI_WFA); pos += 3; *pos++ = P2P_OUI_TYPE; *pos++ = P2P_ATTR_MINOR_REASON_CODE; WPA_PUT_LE16(pos, 1); pos += 2; *pos++ = minor_reason_code; ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt, pos - (u8 *) mgmt, 1); os_free(mgmt); return ret < 0 ? -1 : 0; }
u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid) { u8 bitmap; *eid++ = WLAN_EID_VENDOR_SPECIFIC; *eid++ = 4 + 3 + 1; WPA_PUT_BE24(eid, OUI_WFA); eid += 3; *eid++ = P2P_OUI_TYPE; *eid++ = P2P_ATTR_MANAGEABILITY; WPA_PUT_LE16(eid, 1); eid += 2; bitmap = P2P_MAN_DEVICE_MANAGEMENT; if (hapd->conf->p2p & P2P_ALLOW_CROSS_CONNECTION) bitmap |= P2P_MAN_CROSS_CONNECTION_PERMITTED; bitmap |= P2P_MAN_COEXISTENCE_OPTIONAL; *eid++ = bitmap; return eid; }
u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid) { u8 conf; if (!hapd->conf->hs20) return eid; *eid++ = WLAN_EID_VENDOR_SPECIFIC; *eid++ = 7; WPA_PUT_BE24(eid, OUI_WFA); eid += 3; *eid++ = HS20_INDICATION_OUI_TYPE; conf = HS20_VERSION; /* Release Number */ conf |= HS20_ANQP_DOMAIN_ID_PRESENT; if (hapd->conf->disable_dgaf) conf |= HS20_DGAF_DISABLED; *eid++ = conf; WPA_PUT_LE16(eid, hapd->conf->anqp_domain_id); eid += 2; return eid; }
static int tls_write_server_hello_done(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length; size_t rlen; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - ServerHelloDone (empty) */ 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; }
void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa) { u8 cell_capa[7]; if (wpa_s->conf->mbo_cell_capa == mbo_cell_capa) { wpa_printf(MSG_DEBUG, "MBO: Cellular capability already set to %u", mbo_cell_capa); return; } wpa_s->conf->mbo_cell_capa = mbo_cell_capa; cell_capa[0] = WLAN_EID_VENDOR_SPECIFIC; cell_capa[1] = 5; /* Length */ WPA_PUT_BE24(cell_capa + 2, OUI_WFA); cell_capa[5] = MBO_ATTR_ID_CELL_DATA_CAPA; cell_capa[6] = mbo_cell_capa; wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7); wpa_supplicant_set_default_scan_ies(wpa_s); }
u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, size_t len) { #ifdef CONFIG_OWE u8 *pos = eid; size_t elen; if (hapd->conf->owe_transition_ifname[0] && !hostapd_eid_owe_trans_enabled(hapd)) hostapd_owe_trans_get_info(hapd); if (!hostapd_eid_owe_trans_enabled(hapd)) return pos; elen = hostapd_eid_owe_trans_len(hapd); if (len < elen) { wpa_printf(MSG_DEBUG, "OWE: Not enough room in the buffer for OWE IE"); return pos; } *pos++ = WLAN_EID_VENDOR_SPECIFIC; *pos++ = elen - 2; WPA_PUT_BE24(pos, OUI_WFA); pos += 3; *pos++ = OWE_OUI_TYPE; os_memcpy(pos, hapd->conf->owe_transition_bssid, ETH_ALEN); pos += ETH_ALEN; *pos++ = hapd->conf->owe_transition_ssid_len; os_memcpy(pos, hapd->conf->owe_transition_ssid, hapd->conf->owe_transition_ssid_len); pos += hapd->conf->owe_transition_ssid_len; return pos; #else /* CONFIG_OWE */ return eid; #endif /* CONFIG_OWE */ }
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 tls_write_client_finished(struct tlsv1_client *conn, u8 **msgpos, u8 *end) { u8 *pos, *hs_start; size_t rlen, hlen; u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN]; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; wpa_printf(MSG_DEBUG, "TLSv1: Send Finished"); /* Encrypted Handshake Message: Finished */ hlen = MD5_MAC_LEN; if (conn->verify.md5_client == NULL || crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) { tls_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; tls_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 + 1 + 3, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)", verify_data + 1 + 3, TLS_VERIFY_DATA_LEN); /* Handshake */ pos = hs_start = verify_data; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; /* uint24 length */ WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN); pos += 3; pos += TLS_VERIFY_DATA_LEN; /* verify_data already in place */ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, *msgpos, end - *msgpos, hs_start, pos - hs_start, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } *msgpos += rlen; return 0; }
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_certificate(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start; size_t rlen; struct x509_certificate *cert; const struct tls_cipher_suite *suite; suite = tls_get_cipher_suite(conn->rl.cipher_suite); if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) { wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when " "using anonymous DH"); return 0; } pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate"); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* opaque fragment[TLSPlaintext.length] */ /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; /* body - Certificate */ /* uint24 length (to be filled) */ cert_start = pos; pos += 3; cert = conn->cred->cert; while (cert) { if (pos + 3 + cert->cert_len > end) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space " "for Certificate (cert_len=%lu left=%lu)", (unsigned long) cert->cert_len, (unsigned long) (end - pos)); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } WPA_PUT_BE24(pos, cert->cert_len); pos += 3; os_memcpy(pos, cert->cert_start, cert->cert_len); pos += cert->cert_len; if (x509_certificate_self_signed(cert)) break; cert = x509_certificate_get_subject(conn->cred->trusted_certs, &cert->issuer); } if (cert == conn->cred->cert || cert == NULL) { /* * Server was not configured with all the needed certificates * to form a full certificate chain. The client may fail to * validate the chain unless it is configured with all the * missing CA certificates. */ wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain " "not configured - validation may fail"); } WPA_PUT_BE24(cert_start, pos - cert_start - 3); 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; }
static int eap_gpsk_derive_keys_aes(const u8 *psk, size_t psk_len, const u8 *seed, size_t seed_len, u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, u8 *pk, size_t *pk_len) { #define EAP_GPSK_SK_LEN_AES 16 #define EAP_GPSK_PK_LEN_AES 16 u8 zero_string[1], mk[32], *pos, *data; u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_AES + EAP_GPSK_PK_LEN_AES]; size_t data_len; /* * inputString = RAND_Client || ID_Client || RAND_Server || ID_Server * (= seed) * KS = 16, PL = psk_len, CSuite_Sel = 0x000000 0x000001 * MK = GKDF-32 (0x00, PL || PSK || CSuite_Sel || inputString) * MSK = GKDF-160 (MK, inputString)[0..63] * EMSK = GKDF-160 (MK, inputString)[64..127] * SK = GKDF-160 (MK, inputString)[128..143] * PK = GKDF-160 (MK, inputString)[144..159] * MID = GKDF-16(0x00, "Method ID" || EAP_Method_Type || CSuite_Sel || * inputString) * Hash-Function = SHA-1 (see [RFC3174]) * hashlen = 20 octets (160 bits) */ os_memset(zero_string, 0, sizeof(zero_string)); data_len = 2 + psk_len + 6 + seed_len; data = os_malloc(data_len); if (data == NULL) return -1; pos = data; WPA_PUT_BE16(pos, psk_len); pos += 2; os_memcpy(pos, psk, psk_len); pos += psk_len; WPA_PUT_BE24(pos, 0); /* CSuite/Vendor = IETF */ pos += 3; WPA_PUT_BE24(pos, EAP_GPSK_CIPHER_AES); /* CSuite/Specifier */ pos += 3; os_memcpy(pos, seed, seed_len); /* inputString */ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation (AES)", data, data_len); if (eap_gpsk_gkdf(zero_string, sizeof(zero_string), data, data_len, mk, sizeof(mk)) < 0) { os_free(data); return -1; } os_free(data); wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, sizeof(mk)); if (eap_gpsk_gkdf(mk, sizeof(mk), seed, seed_len, kdf_out, sizeof(kdf_out)) < 0) return -1; pos = kdf_out; wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN); os_memcpy(msk, pos, EAP_MSK_LEN); pos += EAP_MSK_LEN; wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN); os_memcpy(emsk, pos, EAP_EMSK_LEN); pos += EAP_EMSK_LEN; wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK", pos, EAP_GPSK_SK_LEN_AES); os_memcpy(sk, pos, EAP_GPSK_SK_LEN_AES); *sk_len = EAP_GPSK_SK_LEN_AES; pos += EAP_GPSK_SK_LEN_AES; wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK", pos, EAP_GPSK_PK_LEN_AES); os_memcpy(pk, pos, EAP_GPSK_PK_LEN_AES); *pk_len = EAP_GPSK_PK_LEN_AES; 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 */ }
static u8 * eap_sake_build_msg(struct eap_sake_data *data, u8 **payload, int id, size_t *length, u8 subtype) { struct eap_sake_hdr *req; struct eap_sake_exp_hdr *ereq; size_t pad; u8 *msg; *length += data->expanded_eap ? sizeof(struct eap_sake_exp_hdr) : sizeof(struct eap_sake_hdr); /* Pad to 32-bit boundary; minimum pad length is 2. */ pad = *length % 4; switch (pad) { case 1: pad = 3; break; case 2: pad = 2; break; case 3: pad = 5; break; default: pad = 0; break; } *length += pad; msg = wpa_zalloc(*length); if (msg == NULL) { wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory " "request"); return NULL; } if (data->expanded_eap) { ereq = (struct eap_sake_exp_hdr *) msg; ereq->code = EAP_CODE_RESPONSE; ereq->identifier = id; ereq->length = htons((u16) *length); ereq->type = EAP_TYPE_EXPANDED; WPA_PUT_BE24(ereq->vendor_id, EAP_VENDOR_IETF); WPA_PUT_BE32(ereq->vendor_type, EAP_TYPE_SAKE); ereq->pad = 0; ereq->version = EAP_SAKE_VERSION; ereq->session_id = data->session_id; ereq->subtype = subtype; *payload = (u8 *) (ereq + 1); } else { req = (struct eap_sake_hdr *) msg; req->code = EAP_CODE_RESPONSE; req->identifier = id; req->length = htons((u16) *length); req->type = EAP_TYPE_SAKE; req->version = EAP_SAKE_VERSION; req->session_id = data->session_id; req->subtype = subtype; *payload = (u8 *) (req + 1); } if (pad) { u8 *pos = &msg[*length - pad]; *pos++ = EAP_SAKE_AT_PADDING; *pos++ = pad; } return msg; }
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; }
static u8 * eap_gpsk_process_gpsk_1(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, csuite_list_len, miclen; struct eap_hdr *resp; u8 *rpos, *start; const u8 *csuite_list, *pos, *end; const struct eap_hdr *req; struct eap_gpsk_csuite *csuite; u16 alen; int i, count; if (data->state != GPSK_1) { ret->ignore = TRUE; return NULL; } wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1"); req = (const struct eap_hdr *) reqData; pos = payload; end = payload + payload_len; if (end - pos < 2) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet"); return NULL; } alen = WPA_GET_BE16(pos); pos += 2; if (end - pos < alen) { wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow"); return NULL; } os_free(data->id_server); data->id_server = os_malloc(alen); if (data->id_server == NULL) { wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server"); return NULL; } os_memcpy(data->id_server, pos, alen); data->id_server_len = alen; wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server", data->id_server, data->id_server_len); pos += alen; if (end - pos < EAP_GPSK_RAND_LEN) { wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow"); return NULL; } os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN); wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server", data->rand_server, EAP_GPSK_RAND_LEN); pos += EAP_GPSK_RAND_LEN; if (end - pos < 2) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet"); return NULL; } csuite_list_len = WPA_GET_BE16(pos); pos += 2; if (end - pos < (int) csuite_list_len) { wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow"); return NULL; } csuite_list = pos; if (csuite_list_len == 0 || csuite_list_len % sizeof(struct eap_gpsk_csuite)) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %d", csuite_list_len); return NULL; } count = csuite_list_len / sizeof(struct eap_gpsk_csuite); data->vendor = EAP_GPSK_VENDOR_IETF; data->specifier = EAP_GPSK_CIPHER_RESERVED; csuite = (struct eap_gpsk_csuite *) csuite_list; for (i = 0; i < count; i++) { int vendor, specifier; vendor = WPA_GET_BE24(csuite->vendor); specifier = WPA_GET_BE24(csuite->specifier); wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d", i, vendor, specifier); if (data->vendor == EAP_GPSK_VENDOR_IETF && data->specifier == EAP_GPSK_CIPHER_RESERVED && eap_gpsk_supported_ciphersuite(vendor, specifier)) { data->vendor = vendor; data->specifier = specifier; } csuite++; } if (data->vendor == EAP_GPSK_VENDOR_IETF && data->specifier == EAP_GPSK_CIPHER_RESERVED) { wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported " "ciphersuite found"); eap_gpsk_state(data, FAILURE); return NULL; } wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d", data->vendor, data->specifier); wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2"); miclen = eap_gpsk_mic_len(data->vendor, data->specifier); len = 1 + 2 + data->id_client_len + 2 + data->id_server_len + 2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len + sizeof(struct eap_gpsk_csuite) + 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_2; start = rpos; wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Client", data->id_client, data->id_client_len); WPA_PUT_BE16(rpos, data->id_client_len); rpos += 2; if (data->id_client) os_memcpy(rpos, data->id_client, data->id_client_len); rpos += data->id_client_len; WPA_PUT_BE16(rpos, data->id_server_len); rpos += 2; if (data->id_server) os_memcpy(rpos, data->id_server, data->id_server_len); rpos += data->id_server_len; if (os_get_random(data->rand_client, EAP_GPSK_RAND_LEN)) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data " "for RAND_Client"); eap_gpsk_state(data, FAILURE); os_free(resp); return NULL; } wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Client", data->rand_client, EAP_GPSK_RAND_LEN); os_memcpy(rpos, data->rand_client, EAP_GPSK_RAND_LEN); rpos += EAP_GPSK_RAND_LEN; os_memcpy(rpos, data->rand_server, EAP_GPSK_RAND_LEN); rpos += EAP_GPSK_RAND_LEN; WPA_PUT_BE16(rpos, csuite_list_len); rpos += 2; os_memcpy(rpos, csuite_list, csuite_list_len); rpos += csuite_list_len; csuite = (struct eap_gpsk_csuite *) rpos; WPA_PUT_BE24(csuite->vendor, data->vendor); WPA_PUT_BE24(csuite->specifier, data->specifier); rpos = (u8 *) (csuite + 1); if (eap_gpsk_derive_keys(data->psk, data->psk_len, data->vendor, data->specifier, data->rand_client, data->rand_server, data->id_client, data->id_client_len, data->id_server, data->id_server_len, data->msk, data->emsk, data->sk, &data->sk_len, data->pk, &data->pk_len) < 0) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys"); eap_gpsk_state(data, FAILURE); os_free(resp); return NULL; } /* No PD_Payload_1 */ 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, GPSK_3); return (u8 *) resp; }
static int tls_write_server_finished(struct tlsv1_server *conn, u8 **msgpos, u8 *end) { u8 *pos, *rhdr, *hs_start, *hs_length; size_t rlen, hlen; u8 verify_data[TLS_VERIFY_DATA_LEN]; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; pos = *msgpos; wpa_printf(MSG_DEBUG, "TLSv1: Send Finished"); /* Encrypted Handshake Message: Finished */ hlen = MD5_MAC_LEN; if (conn->verify.md5_server == NULL || crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) { tlsv1_server_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; tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha1_server = NULL; if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, verify_data, TLS_VERIFY_DATA_LEN)) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)", verify_data, TLS_VERIFY_DATA_LEN); rhdr = pos; pos += TLS_RECORD_HEADER_LEN; /* Handshake */ hs_start = pos; /* HandshakeType msg_type */ *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; /* uint24 length (to be filled) */ hs_length = pos; pos += 3; os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN); pos += TLS_VERIFY_DATA_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, &rlen) < 0) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a 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_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[100], *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; #ifdef CONFIG_TLSV12 if (conn->rl.tls_version == TLS_VERSION_1_2) { hlen = SHA256_MAC_LEN; if (conn->verify.sha256_cert == NULL || crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) < 0) { conn->verify.sha256_cert = NULL; tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); return -1; } conn->verify.sha256_cert = NULL; /* * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5 * * DigestInfo ::= SEQUENCE { * digestAlgorithm DigestAlgorithm, * digest OCTET STRING * } * * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11} * * DER encoded DigestInfo for SHA256 per RFC 3447: * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || * H */ os_memmove(hash + 19, hash, hlen); hlen += 19; os_memcpy(hash, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65" "\x03\x04\x02\x01\x05\x00\x04\x20", 19); } else { #endif /* CONFIG_TLSV12 */ 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; #ifdef CONFIG_TLSV12 } #endif /* CONFIG_TLSV12 */ wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen); #ifdef CONFIG_TLSV12 if (conn->rl.tls_version >= TLS_VERSION_1_2) { /* * RFC 5246, 4.7: * TLS v1.2 adds explicit indication of the used signature and * hash algorithms. * * struct { * HashAlgorithm hash; * SignatureAlgorithm signature; * } SignatureAndHashAlgorithm; */ *pos++ = TLS_HASH_ALG_SHA256; *pos++ = TLS_SIGN_ALG_RSA; } #endif /* CONFIG_TLSV12 */ /* * 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, hs_start, 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; }