00001
00016 #include "includes.h"
00017
00018 #include "common.h"
00019 #include "eap_defs.h"
00020 #include "aes_wrap.h"
00021 #include "crypto.h"
00022 #ifdef EAP_GPSK_SHA256
00023 #include "sha256.h"
00024 #endif
00025 #include "eap_gpsk_common.h"
00026
00027
00035 int eap_gpsk_supported_ciphersuite(int vendor, int specifier)
00036 {
00037 if (vendor == EAP_GPSK_VENDOR_IETF &&
00038 specifier == EAP_GPSK_CIPHER_AES)
00039 return 1;
00040 #ifdef EAP_GPSK_SHA256
00041 if (vendor == EAP_GPSK_VENDOR_IETF &&
00042 specifier == EAP_GPSK_CIPHER_SHA256)
00043 return 1;
00044 #endif
00045 return 0;
00046 }
00047
00048
00049 static int eap_gpsk_gkdf_cmac(const u8 *psk ,
00050 const u8 *data , size_t data_len,
00051 u8 *buf, size_t len )
00052 {
00053 u8 *opos;
00054 size_t i, n, hashlen, left, clen;
00055 u8 ibuf[2], hash[16];
00056 const u8 *addr[2];
00057 size_t vlen[2];
00058
00059 hashlen = sizeof(hash);
00060
00061 addr[0] = ibuf;
00062 vlen[0] = sizeof(ibuf);
00063 addr[1] = data;
00064 vlen[1] = data_len;
00065
00066 opos = buf;
00067 left = len;
00068 n = (len + hashlen - 1) / hashlen;
00069 for (i = 1; i <= n; i++) {
00070 WPA_PUT_BE16(ibuf, i);
00071 if (omac1_aes_128_vector(psk, 2, addr, vlen, hash))
00072 return -1;
00073 clen = left > hashlen ? hashlen : left;
00074 os_memcpy(opos, hash, clen);
00075 opos += clen;
00076 left -= clen;
00077 }
00078
00079 return 0;
00080 }
00081
00082
00083 #ifdef EAP_GPSK_SHA256
00084 static int eap_gpsk_gkdf_sha256(const u8 *psk ,
00085 const u8 *data , size_t data_len,
00086 u8 *buf, size_t len )
00087 {
00088 u8 *opos;
00089 size_t i, n, hashlen, left, clen;
00090 u8 ibuf[2], hash[SHA256_MAC_LEN];
00091 const u8 *addr[2];
00092 size_t vlen[2];
00093
00094 hashlen = SHA256_MAC_LEN;
00095
00096 addr[0] = ibuf;
00097 vlen[0] = sizeof(ibuf);
00098 addr[1] = data;
00099 vlen[1] = data_len;
00100
00101 opos = buf;
00102 left = len;
00103 n = (len + hashlen - 1) / hashlen;
00104 for (i = 1; i <= n; i++) {
00105 WPA_PUT_BE16(ibuf, i);
00106 hmac_sha256_vector(psk, 32, 2, addr, vlen, hash);
00107 clen = left > hashlen ? hashlen : left;
00108 os_memcpy(opos, hash, clen);
00109 opos += clen;
00110 left -= clen;
00111 }
00112
00113 return 0;
00114 }
00115 #endif
00116
00117
00118 static int eap_gpsk_derive_keys_helper(u32 csuite_specifier,
00119 u8 *kdf_out, size_t kdf_out_len,
00120 const u8 *psk, size_t psk_len,
00121 const u8 *seed, size_t seed_len,
00122 u8 *msk, u8 *emsk,
00123 u8 *sk, size_t sk_len,
00124 u8 *pk, size_t pk_len)
00125 {
00126 u8 mk[32], *pos, *data;
00127 size_t data_len, mk_len;
00128 int (*gkdf)(const u8 *_psk, const u8 *_data, size_t _data_len,
00129 u8 *buf, size_t len);
00130
00131 gkdf = NULL;
00132 switch (csuite_specifier) {
00133 case EAP_GPSK_CIPHER_AES:
00134 gkdf = eap_gpsk_gkdf_cmac;
00135 mk_len = 16;
00136 break;
00137 #ifdef EAP_GPSK_SHA256
00138 case EAP_GPSK_CIPHER_SHA256:
00139 gkdf = eap_gpsk_gkdf_sha256;
00140 mk_len = SHA256_MAC_LEN;
00141 break;
00142 #endif
00143 default:
00144 return -1;
00145 }
00146
00147 if (psk_len < mk_len)
00148 return -1;
00149
00150 data_len = 2 + psk_len + 6 + seed_len;
00151 data = os_malloc(data_len);
00152 if (data == NULL)
00153 return -1;
00154 pos = data;
00155 WPA_PUT_BE16(pos, psk_len);
00156 pos += 2;
00157 os_memcpy(pos, psk, psk_len);
00158 pos += psk_len;
00159 WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF);
00160 pos += 4;
00161 WPA_PUT_BE16(pos, csuite_specifier);
00162 pos += 2;
00163 os_memcpy(pos, seed, seed_len);
00164 wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation",
00165 data, data_len);
00166
00167 if (gkdf(psk, data, data_len, mk, mk_len) < 0) {
00168 os_free(data);
00169 return -1;
00170 }
00171 os_free(data);
00172 wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, mk_len);
00173
00174 if (gkdf(mk, seed, seed_len, kdf_out, kdf_out_len) < 0)
00175 return -1;
00176
00177 pos = kdf_out;
00178 wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN);
00179 os_memcpy(msk, pos, EAP_MSK_LEN);
00180 pos += EAP_MSK_LEN;
00181
00182 wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN);
00183 os_memcpy(emsk, pos, EAP_EMSK_LEN);
00184 pos += EAP_EMSK_LEN;
00185
00186 wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK", pos, sk_len);
00187 os_memcpy(sk, pos, sk_len);
00188 pos += sk_len;
00189
00190 if (pk) {
00191 wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK", pos, pk_len);
00192 os_memcpy(pk, pos, pk_len);
00193 }
00194
00195 return 0;
00196 }
00197
00198
00199 static int eap_gpsk_derive_keys_aes(const u8 *psk, size_t psk_len,
00200 const u8 *seed, size_t seed_len,
00201 u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
00202 u8 *pk, size_t *pk_len)
00203 {
00204 #define EAP_GPSK_SK_LEN_AES 16
00205 #define EAP_GPSK_PK_LEN_AES 16
00206 u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_AES +
00207 EAP_GPSK_PK_LEN_AES];
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223 *sk_len = EAP_GPSK_SK_LEN_AES;
00224 *pk_len = EAP_GPSK_PK_LEN_AES;
00225
00226 return eap_gpsk_derive_keys_helper(EAP_GPSK_CIPHER_AES,
00227 kdf_out, sizeof(kdf_out),
00228 psk, psk_len, seed, seed_len,
00229 msk, emsk, sk, *sk_len,
00230 pk, *pk_len);
00231 }
00232
00233
00234 #ifdef EAP_GPSK_SHA256
00235 static int eap_gpsk_derive_keys_sha256(const u8 *psk, size_t psk_len,
00236 const u8 *seed, size_t seed_len,
00237 u8 *msk, u8 *emsk,
00238 u8 *sk, size_t *sk_len)
00239 {
00240 #define EAP_GPSK_SK_LEN_SHA256 SHA256_MAC_LEN
00241 #define EAP_GPSK_PK_LEN_SHA256 SHA256_MAC_LEN
00242 u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_SHA256 +
00243 EAP_GPSK_PK_LEN_SHA256];
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258 *sk_len = EAP_GPSK_SK_LEN_SHA256;
00259
00260 return eap_gpsk_derive_keys_helper(EAP_GPSK_CIPHER_SHA256,
00261 kdf_out, sizeof(kdf_out),
00262 psk, psk_len, seed, seed_len,
00263 msk, emsk, sk, *sk_len,
00264 NULL, 0);
00265 }
00266 #endif
00267
00268
00290 int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
00291 int specifier,
00292 const u8 *rand_peer, const u8 *rand_server,
00293 const u8 *id_peer, size_t id_peer_len,
00294 const u8 *id_server, size_t id_server_len,
00295 u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
00296 u8 *pk, size_t *pk_len)
00297 {
00298 u8 *seed, *pos;
00299 size_t seed_len;
00300 int ret;
00301
00302 wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)",
00303 vendor, specifier);
00304
00305 if (vendor != EAP_GPSK_VENDOR_IETF)
00306 return -1;
00307
00308 wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
00309
00310
00311 seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len;
00312 seed = os_malloc(seed_len);
00313 if (seed == NULL) {
00314 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
00315 "for key derivation");
00316 return -1;
00317 }
00318
00319 pos = seed;
00320 os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN);
00321 pos += EAP_GPSK_RAND_LEN;
00322 os_memcpy(pos, id_peer, id_peer_len);
00323 pos += id_peer_len;
00324 os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN);
00325 pos += EAP_GPSK_RAND_LEN;
00326 os_memcpy(pos, id_server, id_server_len);
00327 pos += id_server_len;
00328 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len);
00329
00330 switch (specifier) {
00331 case EAP_GPSK_CIPHER_AES:
00332 ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, seed_len,
00333 msk, emsk, sk, sk_len,
00334 pk, pk_len);
00335 break;
00336 #ifdef EAP_GPSK_SHA256
00337 case EAP_GPSK_CIPHER_SHA256:
00338 ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, seed_len,
00339 msk, emsk, sk, sk_len);
00340 break;
00341 #endif
00342 default:
00343 wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in "
00344 "key derivation", vendor, specifier);
00345 ret = -1;
00346 break;
00347 }
00348
00349 os_free(seed);
00350
00351 return ret;
00352 }
00353
00354
00362 size_t eap_gpsk_mic_len(int vendor, int specifier)
00363 {
00364 if (vendor != EAP_GPSK_VENDOR_IETF)
00365 return 0;
00366
00367 switch (specifier) {
00368 case EAP_GPSK_CIPHER_AES:
00369 return 16;
00370 #ifdef EAP_GPSK_SHA256
00371 case EAP_GPSK_CIPHER_SHA256:
00372 return 32;
00373 #endif
00374 default:
00375 return 0;
00376 }
00377 }
00378
00379
00380 static int eap_gpsk_compute_mic_aes(const u8 *sk, size_t sk_len,
00381 const u8 *data, size_t len, u8 *mic)
00382 {
00383 if (sk_len != 16) {
00384 wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid SK length %lu for "
00385 "AES-CMAC MIC", (unsigned long) sk_len);
00386 return -1;
00387 }
00388
00389 return omac1_aes_128(sk, data, len, mic);
00390 }
00391
00392
00405 int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
00406 int specifier, const u8 *data, size_t len, u8 *mic)
00407 {
00408 int ret;
00409
00410 if (vendor != EAP_GPSK_VENDOR_IETF)
00411 return -1;
00412
00413 switch (specifier) {
00414 case EAP_GPSK_CIPHER_AES:
00415 ret = eap_gpsk_compute_mic_aes(sk, sk_len, data, len, mic);
00416 break;
00417 #ifdef EAP_GPSK_SHA256
00418 case EAP_GPSK_CIPHER_SHA256:
00419 hmac_sha256(sk, sk_len, data, len, mic);
00420 ret = 0;
00421 break;
00422 #endif
00423 default:
00424 wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in "
00425 "MIC computation", vendor, specifier);
00426 ret = -1;
00427 break;
00428 }
00429
00430 return ret;
00431 }
00432