eap_gpsk_common.c

Go to the documentation of this file.
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 /* EAP_GPSK_SHA256 */
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 /* EAP_GPSK_SHA256 */
00045         return 0;
00046 }
00047 
00048 
00049 static int eap_gpsk_gkdf_cmac(const u8 *psk /* Y */,
00050                               const u8 *data /* Z */, size_t data_len,
00051                               u8 *buf, size_t len /* X */)
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         /* M_i = MAC_Y (i || Z); (MAC = AES-CMAC-128) */
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 /* Y */,
00085                                 const u8 *data /* Z */, size_t data_len,
00086                                 u8 *buf, size_t len /* X */)
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         /* M_i = MAC_Y (i || Z); (MAC = HMAC-SHA256) */
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 /* EAP_GPSK_SHA256 */
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 /* EAP_GPSK_SHA256 */
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); /* CSuite/Vendor = IETF */
00160         pos += 4;
00161         WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */
00162         pos += 2;
00163         os_memcpy(pos, seed, seed_len); /* inputString */
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          * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
00211          *            (= seed)
00212          * KS = 16, PL = psk_len, CSuite_Sel = 0x00000000 0x0001
00213          * MK = GKDF-16 (PSK[0..15], PL || PSK || CSuite_Sel || inputString)
00214          * MSK = GKDF-160 (MK, inputString)[0..63]
00215          * EMSK = GKDF-160 (MK, inputString)[64..127]
00216          * SK = GKDF-160 (MK, inputString)[128..143]
00217          * PK = GKDF-160 (MK, inputString)[144..159]
00218          * zero = 0x00 || 0x00 || ... || 0x00 (16 times)
00219          * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
00220          *                      CSuite_Sel || inputString)
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          * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
00247          *            (= seed)
00248          * KS = 32, PL = psk_len, CSuite_Sel = 0x00000000 0x0002
00249          * MK = GKDF-32 (PSK[0..31], PL || PSK || CSuite_Sel || inputString)
00250          * MSK = GKDF-160 (MK, inputString)[0..63]
00251          * EMSK = GKDF-160 (MK, inputString)[64..127]
00252          * SK = GKDF-160 (MK, inputString)[128..159]
00253          * zero = 0x00 || 0x00 || ... || 0x00 (32 times)
00254          * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
00255          *                      CSuite_Sel || inputString)
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 /* EAP_GPSK_SHA256 */
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         /* Seed = RAND_Peer || ID_Peer || RAND_Server || ID_Server */
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 /* EAP_GPSK_SHA256 */
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 /* EAP_GPSK_SHA256 */
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 /* EAP_GPSK_SHA256 */
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 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:51 2009 for hostapd by  doxygen 1.6.1