18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP server/peer: EAP-PAX shared routines
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha1.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_pax_common.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_pax_kdf - PAX Key Derivation Function
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @key: Secret key (X)
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @key_len: Length of the secret key in bytes
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @identifier: Public identifier for the key (Y)
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @entropy: Exchanged entropy to seed the KDF (Z)
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @entropy_len: Length of the entropy in bytes
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @output_len: Output len in bytes (W)
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @output: Buffer for the derived key
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 failed
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * RFC 4746, Section 2.6: PAX-KDF-W(X, Y, Z)
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		const char *identifier,
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		const u8 *entropy, size_t entropy_len,
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t output_len, u8 *output)
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 mac[SHA1_MAC_LEN];
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 counter, *pos;
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[3];
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[3];
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t num_blocks, left;
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	num_blocks = (output_len + EAP_PAX_MAC_LEN - 1) / EAP_PAX_MAC_LEN;
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (identifier == NULL || num_blocks >= 255)
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO: add support for EAP_PAX_HMAC_SHA256_128 */
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = (const u8 *) identifier;
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = os_strlen(identifier);
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = entropy;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = entropy_len;
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = &counter;
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = 1;
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = output;
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	left = output_len;
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (counter = 1; counter <= (u8) num_blocks; counter++) {
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t clen = left > EAP_PAX_MAC_LEN ? EAP_PAX_MAC_LEN : left;
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hmac_sha1_vector(key, key_len, 3, addr, len, mac);
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(pos, mac, clen);
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += clen;
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		left -= clen;
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_pax_mac - EAP-PAX MAC
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @key: Secret key
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @key_len: Length of the secret key in bytes
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data1: Optional data, first block; %NULL if not used
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data1_len: Length of data1 in bytes
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data2: Optional data, second block; %NULL if not used
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data2_len: Length of data2 in bytes
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data3: Optional data, third block; %NULL if not used
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data3_len: Length of data3 in bytes
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @mac: Buffer for the MAC value (EAP_PAX_MAC_LEN = 16 bytes)
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Wrapper function to calculate EAP-PAX MAC.
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		const u8 *data1, size_t data1_len,
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		const u8 *data2, size_t data2_len,
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		const u8 *data3, size_t data3_len,
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u8 *mac)
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA1_MAC_LEN];
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[3];
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[3];
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t count;
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO: add support for EAP_PAX_HMAC_SHA256_128 */
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = data1;
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = data1_len;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = data2;
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = data2_len;
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = data3;
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = data3_len;
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	count = (data1 ? 1 : 0) + (data2 ? 1 : 0) + (data3 ? 1 : 0);
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha1_vector(key, key_len, count, addr, len, hash);
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(mac, hash, EAP_PAX_MAC_LEN);
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eap_pax_initial_key_derivation - EAP-PAX initial key derivation
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ak: Authentication Key
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @e: Entropy
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @mk: Buffer for the derived Master Key
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ck: Buffer for the derived Confirmation Key
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ick: Buffer for the derived Integrity Check Key
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   u8 *mk, u8 *ck, u8 *ick)
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-PAX: initial key derivation");
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eap_pax_kdf(mac_id, ak, EAP_PAX_AK_LEN, "Master Key",
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_MK_LEN, mk) ||
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Confirmation Key",
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_CK_LEN, ck) ||
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Integrity Check Key",
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_ICK_LEN, ick))
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: AK", ak, EAP_PAX_AK_LEN);
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: MK", mk, EAP_PAX_MK_LEN);
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: CK", ck, EAP_PAX_CK_LEN);
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: ICK", ick, EAP_PAX_ICK_LEN);
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
145