static int ikev2_build_kei(struct ikev2_initiator_data *data, struct wpabuf *msg, u8 next_payload) { struct ikev2_payload_hdr *phdr; size_t plen; struct wpabuf *pv; asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: Adding KEi payload"); data->dh = dh_groups_get(data->proposal.dh); pv = dh_init(data->dh, &data->i_dh_private); if (pv == NULL) { asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: Failed to initialize DH"); return -1; } /* KEi - RFC 4306, Sect. 3.4 */ phdr = wpabuf_put(msg, sizeof(*phdr)); phdr->next_payload = next_payload; phdr->flags = 0; wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */ wpabuf_put(msg, 2); /* RESERVED */ /* * RFC 4306, Sect. 3.4: possible zero padding for public value to * match the length of the prime. */ wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv)); wpabuf_put_buf(msg, pv); os_free(pv); plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; WPA_PUT_BE16(phdr->payload_length, plen); return 0; }
int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg) { struct wpabuf *pubkey; wpa_printf(MSG_DEBUG, "WPS: * Public Key"); pubkey = dh_init(dh_groups_get(WPS_DH_GROUP), &wps->dh_privkey); pubkey = wpabuf_zeropad(pubkey, 192); if (pubkey == NULL) { wpa_printf(MSG_DEBUG, "WPS: Failed to initialize " "Diffie-Hellman handshake"); return -1; } wpabuf_put_be16(msg, ATTR_PUBLIC_KEY); wpabuf_put_be16(msg, wpabuf_len(pubkey)); wpabuf_put_buf(msg, pubkey); if (wps->registrar) { wpabuf_free(wps->dh_pubkey_r); wps->dh_pubkey_r = pubkey; } else { wpabuf_free(wps->dh_pubkey_e); wps->dh_pubkey_e = pubkey; } return 0; }
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) { *publ = dh_init(dh_groups_get(5), priv); if (*publ == 0) return NULL; return (void *) 1; }
static const struct dh_group * eap_eke_dh_group(u8 group) { switch (group) { case EAP_EKE_DHGROUP_EKE_2: return dh_groups_get(2); case EAP_EKE_DHGROUP_EKE_5: return dh_groups_get(5); case EAP_EKE_DHGROUP_EKE_14: return dh_groups_get(14); case EAP_EKE_DHGROUP_EKE_15: return dh_groups_get(15); case EAP_EKE_DHGROUP_EKE_16: return dh_groups_get(16); } return NULL; }
static int ikev2_process_sai1(struct ikev2_responder_data *data, const u8 *sai1, size_t sai1_len) { struct ikev2_proposal_data prop; const u8 *pos, *end; int found = 0; /* Security Association Payloads: <Proposals> */ if (sai1 == NULL) { wpa_printf(MSG_INFO, "IKEV2: SAi1 not received"); return -1; } os_memset(&prop, 0, sizeof(prop)); prop.proposal_num = 1; pos = sai1; end = sai1 + sai1_len; while (pos < end) { int plen; prop.integ = -1; prop.prf = -1; prop.encr = -1; prop.dh = -1; plen = ikev2_parse_proposal(&prop, pos, end); if (plen < 0) return -1; if (!found && prop.integ != -1 && prop.prf != -1 && prop.encr != -1 && prop.dh != -1) { os_memcpy(&data->proposal, &prop, sizeof(prop)); data->dh = dh_groups_get(prop.dh); found = 1; } pos += plen; } if (pos != end) { wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposals"); return -1; } if (!found) { wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found"); return -1; } wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d " "INTEG:%d D-H:%d", data->proposal.proposal_num, data->proposal.encr, data->proposal.prf, data->proposal.integ, data->proposal.dh); return 0; }
int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type, char *path, char *method, char *name) { struct wps_context *wps = hapd->wps; struct oob_device_data *oob_dev; oob_dev = wps_get_oob_device(device_type); if (oob_dev == NULL) return -1; oob_dev->device_path = path; oob_dev->device_name = name; wps->oob_conf.oob_method = wps_get_oob_method(method); if (wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) { /* * Use pre-configured DH keys in order to be able to write the * key hash into the OOB file. */ wpabuf_free(wps->dh_pubkey); wpabuf_free(wps->dh_privkey); wps->dh_privkey = NULL; wps->dh_pubkey = dh_init(dh_groups_get(WPS_DH_GROUP), &wps->dh_privkey); wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192); if (wps->dh_pubkey == NULL) { wpa_printf(MSG_ERROR, "WPS: Failed to initialize " "Diffie-Hellman handshake"); return -1; } } if (wps_process_oob(wps, oob_dev, 1) < 0) goto error; if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E || wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) && hostapd_wps_add_pin(hapd, NULL, "any", wpabuf_head(wps->oob_conf.dev_password), 0) < 0) goto error; return 0; error: wpabuf_free(wps->dh_pubkey); wps->dh_pubkey = NULL; wpabuf_free(wps->dh_privkey); wps->dh_privkey = NULL; return -1; }
static int ikev2_parse_transform(struct ikev2_proposal_data *prop, const u8 *pos, const u8 *end) { int transform_len; const struct ikev2_transform *t; u16 transform_id; const u8 *tend; if (end - pos < (int) sizeof(*t)) { wpa_printf(MSG_INFO, "IKEV2: Too short transform"); return -1; } t = (const struct ikev2_transform *) pos; transform_len = WPA_GET_BE16(t->transform_length); if (transform_len < (int) sizeof(*t) || pos + transform_len > end) { wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d", transform_len); return -1; } tend = pos + transform_len; transform_id = WPA_GET_BE16(t->transform_id); wpa_printf(MSG_DEBUG, "IKEV2: Transform:"); wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Transform Length: %d " "Transform Type: %d Transform ID: %d", t->type, transform_len, t->transform_type, transform_id); if (t->type != 0 && t->type != 3) { wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type"); return -1; } pos = (const u8 *) (t + 1); if (pos < tend) { wpa_hexdump(MSG_DEBUG, "IKEV2: Transform Attributes", pos, tend - pos); } switch (t->transform_type) { case IKEV2_TRANSFORM_ENCR: if (ikev2_get_encr(transform_id)) { if (transform_id == ENCR_AES_CBC) { if (tend - pos != 4) { wpa_printf(MSG_DEBUG, "IKEV2: No " "Transform Attr for AES"); break; } #ifdef CCNS_PL if (WPA_GET_BE16(pos) != 0x001d /* ?? */) { wpa_printf(MSG_DEBUG, "IKEV2: Not a " "Key Size attribute for " "AES"); break; } #else /* CCNS_PL */ if (WPA_GET_BE16(pos) != 0x800e) { wpa_printf(MSG_DEBUG, "IKEV2: Not a " "Key Size attribute for " "AES"); break; } #endif /* CCNS_PL */ if (WPA_GET_BE16(pos + 2) != 128) { wpa_printf(MSG_DEBUG, "IKEV2: " "Unsupported AES key size " "%d bits", WPA_GET_BE16(pos + 2)); break; } } prop->encr = transform_id; } break; case IKEV2_TRANSFORM_PRF: if (ikev2_get_prf(transform_id)) prop->prf = transform_id; break; case IKEV2_TRANSFORM_INTEG: if (ikev2_get_integ(transform_id)) prop->integ = transform_id; break; case IKEV2_TRANSFORM_DH: if (dh_groups_get(transform_id)) prop->dh = transform_id; break; } return transform_len; }
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, const struct wpabuf *own_private) { return dh_derive_shared(peer_public, own_private, dh_groups_get(5)); }
int wps_derive_keys(struct wps_data *wps) { struct wpabuf *pubkey, *dh_shared; u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN]; const u8 *addr[3]; size_t len[3]; u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN]; if (wps->dh_privkey == NULL) { wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available"); return -1; } pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r; if (pubkey == NULL) { wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available"); return -1; } dh_shared = dh_derive_shared(pubkey, wps->dh_privkey, dh_groups_get(WPS_DH_GROUP)); dh_shared = wpabuf_zeropad(dh_shared, 192); if (dh_shared == NULL) { wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key"); return -1; } /* Own DH private key is not needed anymore */ wpabuf_free(wps->dh_privkey); wps->dh_privkey = NULL; wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared); /* DHKey = SHA-256(g^AB mod p) */ addr[0] = wpabuf_head(dh_shared); len[0] = wpabuf_len(dh_shared); sha256_vector(1, addr, len, dhkey); wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey)); wpabuf_free(dh_shared); /* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */ addr[0] = wps->nonce_e; len[0] = WPS_NONCE_LEN; addr[1] = wps->mac_addr_e; len[1] = ETH_ALEN; addr[2] = wps->nonce_r; len[2] = WPS_NONCE_LEN; hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk); wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk)); wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation", keys, sizeof(keys)); os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN); os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN); os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN, WPS_EMSK_LEN); wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey", wps->authkey, WPS_AUTHKEY_LEN); wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey", wps->keywrapkey, WPS_KEYWRAPKEY_LEN); wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN); return 0; }