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