LCOV - code coverage report
Current view: top level - src/eap_common - eap_sake_common.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1443382998 Lines: 127 183 69.4 %
Date: 2015-09-27 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :  * EAP server/peer: EAP-SAKE shared routines
       3             :  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "includes.h"
      10             : 
      11             : #include "common.h"
      12             : #include "wpabuf.h"
      13             : #include "crypto/sha1.h"
      14             : #include "eap_defs.h"
      15             : #include "eap_sake_common.h"
      16             : 
      17             : 
      18          36 : static int eap_sake_parse_add_attr(struct eap_sake_parse_attr *attr,
      19             :                                    u8 attr_id, u8 len, const u8 *data)
      20             : {
      21             :         size_t i;
      22             : 
      23          36 :         switch (attr_id) {
      24             :         case EAP_SAKE_AT_RAND_S:
      25          10 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_S");
      26          10 :                 if (len != EAP_SAKE_RAND_LEN) {
      27           1 :                         wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_S with "
      28             :                                    "invalid payload length %d", len);
      29           1 :                         return -1;
      30             :                 }
      31           9 :                 attr->rand_s = data;
      32           9 :                 break;
      33             :         case EAP_SAKE_AT_RAND_P:
      34           4 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_P");
      35           4 :                 if (len != EAP_SAKE_RAND_LEN) {
      36           0 :                         wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_P with "
      37             :                                    "invalid payload length %d", len);
      38           0 :                         return -1;
      39             :                 }
      40           4 :                 attr->rand_p = data;
      41           4 :                 break;
      42             :         case EAP_SAKE_AT_MIC_S:
      43           5 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_S");
      44           5 :                 if (len != EAP_SAKE_MIC_LEN) {
      45           1 :                         wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_S with "
      46             :                                    "invalid payload length %d", len);
      47           1 :                         return -1;
      48             :                 }
      49           4 :                 attr->mic_s = data;
      50           4 :                 break;
      51             :         case EAP_SAKE_AT_MIC_P:
      52           7 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_P");
      53           7 :                 if (len != EAP_SAKE_MIC_LEN) {
      54           0 :                         wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_P with "
      55             :                                    "invalid payload length %d", len);
      56           0 :                         return -1;
      57             :                 }
      58           7 :                 attr->mic_p = data;
      59           7 :                 break;
      60             :         case EAP_SAKE_AT_SERVERID:
      61           4 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SERVERID");
      62           4 :                 attr->serverid = data;
      63           4 :                 attr->serverid_len = len;
      64           4 :                 break;
      65             :         case EAP_SAKE_AT_PEERID:
      66           4 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PEERID");
      67           4 :                 attr->peerid = data;
      68           4 :                 attr->peerid_len = len;
      69           4 :                 break;
      70             :         case EAP_SAKE_AT_SPI_S:
      71           0 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_S");
      72           0 :                 attr->spi_s = data;
      73           0 :                 attr->spi_s_len = len;
      74           0 :                 break;
      75             :         case EAP_SAKE_AT_SPI_P:
      76           0 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_P");
      77           0 :                 attr->spi_p = data;
      78           0 :                 attr->spi_p_len = len;
      79           0 :                 break;
      80             :         case EAP_SAKE_AT_ANY_ID_REQ:
      81           2 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ANY_ID_REQ");
      82           2 :                 if (len != 2) {
      83           1 :                         wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid AT_ANY_ID_REQ"
      84             :                                    " payload length %d", len);
      85           1 :                         return -1;
      86             :                 }
      87           1 :                 attr->any_id_req = data;
      88           1 :                 break;
      89             :         case EAP_SAKE_AT_PERM_ID_REQ:
      90           0 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PERM_ID_REQ");
      91           0 :                 if (len != 2) {
      92           0 :                         wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
      93             :                                    "AT_PERM_ID_REQ payload length %d", len);
      94           0 :                         return -1;
      95             :                 }
      96           0 :                 attr->perm_id_req = data;
      97           0 :                 break;
      98             :         case EAP_SAKE_AT_ENCR_DATA:
      99           0 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ENCR_DATA");
     100           0 :                 attr->encr_data = data;
     101           0 :                 attr->encr_data_len = len;
     102           0 :                 break;
     103             :         case EAP_SAKE_AT_IV:
     104           0 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
     105           0 :                 attr->iv = data;
     106           0 :                 attr->iv_len = len;
     107           0 :                 break;
     108             :         case EAP_SAKE_AT_PADDING:
     109           0 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PADDING");
     110           0 :                 for (i = 0; i < len; i++) {
     111           0 :                         if (data[i]) {
     112           0 :                                 wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_PADDING "
     113             :                                            "with non-zero pad byte");
     114           0 :                                 return -1;
     115             :                         }
     116             :                 }
     117           0 :                 break;
     118             :         case EAP_SAKE_AT_NEXT_TMPID:
     119           0 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_NEXT_TMPID");
     120           0 :                 attr->next_tmpid = data;
     121           0 :                 attr->next_tmpid_len = len;
     122           0 :                 break;
     123             :         case EAP_SAKE_AT_MSK_LIFE:
     124           0 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
     125           0 :                 if (len != 4) {
     126           0 :                         wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
     127             :                                    "AT_MSK_LIFE payload length %d", len);
     128           0 :                         return -1;
     129             :                 }
     130           0 :                 attr->msk_life = data;
     131           0 :                 break;
     132             :         default:
     133           0 :                 if (attr_id < 128) {
     134           0 :                         wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown non-skippable"
     135             :                                    " attribute %d", attr_id);
     136           0 :                         return -1;
     137             :                 }
     138           0 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring unknown skippable "
     139             :                            "attribute %d", attr_id);
     140           0 :                 break;
     141             :         }
     142             : 
     143          33 :         if (attr->iv && !attr->encr_data) {
     144           0 :                 wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_IV included without "
     145             :                            "AT_ENCR_DATA");
     146           0 :                 return -1;
     147             :         }
     148             : 
     149          33 :         return 0;
     150             : }
     151             : 
     152             : 
     153             : /**
     154             :  * eap_sake_parse_attributes - Parse EAP-SAKE attributes
     155             :  * @buf: Packet payload (starting with the first attribute)
     156             :  * @len: Payload length
     157             :  * @attr: Structure to be filled with found attributes
     158             :  * Returns: 0 on success or -1 on failure
     159             :  */
     160          28 : int eap_sake_parse_attributes(const u8 *buf, size_t len,
     161             :                               struct eap_sake_parse_attr *attr)
     162             : {
     163          28 :         const u8 *pos = buf, *end = buf + len;
     164             : 
     165          28 :         os_memset(attr, 0, sizeof(*attr));
     166          89 :         while (pos < end) {
     167          37 :                 if (end - pos < 2) {
     168           0 :                         wpa_printf(MSG_DEBUG, "EAP-SAKE: Too short attribute");
     169           0 :                         return -1;
     170             :                 }
     171             : 
     172          37 :                 if (pos[1] < 2) {
     173           0 :                         wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid attribute "
     174           0 :                                    "length (%d)", pos[1]);
     175           0 :                         return -1;
     176             :                 }
     177             : 
     178          37 :                 if (pos + pos[1] > end) {
     179           1 :                         wpa_printf(MSG_DEBUG, "EAP-SAKE: Attribute underflow");
     180           1 :                         return -1;
     181             :                 }
     182             : 
     183          36 :                 if (eap_sake_parse_add_attr(attr, pos[0], pos[1] - 2, pos + 2))
     184           3 :                         return -1;
     185             : 
     186          33 :                 pos += pos[1];
     187             :         }
     188             : 
     189          24 :         return 0;
     190             : }
     191             : 
     192             : 
     193             : /**
     194             :  * eap_sake_kdf - EAP-SAKE Key Derivation Function (KDF)
     195             :  * @key: Key for KDF
     196             :  * @key_len: Length of the key in bytes
     197             :  * @label: A unique label for each purpose of the KDF
     198             :  * @data: Extra data (start) to bind into the key
     199             :  * @data_len: Length of the data
     200             :  * @data2: Extra data (end) to bind into the key
     201             :  * @data2_len: Length of the data2
     202             :  * @buf: Buffer for the generated pseudo-random key
     203             :  * @buf_len: Number of bytes of key to generate
     204             :  *
     205             :  * This function is used to derive new, cryptographically separate keys from a
     206             :  * given key (e.g., SMS). This is identical to the PRF used in IEEE 802.11i.
     207             :  */
     208          78 : static void eap_sake_kdf(const u8 *key, size_t key_len, const char *label,
     209             :                          const u8 *data, size_t data_len,
     210             :                          const u8 *data2, size_t data2_len,
     211             :                          u8 *buf, size_t buf_len)
     212             : {
     213          78 :         u8 counter = 0;
     214             :         size_t pos, plen;
     215             :         u8 hash[SHA1_MAC_LEN];
     216          78 :         size_t label_len = os_strlen(label) + 1;
     217             :         const unsigned char *addr[4];
     218             :         size_t len[4];
     219             : 
     220          78 :         addr[0] = (u8 *) label; /* Label | Y */
     221          78 :         len[0] = label_len;
     222          78 :         addr[1] = data; /* Msg[start] */
     223          78 :         len[1] = data_len;
     224          78 :         addr[2] = data2; /* Msg[end] */
     225          78 :         len[2] = data2_len;
     226          78 :         addr[3] = &counter; /* Length */
     227          78 :         len[3] = 1;
     228             : 
     229          78 :         pos = 0;
     230         247 :         while (pos < buf_len) {
     231         169 :                 plen = buf_len - pos;
     232         169 :                 if (plen >= SHA1_MAC_LEN) {
     233          91 :                         hmac_sha1_vector(key, key_len, 4, addr, len,
     234             :                                          &buf[pos]);
     235          91 :                         pos += SHA1_MAC_LEN;
     236             :                 } else {
     237          78 :                         hmac_sha1_vector(key, key_len, 4, addr, len,
     238             :                                          hash);
     239          78 :                         os_memcpy(&buf[pos], hash, plen);
     240          78 :                         break;
     241             :                 }
     242          91 :                 counter++;
     243             :         }
     244          78 : }
     245             : 
     246             : 
     247             : /**
     248             :  * eap_sake_derive_keys - Derive EAP-SAKE keys
     249             :  * @root_secret_a: 16-byte Root-Secret-A
     250             :  * @root_secret_b: 16-byte Root-Secret-B
     251             :  * @rand_s: 16-byte RAND_S
     252             :  * @rand_p: 16-byte RAND_P
     253             :  * @tek: Buffer for Temporary EAK Keys (TEK-Auth[16] | TEK-Cipher[16])
     254             :  * @msk: Buffer for 64-byte MSK
     255             :  * @emsk: Buffer for 64-byte EMSK
     256             :  *
     257             :  * This function derives EAP-SAKE keys as defined in RFC 4763, section 3.2.6.
     258             :  */
     259          13 : void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
     260             :                           const u8 *rand_s, const u8 *rand_p, u8 *tek, u8 *msk,
     261             :                           u8 *emsk)
     262             : {
     263             :         u8 sms_a[EAP_SAKE_SMS_LEN];
     264             :         u8 sms_b[EAP_SAKE_SMS_LEN];
     265             :         u8 key_buf[EAP_MSK_LEN + EAP_EMSK_LEN];
     266             : 
     267          13 :         wpa_printf(MSG_DEBUG, "EAP-SAKE: Deriving keys");
     268             : 
     269          13 :         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-A",
     270             :                         root_secret_a, EAP_SAKE_ROOT_SECRET_LEN);
     271          13 :         eap_sake_kdf(root_secret_a, EAP_SAKE_ROOT_SECRET_LEN,
     272             :                      "SAKE Master Secret A",
     273             :                      rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
     274             :                      sms_a, EAP_SAKE_SMS_LEN);
     275          13 :         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-A", sms_a, EAP_SAKE_SMS_LEN);
     276          13 :         eap_sake_kdf(sms_a, EAP_SAKE_SMS_LEN, "Transient EAP Key",
     277             :                      rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
     278             :                      tek, EAP_SAKE_TEK_LEN);
     279          13 :         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Auth",
     280             :                         tek, EAP_SAKE_TEK_AUTH_LEN);
     281          13 :         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Cipher",
     282             :                         tek + EAP_SAKE_TEK_AUTH_LEN, EAP_SAKE_TEK_CIPHER_LEN);
     283             : 
     284          13 :         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-B",
     285             :                         root_secret_b, EAP_SAKE_ROOT_SECRET_LEN);
     286          13 :         eap_sake_kdf(root_secret_b, EAP_SAKE_ROOT_SECRET_LEN,
     287             :                      "SAKE Master Secret B",
     288             :                      rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
     289             :                      sms_b, EAP_SAKE_SMS_LEN);
     290          13 :         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-B", sms_b, EAP_SAKE_SMS_LEN);
     291          13 :         eap_sake_kdf(sms_b, EAP_SAKE_SMS_LEN, "Master Session Key",
     292             :                      rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
     293             :                      key_buf, sizeof(key_buf));
     294          13 :         os_memcpy(msk, key_buf, EAP_MSK_LEN);
     295          13 :         os_memcpy(emsk, key_buf + EAP_MSK_LEN, EAP_EMSK_LEN);
     296          13 :         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: MSK", msk, EAP_MSK_LEN);
     297          13 :         wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: EMSK", emsk, EAP_EMSK_LEN);
     298          13 : }
     299             : 
     300             : 
     301             : /**
     302             :  * eap_sake_compute_mic - Compute EAP-SAKE MIC for an EAP packet
     303             :  * @tek_auth: 16-byte TEK-Auth
     304             :  * @rand_s: 16-byte RAND_S
     305             :  * @rand_p: 16-byte RAND_P
     306             :  * @serverid: SERVERID
     307             :  * @serverid_len: SERVERID length
     308             :  * @peerid: PEERID
     309             :  * @peerid_len: PEERID length
     310             :  * @peer: MIC calculation for 0 = Server, 1 = Peer message
     311             :  * @eap: EAP packet
     312             :  * @eap_len: EAP packet length
     313             :  * @mic_pos: MIC position in the EAP packet (must be [eap .. eap + eap_len])
     314             :  * @mic: Buffer for the computed 16-byte MIC
     315             :  */
     316          26 : int eap_sake_compute_mic(const u8 *tek_auth,
     317             :                          const u8 *rand_s, const u8 *rand_p,
     318             :                          const u8 *serverid, size_t serverid_len,
     319             :                          const u8 *peerid, size_t peerid_len,
     320             :                          int peer, const u8 *eap, size_t eap_len,
     321             :                          const u8 *mic_pos, u8 *mic)
     322             : {
     323             :         u8 _rand[2 * EAP_SAKE_RAND_LEN];
     324             :         u8 *tmp, *pos;
     325             :         size_t tmplen;
     326             : 
     327          26 :         tmplen = serverid_len + 1 + peerid_len + 1 + eap_len;
     328          26 :         tmp = os_malloc(tmplen);
     329          26 :         if (tmp == NULL)
     330           0 :                 return -1;
     331          26 :         pos = tmp;
     332          26 :         if (peer) {
     333          19 :                 if (peerid) {
     334          19 :                         os_memcpy(pos, peerid, peerid_len);
     335          19 :                         pos += peerid_len;
     336             :                 }
     337          19 :                 *pos++ = 0x00;
     338          19 :                 if (serverid) {
     339          14 :                         os_memcpy(pos, serverid, serverid_len);
     340          14 :                         pos += serverid_len;
     341             :                 }
     342          19 :                 *pos++ = 0x00;
     343             : 
     344          19 :                 os_memcpy(_rand, rand_s, EAP_SAKE_RAND_LEN);
     345          19 :                 os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_p,
     346             :                           EAP_SAKE_RAND_LEN);
     347             :         } else {
     348           7 :                 if (serverid) {
     349           6 :                         os_memcpy(pos, serverid, serverid_len);
     350           6 :                         pos += serverid_len;
     351             :                 }
     352           7 :                 *pos++ = 0x00;
     353           7 :                 if (peerid) {
     354           7 :                         os_memcpy(pos, peerid, peerid_len);
     355           7 :                         pos += peerid_len;
     356             :                 }
     357           7 :                 *pos++ = 0x00;
     358             : 
     359           7 :                 os_memcpy(_rand, rand_p, EAP_SAKE_RAND_LEN);
     360           7 :                 os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_s,
     361             :                           EAP_SAKE_RAND_LEN);
     362             :         }
     363             : 
     364          26 :         os_memcpy(pos, eap, eap_len);
     365          26 :         os_memset(pos + (mic_pos - eap), 0, EAP_SAKE_MIC_LEN);
     366             : 
     367          26 :         eap_sake_kdf(tek_auth, EAP_SAKE_TEK_AUTH_LEN,
     368             :                      peer ? "Peer MIC" : "Server MIC",
     369             :                      _rand, 2 * EAP_SAKE_RAND_LEN, tmp, tmplen,
     370             :                      mic, EAP_SAKE_MIC_LEN);
     371             : 
     372          26 :         os_free(tmp);
     373             : 
     374          26 :         return 0;
     375             : }
     376             : 
     377             : 
     378          27 : void eap_sake_add_attr(struct wpabuf *buf, u8 type, const u8 *data,
     379             :                        size_t len)
     380             : {
     381          27 :         wpabuf_put_u8(buf, type);
     382          27 :         wpabuf_put_u8(buf, 2 + len); /* Length; including attr header */
     383          27 :         if (data)
     384          27 :                 wpabuf_put_data(buf, data, len);
     385             :         else
     386           0 :                 os_memset(wpabuf_put(buf, len), 0, len);
     387          27 : }

Generated by: LCOV version 1.10