LCOV - code coverage report
Current view: top level - src/eap_server - ikev2.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1393793999 Lines: 434 617 70.3 %
Date: 2014-03-02 Functions: 26 27 96.3 %
Branches: 143 284 50.4 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * IKEv2 initiator (RFC 4306) for EAP-IKEV2
       3                 :            :  * Copyright (c) 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 "crypto/dh_groups.h"
      13                 :            : #include "crypto/random.h"
      14                 :            : #include "ikev2.h"
      15                 :            : 
      16                 :            : 
      17                 :            : static int ikev2_process_idr(struct ikev2_initiator_data *data,
      18                 :            :                              const u8 *idr, size_t idr_len);
      19                 :            : 
      20                 :            : 
      21                 :          4 : void ikev2_initiator_deinit(struct ikev2_initiator_data *data)
      22                 :            : {
      23                 :          4 :         ikev2_free_keys(&data->keys);
      24                 :          4 :         wpabuf_free(data->r_dh_public);
      25                 :          4 :         wpabuf_free(data->i_dh_private);
      26                 :          4 :         os_free(data->IDi);
      27                 :          4 :         os_free(data->IDr);
      28                 :          4 :         os_free(data->shared_secret);
      29                 :          4 :         wpabuf_free(data->i_sign_msg);
      30                 :          4 :         wpabuf_free(data->r_sign_msg);
      31                 :          4 :         os_free(data->key_pad);
      32                 :          4 : }
      33                 :            : 
      34                 :            : 
      35                 :          4 : static int ikev2_derive_keys(struct ikev2_initiator_data *data)
      36                 :            : {
      37                 :            :         u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN];
      38                 :            :         size_t buf_len, pad_len;
      39                 :            :         struct wpabuf *shared;
      40                 :            :         const struct ikev2_integ_alg *integ;
      41                 :            :         const struct ikev2_prf_alg *prf;
      42                 :            :         const struct ikev2_encr_alg *encr;
      43                 :            :         int ret;
      44                 :            :         const u8 *addr[2];
      45                 :            :         size_t len[2];
      46                 :            : 
      47                 :            :         /* RFC 4306, Sect. 2.14 */
      48                 :            : 
      49                 :          4 :         integ = ikev2_get_integ(data->proposal.integ);
      50                 :          4 :         prf = ikev2_get_prf(data->proposal.prf);
      51                 :          4 :         encr = ikev2_get_encr(data->proposal.encr);
      52 [ +  - ][ -  + ]:          4 :         if (integ == NULL || prf == NULL || encr == NULL) {
                 [ +  - ]
      53                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal");
      54                 :          0 :                 return -1;
      55                 :            :         }
      56                 :            : 
      57                 :          4 :         shared = dh_derive_shared(data->r_dh_public, data->i_dh_private,
      58                 :            :                                   data->dh);
      59         [ -  + ]:          4 :         if (shared == NULL)
      60                 :          0 :                 return -1;
      61                 :            : 
      62                 :            :         /* Construct Ni | Nr | SPIi | SPIr */
      63                 :            : 
      64                 :          4 :         buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN;
      65                 :          4 :         buf = os_malloc(buf_len);
      66         [ -  + ]:          4 :         if (buf == NULL) {
      67                 :          0 :                 wpabuf_free(shared);
      68                 :          0 :                 return -1;
      69                 :            :         }
      70                 :            : 
      71                 :          4 :         pos = buf;
      72                 :          4 :         os_memcpy(pos, data->i_nonce, data->i_nonce_len);
      73                 :          4 :         pos += data->i_nonce_len;
      74                 :          4 :         os_memcpy(pos, data->r_nonce, data->r_nonce_len);
      75                 :          4 :         pos += data->r_nonce_len;
      76                 :          4 :         os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN);
      77                 :          4 :         pos += IKEV2_SPI_LEN;
      78                 :          4 :         os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN);
      79                 :            : 
      80                 :            :         /* SKEYSEED = prf(Ni | Nr, g^ir) */
      81                 :            : 
      82                 :            :         /* Use zero-padding per RFC 4306, Sect. 2.14 */
      83                 :          4 :         pad_len = data->dh->prime_len - wpabuf_len(shared);
      84         [ -  + ]:          4 :         pad = os_zalloc(pad_len ? pad_len : 1);
      85         [ -  + ]:          4 :         if (pad == NULL) {
      86                 :          0 :                 wpabuf_free(shared);
      87                 :          0 :                 os_free(buf);
      88                 :          0 :                 return -1;
      89                 :            :         }
      90                 :          4 :         addr[0] = pad;
      91                 :          4 :         len[0] = pad_len;
      92                 :          4 :         addr[1] = wpabuf_head(shared);
      93                 :          4 :         len[1] = wpabuf_len(shared);
      94         [ -  + ]:          4 :         if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len,
      95                 :            :                            2, addr, len, skeyseed) < 0) {
      96                 :          0 :                 wpabuf_free(shared);
      97                 :          0 :                 os_free(buf);
      98                 :          0 :                 os_free(pad);
      99                 :          0 :                 return -1;
     100                 :            :         }
     101                 :          4 :         os_free(pad);
     102                 :          4 :         wpabuf_free(shared);
     103                 :            : 
     104                 :            :         /* DH parameters are not needed anymore, so free them */
     105                 :          4 :         wpabuf_free(data->r_dh_public);
     106                 :          4 :         data->r_dh_public = NULL;
     107                 :          4 :         wpabuf_free(data->i_dh_private);
     108                 :          4 :         data->i_dh_private = NULL;
     109                 :            : 
     110                 :          4 :         wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED",
     111                 :            :                         skeyseed, prf->hash_len);
     112                 :            : 
     113                 :          4 :         ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len,
     114                 :            :                                    &data->keys);
     115                 :          4 :         os_free(buf);
     116                 :          4 :         return ret;
     117                 :            : }
     118                 :            : 
     119                 :            : 
     120                 :         16 : static int ikev2_parse_transform(struct ikev2_initiator_data *data,
     121                 :            :                                  struct ikev2_proposal_data *prop,
     122                 :            :                                  const u8 *pos, const u8 *end)
     123                 :            : {
     124                 :            :         int transform_len;
     125                 :            :         const struct ikev2_transform *t;
     126                 :            :         u16 transform_id;
     127                 :            :         const u8 *tend;
     128                 :            : 
     129         [ -  + ]:         16 :         if (end - pos < (int) sizeof(*t)) {
     130                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Too short transform");
     131                 :          0 :                 return -1;
     132                 :            :         }
     133                 :            : 
     134                 :         16 :         t = (const struct ikev2_transform *) pos;
     135                 :         16 :         transform_len = WPA_GET_BE16(t->transform_length);
     136 [ -  + ][ +  - ]:         16 :         if (transform_len < (int) sizeof(*t) || pos + transform_len > end) {
     137                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d",
     138                 :            :                            transform_len);
     139                 :          0 :                 return -1;
     140                 :            :         }
     141                 :         16 :         tend = pos + transform_len;
     142                 :            : 
     143                 :         16 :         transform_id = WPA_GET_BE16(t->transform_id);
     144                 :            : 
     145                 :         16 :         wpa_printf(MSG_DEBUG, "IKEV2:   Transform:");
     146                 :         16 :         wpa_printf(MSG_DEBUG, "IKEV2:     Type: %d  Transform Length: %d  "
     147                 :            :                    "Transform Type: %d  Transform ID: %d",
     148                 :         32 :                    t->type, transform_len, t->transform_type, transform_id);
     149                 :            : 
     150 [ -  + ][ +  + ]:         16 :         if (t->type != 0 && t->type != 3) {
     151                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type");
     152                 :          0 :                 return -1;
     153                 :            :         }
     154                 :            : 
     155                 :         16 :         pos = (const u8 *) (t + 1);
     156         [ +  + ]:         16 :         if (pos < tend) {
     157                 :          4 :                 wpa_hexdump(MSG_DEBUG, "IKEV2:     Transform Attributes",
     158                 :          4 :                             pos, tend - pos);
     159                 :            :         }
     160                 :            : 
     161   [ +  +  +  +  :         16 :         switch (t->transform_type) {
                      - ]
     162                 :            :         case IKEV2_TRANSFORM_ENCR:
     163 [ +  - ][ +  - ]:          4 :                 if (ikev2_get_encr(transform_id) &&
     164                 :          4 :                     transform_id == data->proposal.encr) {
     165         [ +  - ]:          4 :                         if (transform_id == ENCR_AES_CBC) {
     166         [ -  + ]:          4 :                                 if (tend - pos != 4) {
     167                 :          0 :                                         wpa_printf(MSG_DEBUG, "IKEV2: No "
     168                 :            :                                                    "Transform Attr for AES");
     169                 :          0 :                                         break;
     170                 :            :                                 }
     171         [ -  + ]:          4 :                                 if (WPA_GET_BE16(pos) != 0x800e) {
     172                 :          0 :                                         wpa_printf(MSG_DEBUG, "IKEV2: Not a "
     173                 :            :                                                    "Key Size attribute for "
     174                 :            :                                                    "AES");
     175                 :          0 :                                         break;
     176                 :            :                                 }
     177         [ -  + ]:          4 :                                 if (WPA_GET_BE16(pos + 2) != 128) {
     178                 :          0 :                                         wpa_printf(MSG_DEBUG, "IKEV2: "
     179                 :            :                                                    "Unsupported AES key size "
     180                 :            :                                                    "%d bits",
     181                 :          0 :                                                    WPA_GET_BE16(pos + 2));
     182                 :          0 :                                         break;
     183                 :            :                                 }
     184                 :            :                         }
     185                 :          4 :                         prop->encr = transform_id;
     186                 :            :                 }
     187                 :          4 :                 break;
     188                 :            :         case IKEV2_TRANSFORM_PRF:
     189 [ +  - ][ +  - ]:          4 :                 if (ikev2_get_prf(transform_id) &&
     190                 :          4 :                     transform_id == data->proposal.prf)
     191                 :          4 :                         prop->prf = transform_id;
     192                 :          4 :                 break;
     193                 :            :         case IKEV2_TRANSFORM_INTEG:
     194 [ +  - ][ +  - ]:          4 :                 if (ikev2_get_integ(transform_id) &&
     195                 :          4 :                     transform_id == data->proposal.integ)
     196                 :          4 :                         prop->integ = transform_id;
     197                 :          4 :                 break;
     198                 :            :         case IKEV2_TRANSFORM_DH:
     199 [ +  - ][ +  - ]:          4 :                 if (dh_groups_get(transform_id) &&
     200                 :          4 :                     transform_id == data->proposal.dh)
     201                 :          4 :                         prop->dh = transform_id;
     202                 :          4 :                 break;
     203                 :            :         }
     204                 :            : 
     205                 :         16 :         return transform_len;
     206                 :            : }
     207                 :            : 
     208                 :            : 
     209                 :          4 : static int ikev2_parse_proposal(struct ikev2_initiator_data *data,
     210                 :            :                                 struct ikev2_proposal_data *prop,
     211                 :            :                                 const u8 *pos, const u8 *end)
     212                 :            : {
     213                 :            :         const u8 *pend, *ppos;
     214                 :            :         int proposal_len, i;
     215                 :            :         const struct ikev2_proposal *p;
     216                 :            : 
     217         [ -  + ]:          4 :         if (end - pos < (int) sizeof(*p)) {
     218                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Too short proposal");
     219                 :          0 :                 return -1;
     220                 :            :         }
     221                 :            : 
     222                 :          4 :         p = (const struct ikev2_proposal *) pos;
     223                 :          4 :         proposal_len = WPA_GET_BE16(p->proposal_length);
     224 [ -  + ][ +  - ]:          4 :         if (proposal_len < (int) sizeof(*p) || pos + proposal_len > end) {
     225                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d",
     226                 :            :                            proposal_len);
     227                 :          0 :                 return -1;
     228                 :            :         }
     229                 :          4 :         wpa_printf(MSG_DEBUG, "IKEV2: SAi1 Proposal # %d",
     230                 :          4 :                    p->proposal_num);
     231                 :          4 :         wpa_printf(MSG_DEBUG, "IKEV2:   Type: %d  Proposal Length: %d "
     232                 :            :                    " Protocol ID: %d",
     233                 :          8 :                    p->type, proposal_len, p->protocol_id);
     234                 :          4 :         wpa_printf(MSG_DEBUG, "IKEV2:   SPI Size: %d  Transforms: %d",
     235                 :          8 :                    p->spi_size, p->num_transforms);
     236                 :            : 
     237 [ #  # ][ -  + ]:          4 :         if (p->type != 0 && p->type != 2) {
     238                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal type");
     239                 :          0 :                 return -1;
     240                 :            :         }
     241                 :            : 
     242         [ -  + ]:          4 :         if (p->protocol_id != IKEV2_PROTOCOL_IKE) {
     243                 :          0 :                 wpa_printf(MSG_DEBUG, "IKEV2: Unexpected Protocol ID "
     244                 :            :                            "(only IKE allowed for EAP-IKEv2)");
     245                 :          0 :                 return -1;
     246                 :            :         }
     247                 :            : 
     248         [ -  + ]:          4 :         if (p->proposal_num != prop->proposal_num) {
     249         [ #  # ]:          0 :                 if (p->proposal_num == prop->proposal_num + 1)
     250                 :          0 :                         prop->proposal_num = p->proposal_num;
     251                 :            :                 else {
     252                 :          0 :                         wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal #");
     253                 :          0 :                         return -1;
     254                 :            :                 }
     255                 :            :         }
     256                 :            : 
     257                 :          4 :         ppos = (const u8 *) (p + 1);
     258                 :          4 :         pend = pos + proposal_len;
     259         [ -  + ]:          4 :         if (ppos + p->spi_size > pend) {
     260                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI "
     261                 :            :                            "in proposal");
     262                 :          0 :                 return -1;
     263                 :            :         }
     264         [ -  + ]:          4 :         if (p->spi_size) {
     265                 :          0 :                 wpa_hexdump(MSG_DEBUG, "IKEV2:    SPI",
     266                 :          0 :                             ppos, p->spi_size);
     267                 :          0 :                 ppos += p->spi_size;
     268                 :            :         }
     269                 :            : 
     270                 :            :         /*
     271                 :            :          * For initial IKE_SA negotiation, SPI Size MUST be zero; for
     272                 :            :          * subsequent negotiations, it must be 8 for IKE. We only support
     273                 :            :          * initial case for now.
     274                 :            :          */
     275         [ -  + ]:          4 :         if (p->spi_size != 0) {
     276                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Unexpected SPI Size");
     277                 :          0 :                 return -1;
     278                 :            :         }
     279                 :            : 
     280         [ -  + ]:          4 :         if (p->num_transforms == 0) {
     281                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: At least one transform required");
     282                 :          0 :                 return -1;
     283                 :            :         }
     284                 :            : 
     285         [ +  + ]:         20 :         for (i = 0; i < (int) p->num_transforms; i++) {
     286                 :         16 :                 int tlen = ikev2_parse_transform(data, prop, ppos, pend);
     287         [ -  + ]:         16 :                 if (tlen < 0)
     288                 :          0 :                         return -1;
     289                 :         16 :                 ppos += tlen;
     290                 :            :         }
     291                 :            : 
     292         [ -  + ]:          4 :         if (ppos != pend) {
     293                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Unexpected data after "
     294                 :            :                            "transforms");
     295                 :          0 :                 return -1;
     296                 :            :         }
     297                 :            : 
     298                 :          4 :         return proposal_len;
     299                 :            : }
     300                 :            : 
     301                 :            : 
     302                 :          4 : static int ikev2_process_sar1(struct ikev2_initiator_data *data,
     303                 :            :                               const u8 *sar1, size_t sar1_len)
     304                 :            : {
     305                 :            :         struct ikev2_proposal_data prop;
     306                 :            :         const u8 *pos, *end;
     307                 :          4 :         int found = 0;
     308                 :            : 
     309                 :            :         /* Security Association Payloads: <Proposals> */
     310                 :            : 
     311         [ -  + ]:          4 :         if (sar1 == NULL) {
     312                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: SAr1 not received");
     313                 :          0 :                 return -1;
     314                 :            :         }
     315                 :            : 
     316                 :          4 :         os_memset(&prop, 0, sizeof(prop));
     317                 :          4 :         prop.proposal_num = 1;
     318                 :            : 
     319                 :          4 :         pos = sar1;
     320                 :          4 :         end = sar1 + sar1_len;
     321                 :            : 
     322         [ +  - ]:          4 :         while (pos < end) {
     323                 :            :                 int plen;
     324                 :            : 
     325                 :          4 :                 prop.integ = -1;
     326                 :          4 :                 prop.prf = -1;
     327                 :          4 :                 prop.encr = -1;
     328                 :          4 :                 prop.dh = -1;
     329                 :          4 :                 plen = ikev2_parse_proposal(data, &prop, pos, end);
     330         [ -  + ]:          4 :                 if (plen < 0)
     331                 :          0 :                         return -1;
     332                 :            : 
     333 [ +  - ][ +  - ]:          4 :                 if (!found && prop.integ != -1 && prop.prf != -1 &&
         [ +  - ][ +  - ]
     334         [ +  - ]:          4 :                     prop.encr != -1 && prop.dh != -1) {
     335                 :          4 :                         found = 1;
     336                 :            :                 }
     337                 :            : 
     338                 :          4 :                 pos += plen;
     339                 :            : 
     340                 :            :                 /* Only one proposal expected in SAr */
     341                 :          4 :                 break;
     342                 :            :         }
     343                 :            : 
     344         [ -  + ]:          4 :         if (pos != end) {
     345                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposal");
     346                 :          0 :                 return -1;
     347                 :            :         }
     348                 :            : 
     349         [ -  + ]:          4 :         if (!found) {
     350                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found");
     351                 :          0 :                 return -1;
     352                 :            :         }
     353                 :            : 
     354                 :          4 :         wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d "
     355                 :          4 :                    "INTEG:%d D-H:%d", data->proposal.proposal_num,
     356                 :            :                    data->proposal.encr, data->proposal.prf,
     357                 :            :                    data->proposal.integ, data->proposal.dh);
     358                 :            : 
     359                 :          4 :         return 0;
     360                 :            : }
     361                 :            : 
     362                 :            : 
     363                 :          4 : static int ikev2_process_ker(struct ikev2_initiator_data *data,
     364                 :            :                              const u8 *ker, size_t ker_len)
     365                 :            : {
     366                 :            :         u16 group;
     367                 :            : 
     368                 :            :         /*
     369                 :            :          * Key Exchange Payload:
     370                 :            :          * DH Group # (16 bits)
     371                 :            :          * RESERVED (16 bits)
     372                 :            :          * Key Exchange Data (Diffie-Hellman public value)
     373                 :            :          */
     374                 :            : 
     375         [ -  + ]:          4 :         if (ker == NULL) {
     376                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: KEr not received");
     377                 :          0 :                 return -1;
     378                 :            :         }
     379                 :            : 
     380         [ -  + ]:          4 :         if (ker_len < 4 + 96) {
     381                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Too show Key Exchange Payload");
     382                 :          0 :                 return -1;
     383                 :            :         }
     384                 :            : 
     385                 :          4 :         group = WPA_GET_BE16(ker);
     386                 :          4 :         wpa_printf(MSG_DEBUG, "IKEV2: KEr DH Group #%u", group);
     387                 :            : 
     388         [ -  + ]:          4 :         if (group != data->proposal.dh) {
     389                 :          0 :                 wpa_printf(MSG_DEBUG, "IKEV2: KEr DH Group #%u does not match "
     390                 :            :                            "with the selected proposal (%u)",
     391                 :            :                            group, data->proposal.dh);
     392                 :          0 :                 return -1;
     393                 :            :         }
     394                 :            : 
     395         [ -  + ]:          4 :         if (data->dh == NULL) {
     396                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group");
     397                 :          0 :                 return -1;
     398                 :            :         }
     399                 :            : 
     400                 :            :         /* RFC 4306, Section 3.4:
     401                 :            :          * The length of DH public value MUST be equal to the length of the
     402                 :            :          * prime modulus.
     403                 :            :          */
     404         [ -  + ]:          4 :         if (ker_len - 4 != data->dh->prime_len) {
     405                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length "
     406                 :            :                            "%ld (expected %ld)",
     407                 :          0 :                            (long) (ker_len - 4), (long) data->dh->prime_len);
     408                 :          0 :                 return -1;
     409                 :            :         }
     410                 :            : 
     411                 :          4 :         wpabuf_free(data->r_dh_public);
     412                 :          4 :         data->r_dh_public = wpabuf_alloc_copy(ker + 4, ker_len - 4);
     413         [ -  + ]:          4 :         if (data->r_dh_public == NULL)
     414                 :          0 :                 return -1;
     415                 :            : 
     416                 :          4 :         wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEr Diffie-Hellman Public Value",
     417                 :          4 :                         data->r_dh_public);
     418                 :            :         
     419                 :          4 :         return 0;
     420                 :            : }
     421                 :            : 
     422                 :            : 
     423                 :          4 : static int ikev2_process_nr(struct ikev2_initiator_data *data,
     424                 :            :                             const u8 *nr, size_t nr_len)
     425                 :            : {
     426         [ -  + ]:          4 :         if (nr == NULL) {
     427                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Nr not received");
     428                 :          0 :                 return -1;
     429                 :            :         }
     430                 :            : 
     431 [ +  - ][ -  + ]:          4 :         if (nr_len < IKEV2_NONCE_MIN_LEN || nr_len > IKEV2_NONCE_MAX_LEN) {
     432                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Invalid Nr length %ld",
     433                 :            :                            (long) nr_len);
     434                 :          0 :                 return -1;
     435                 :            :         }
     436                 :            : 
     437                 :          4 :         data->r_nonce_len = nr_len;
     438                 :          4 :         os_memcpy(data->r_nonce, nr, nr_len);
     439                 :          4 :         wpa_hexdump(MSG_MSGDUMP, "IKEV2: Nr",
     440                 :          4 :                     data->r_nonce, data->r_nonce_len);
     441                 :            : 
     442                 :          4 :         return 0;
     443                 :            : }
     444                 :            : 
     445                 :            : 
     446                 :          4 : static int ikev2_process_sa_init_encr(struct ikev2_initiator_data *data,
     447                 :            :                                       const struct ikev2_hdr *hdr,
     448                 :            :                                       const u8 *encrypted,
     449                 :            :                                       size_t encrypted_len, u8 next_payload)
     450                 :            : {
     451                 :            :         u8 *decrypted;
     452                 :            :         size_t decrypted_len;
     453                 :            :         struct ikev2_payloads pl;
     454                 :          4 :         int ret = 0;
     455                 :            : 
     456                 :          4 :         decrypted = ikev2_decrypt_payload(data->proposal.encr,
     457                 :            :                                           data->proposal.integ, &data->keys, 0,
     458                 :            :                                           hdr, encrypted, encrypted_len,
     459                 :            :                                           &decrypted_len);
     460         [ -  + ]:          4 :         if (decrypted == NULL)
     461                 :          0 :                 return -1;
     462                 :            : 
     463                 :          4 :         wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads");
     464                 :            : 
     465         [ -  + ]:          4 :         if (ikev2_parse_payloads(&pl, next_payload, decrypted,
     466                 :            :                                  decrypted + decrypted_len) < 0) {
     467                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted "
     468                 :            :                            "payloads");
     469                 :          0 :                 return -1;
     470                 :            :         }
     471                 :            : 
     472         [ +  - ]:          4 :         if (pl.idr)
     473                 :          4 :                 ret = ikev2_process_idr(data, pl.idr, pl.idr_len);
     474                 :            : 
     475                 :          4 :         os_free(decrypted);
     476                 :            : 
     477                 :          4 :         return ret;
     478                 :            : }
     479                 :            : 
     480                 :            : 
     481                 :          4 : static int ikev2_process_sa_init(struct ikev2_initiator_data *data,
     482                 :            :                                  const struct ikev2_hdr *hdr,
     483                 :            :                                  struct ikev2_payloads *pl)
     484                 :            : {
     485   [ +  -  +  - ]:          8 :         if (ikev2_process_sar1(data, pl->sa, pl->sa_len) < 0 ||
     486         [ -  + ]:          8 :             ikev2_process_ker(data, pl->ke, pl->ke_len) < 0 ||
     487                 :          4 :             ikev2_process_nr(data, pl->nonce, pl->nonce_len) < 0)
     488                 :          0 :                 return -1;
     489                 :            : 
     490                 :          4 :         os_memcpy(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN);
     491                 :            : 
     492         [ -  + ]:          4 :         if (ikev2_derive_keys(data) < 0)
     493                 :          0 :                 return -1;
     494                 :            : 
     495         [ +  - ]:          4 :         if (pl->encrypted) {
     496                 :          4 :                 wpa_printf(MSG_DEBUG, "IKEV2: Encrypted payload in SA_INIT - "
     497                 :            :                            "try to get IDr from it");
     498         [ -  + ]:          4 :                 if (ikev2_process_sa_init_encr(data, hdr, pl->encrypted,
     499                 :            :                                                pl->encrypted_len,
     500                 :          4 :                                                pl->encr_next_payload) < 0) {
     501                 :          0 :                         wpa_printf(MSG_INFO, "IKEV2: Failed to process "
     502                 :            :                                    "encrypted payload");
     503                 :          0 :                         return -1;
     504                 :            :                 }
     505                 :            :         }
     506                 :            : 
     507                 :          4 :         data->state = SA_AUTH;
     508                 :            : 
     509                 :          4 :         return 0;
     510                 :            : }
     511                 :            : 
     512                 :            : 
     513                 :          8 : static int ikev2_process_idr(struct ikev2_initiator_data *data,
     514                 :            :                              const u8 *idr, size_t idr_len)
     515                 :            : {
     516                 :            :         u8 id_type;
     517                 :            : 
     518         [ +  + ]:          8 :         if (idr == NULL) {
     519                 :          1 :                 wpa_printf(MSG_INFO, "IKEV2: No IDr received");
     520                 :          1 :                 return -1;
     521                 :            :         }
     522                 :            : 
     523         [ -  + ]:          7 :         if (idr_len < 4) {
     524                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Too short IDr payload");
     525                 :          0 :                 return -1;
     526                 :            :         }
     527                 :            : 
     528                 :          7 :         id_type = idr[0];
     529                 :          7 :         idr += 4;
     530                 :          7 :         idr_len -= 4;
     531                 :            : 
     532                 :          7 :         wpa_printf(MSG_DEBUG, "IKEV2: IDr ID Type %d", id_type);
     533                 :          7 :         wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDr", idr, idr_len);
     534         [ +  + ]:          7 :         if (data->IDr) {
     535 [ +  - ][ +  - ]:          3 :                 if (id_type != data->IDr_type || idr_len != data->IDr_len ||
                 [ -  + ]
     536                 :          3 :                     os_memcmp(idr, data->IDr, idr_len) != 0) {
     537                 :          0 :                         wpa_printf(MSG_INFO, "IKEV2: IDr differs from the one "
     538                 :            :                                    "received earlier");
     539                 :          0 :                         wpa_printf(MSG_DEBUG, "IKEV2: Previous IDr ID Type %d",
     540                 :            :                                    id_type);
     541                 :          0 :                         wpa_hexdump_ascii(MSG_DEBUG, "Previous IKEV2: IDr",
     542                 :          0 :                                           data->IDr, data->IDr_len);
     543                 :          0 :                         return -1;
     544                 :            :                 }
     545                 :          3 :                 os_free(data->IDr);
     546                 :            :         }
     547                 :          7 :         data->IDr = os_malloc(idr_len);
     548         [ -  + ]:          7 :         if (data->IDr == NULL)
     549                 :          0 :                 return -1;
     550                 :          7 :         os_memcpy(data->IDr, idr, idr_len);
     551                 :          7 :         data->IDr_len = idr_len;
     552                 :          7 :         data->IDr_type = id_type;
     553                 :            : 
     554                 :          8 :         return 0;
     555                 :            : }
     556                 :            : 
     557                 :            : 
     558                 :          3 : static int ikev2_process_cert(struct ikev2_initiator_data *data,
     559                 :            :                               const u8 *cert, size_t cert_len)
     560                 :            : {
     561                 :            :         u8 cert_encoding;
     562                 :            : 
     563         [ +  - ]:          3 :         if (cert == NULL) {
     564         [ -  + ]:          3 :                 if (data->peer_auth == PEER_AUTH_CERT) {
     565                 :          0 :                         wpa_printf(MSG_INFO, "IKEV2: No Certificate received");
     566                 :          0 :                         return -1;
     567                 :            :                 }
     568                 :          3 :                 return 0;
     569                 :            :         }
     570                 :            : 
     571         [ #  # ]:          0 :         if (cert_len < 1) {
     572                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: No Cert Encoding field");
     573                 :          0 :                 return -1;
     574                 :            :         }
     575                 :            : 
     576                 :          0 :         cert_encoding = cert[0];
     577                 :          0 :         cert++;
     578                 :          0 :         cert_len--;
     579                 :            : 
     580                 :          0 :         wpa_printf(MSG_DEBUG, "IKEV2: Cert Encoding %d", cert_encoding);
     581                 :          0 :         wpa_hexdump(MSG_MSGDUMP, "IKEV2: Certificate Data", cert, cert_len);
     582                 :            : 
     583                 :            :         /* TODO: validate certificate */
     584                 :            : 
     585                 :          3 :         return 0;
     586                 :            : }
     587                 :            : 
     588                 :            : 
     589                 :          0 : static int ikev2_process_auth_cert(struct ikev2_initiator_data *data,
     590                 :            :                                    u8 method, const u8 *auth, size_t auth_len)
     591                 :            : {
     592         [ #  # ]:          0 :         if (method != AUTH_RSA_SIGN) {
     593                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
     594                 :            :                            "method %d", method);
     595                 :          0 :                 return -1;
     596                 :            :         }
     597                 :            : 
     598                 :            :         /* TODO: validate AUTH */
     599                 :          0 :         return 0;
     600                 :            : }
     601                 :            : 
     602                 :            : 
     603                 :          3 : static int ikev2_process_auth_secret(struct ikev2_initiator_data *data,
     604                 :            :                                      u8 method, const u8 *auth,
     605                 :            :                                      size_t auth_len)
     606                 :            : {
     607                 :            :         u8 auth_data[IKEV2_MAX_HASH_LEN];
     608                 :            :         const struct ikev2_prf_alg *prf;
     609                 :            : 
     610         [ -  + ]:          3 :         if (method != AUTH_SHARED_KEY_MIC) {
     611                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
     612                 :            :                            "method %d", method);
     613                 :          0 :                 return -1;
     614                 :            :         }
     615                 :            : 
     616                 :            :         /* msg | Ni | prf(SK_pr,IDr') */
     617         [ -  + ]:          3 :         if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg,
     618                 :          6 :                                    data->IDr, data->IDr_len, data->IDr_type,
     619                 :          3 :                                    &data->keys, 0, data->shared_secret,
     620                 :            :                                    data->shared_secret_len,
     621                 :          3 :                                    data->i_nonce, data->i_nonce_len,
     622                 :          3 :                                    data->key_pad, data->key_pad_len,
     623                 :            :                                    auth_data) < 0) {
     624                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
     625                 :          0 :                 return -1;
     626                 :            :         }
     627                 :            : 
     628                 :          3 :         wpabuf_free(data->r_sign_msg);
     629                 :          3 :         data->r_sign_msg = NULL;
     630                 :            : 
     631                 :          3 :         prf = ikev2_get_prf(data->proposal.prf);
     632         [ -  + ]:          3 :         if (prf == NULL)
     633                 :          0 :                 return -1;
     634                 :            : 
     635 [ +  - ][ -  + ]:          3 :         if (auth_len != prf->hash_len ||
     636                 :          3 :             os_memcmp(auth, auth_data, auth_len) != 0) {
     637                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data");
     638                 :          0 :                 wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data",
     639                 :            :                             auth, auth_len);
     640                 :          0 :                 wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data",
     641                 :            :                             auth_data, prf->hash_len);
     642                 :          0 :                 return -1;
     643                 :            :         }
     644                 :            : 
     645                 :          3 :         wpa_printf(MSG_DEBUG, "IKEV2: Peer authenticated successfully "
     646                 :            :                    "using shared keys");
     647                 :            : 
     648                 :          3 :         return 0;
     649                 :            : }
     650                 :            : 
     651                 :            : 
     652                 :          3 : static int ikev2_process_auth(struct ikev2_initiator_data *data,
     653                 :            :                               const u8 *auth, size_t auth_len)
     654                 :            : {
     655                 :            :         u8 auth_method;
     656                 :            : 
     657         [ -  + ]:          3 :         if (auth == NULL) {
     658                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload");
     659                 :          0 :                 return -1;
     660                 :            :         }
     661                 :            : 
     662         [ -  + ]:          3 :         if (auth_len < 4) {
     663                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Too short Authentication "
     664                 :            :                            "Payload");
     665                 :          0 :                 return -1;
     666                 :            :         }
     667                 :            : 
     668                 :          3 :         auth_method = auth[0];
     669                 :          3 :         auth += 4;
     670                 :          3 :         auth_len -= 4;
     671                 :            : 
     672                 :          3 :         wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method);
     673                 :          3 :         wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len);
     674                 :            : 
     675      [ -  +  - ]:          3 :         switch (data->peer_auth) {
     676                 :            :         case PEER_AUTH_CERT:
     677                 :          0 :                 return ikev2_process_auth_cert(data, auth_method, auth,
     678                 :            :                                                auth_len);
     679                 :            :         case PEER_AUTH_SECRET:
     680                 :          3 :                 return ikev2_process_auth_secret(data, auth_method, auth,
     681                 :            :                                                  auth_len);
     682                 :            :         }
     683                 :            : 
     684                 :          3 :         return -1;
     685                 :            : }
     686                 :            : 
     687                 :            : 
     688                 :          4 : static int ikev2_process_sa_auth_decrypted(struct ikev2_initiator_data *data,
     689                 :            :                                            u8 next_payload,
     690                 :            :                                            u8 *payload, size_t payload_len)
     691                 :            : {
     692                 :            :         struct ikev2_payloads pl;
     693                 :            : 
     694                 :          4 :         wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads");
     695                 :            : 
     696         [ -  + ]:          4 :         if (ikev2_parse_payloads(&pl, next_payload, payload, payload +
     697                 :            :                                  payload_len) < 0) {
     698                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted "
     699                 :            :                            "payloads");
     700                 :          0 :                 return -1;
     701                 :            :         }
     702                 :            : 
     703   [ +  +  +  - ]:          7 :         if (ikev2_process_idr(data, pl.idr, pl.idr_len) < 0 ||
     704         [ -  + ]:          6 :             ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 ||
     705                 :          3 :             ikev2_process_auth(data, pl.auth, pl.auth_len) < 0)
     706                 :          1 :                 return -1;
     707                 :            : 
     708                 :          4 :         return 0;
     709                 :            : }
     710                 :            : 
     711                 :            : 
     712                 :          4 : static int ikev2_process_sa_auth(struct ikev2_initiator_data *data,
     713                 :            :                                  const struct ikev2_hdr *hdr,
     714                 :            :                                  struct ikev2_payloads *pl)
     715                 :            : {
     716                 :            :         u8 *decrypted;
     717                 :            :         size_t decrypted_len;
     718                 :            :         int ret;
     719                 :            : 
     720                 :          4 :         decrypted = ikev2_decrypt_payload(data->proposal.encr,
     721                 :            :                                           data->proposal.integ,
     722                 :            :                                           &data->keys, 0, hdr, pl->encrypted,
     723                 :            :                                           pl->encrypted_len, &decrypted_len);
     724         [ -  + ]:          4 :         if (decrypted == NULL)
     725                 :          0 :                 return -1;
     726                 :            : 
     727                 :          4 :         ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload,
     728                 :            :                                               decrypted, decrypted_len);
     729                 :          4 :         os_free(decrypted);
     730                 :            : 
     731 [ +  - ][ +  + ]:          4 :         if (ret == 0 && !data->unknown_user) {
     732                 :          3 :                 wpa_printf(MSG_DEBUG, "IKEV2: Authentication completed");
     733                 :          3 :                 data->state = IKEV2_DONE;
     734                 :            :         }
     735                 :            : 
     736                 :          4 :         return ret;
     737                 :            : }
     738                 :            : 
     739                 :            : 
     740                 :          8 : static int ikev2_validate_rx_state(struct ikev2_initiator_data *data,
     741                 :            :                                    u8 exchange_type, u32 message_id)
     742                 :            : {
     743   [ +  +  -  -  :          8 :         switch (data->state) {
                      - ]
     744                 :            :         case SA_INIT:
     745                 :            :                 /* Expect to receive IKE_SA_INIT: HDR, SAr, KEr, Nr, [CERTREQ],
     746                 :            :                  * [SK{IDr}] */
     747         [ -  + ]:          4 :                 if (exchange_type != IKE_SA_INIT) {
     748                 :          0 :                         wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
     749                 :            :                                    "%u in SA_INIT state", exchange_type);
     750                 :          0 :                         return -1;
     751                 :            :                 }
     752         [ -  + ]:          4 :                 if (message_id != 0) {
     753                 :          0 :                         wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
     754                 :            :                                    "in SA_INIT state", message_id);
     755                 :          0 :                         return -1;
     756                 :            :                 }
     757                 :          4 :                 break;
     758                 :            :         case SA_AUTH:
     759                 :            :                 /* Expect to receive IKE_SA_AUTH:
     760                 :            :                  * HDR, SK {IDr, [CERT,] [CERTREQ,] [NFID,] AUTH}
     761                 :            :                  */
     762         [ -  + ]:          4 :                 if (exchange_type != IKE_SA_AUTH) {
     763                 :          0 :                         wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
     764                 :            :                                    "%u in SA_AUTH state", exchange_type);
     765                 :          0 :                         return -1;
     766                 :            :                 }
     767         [ -  + ]:          4 :                 if (message_id != 1) {
     768                 :          0 :                         wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
     769                 :            :                                    "in SA_AUTH state", message_id);
     770                 :          0 :                         return -1;
     771                 :            :                 }
     772                 :          4 :                 break;
     773                 :            :         case CHILD_SA:
     774         [ #  # ]:          0 :                 if (exchange_type != CREATE_CHILD_SA) {
     775                 :          0 :                         wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
     776                 :            :                                    "%u in CHILD_SA state", exchange_type);
     777                 :          0 :                         return -1;
     778                 :            :                 }
     779         [ #  # ]:          0 :                 if (message_id != 2) {
     780                 :          0 :                         wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
     781                 :            :                                    "in CHILD_SA state", message_id);
     782                 :          0 :                         return -1;
     783                 :            :                 }
     784                 :          0 :                 break;
     785                 :            :         case IKEV2_DONE:
     786                 :          0 :                 return -1;
     787                 :            :         }
     788                 :            : 
     789                 :          8 :         return 0;
     790                 :            : }
     791                 :            : 
     792                 :            : 
     793                 :          8 : int ikev2_initiator_process(struct ikev2_initiator_data *data,
     794                 :            :                             const struct wpabuf *buf)
     795                 :            : {
     796                 :            :         const struct ikev2_hdr *hdr;
     797                 :            :         u32 length, message_id;
     798                 :            :         const u8 *pos, *end;
     799                 :            :         struct ikev2_payloads pl;
     800                 :            : 
     801                 :          8 :         wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)",
     802                 :            :                    (unsigned long) wpabuf_len(buf));
     803                 :            : 
     804         [ -  + ]:          8 :         if (wpabuf_len(buf) < sizeof(*hdr)) {
     805                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR");
     806                 :          0 :                 return -1;
     807                 :            :         }
     808                 :            : 
     809                 :          8 :         hdr = (const struct ikev2_hdr *) wpabuf_head(buf);
     810                 :          8 :         end = wpabuf_head_u8(buf) + wpabuf_len(buf);
     811                 :          8 :         message_id = WPA_GET_BE32(hdr->message_id);
     812                 :          8 :         length = WPA_GET_BE32(hdr->length);
     813                 :            : 
     814                 :          8 :         wpa_hexdump(MSG_DEBUG, "IKEV2:   IKE_SA Initiator's SPI",
     815                 :          8 :                     hdr->i_spi, IKEV2_SPI_LEN);
     816                 :          8 :         wpa_hexdump(MSG_DEBUG, "IKEV2:   IKE_SA Initiator's SPI",
     817                 :          8 :                     hdr->r_spi, IKEV2_SPI_LEN);
     818                 :          8 :         wpa_printf(MSG_DEBUG, "IKEV2:   Next Payload: %u  Version: 0x%x  "
     819                 :            :                    "Exchange Type: %u",
     820                 :         24 :                    hdr->next_payload, hdr->version, hdr->exchange_type);
     821                 :          8 :         wpa_printf(MSG_DEBUG, "IKEV2:   Message ID: %u  Length: %u",
     822                 :            :                    message_id, length);
     823                 :            : 
     824         [ -  + ]:          8 :         if (hdr->version != IKEV2_VERSION) {
     825                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x "
     826                 :          0 :                            "(expected 0x%x)", hdr->version, IKEV2_VERSION);
     827                 :          0 :                 return -1;
     828                 :            :         }
     829                 :            : 
     830         [ -  + ]:          8 :         if (length != wpabuf_len(buf)) {
     831                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != "
     832                 :            :                            "RX: %lu)", (unsigned long) length,
     833                 :            :                            (unsigned long) wpabuf_len(buf));
     834                 :          0 :                 return -1;
     835                 :            :         }
     836                 :            : 
     837         [ -  + ]:          8 :         if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0)
     838                 :          0 :                 return -1;
     839                 :            : 
     840         [ -  + ]:          8 :         if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) !=
     841                 :            :             IKEV2_HDR_RESPONSE) {
     842                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x",
     843                 :          0 :                            hdr->flags);
     844                 :          0 :                 return -1;
     845                 :            :         }
     846                 :            : 
     847         [ +  + ]:          8 :         if (data->state != SA_INIT) {
     848         [ -  + ]:          4 :                 if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) {
     849                 :          0 :                         wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA "
     850                 :            :                                    "Initiator's SPI");
     851                 :          0 :                         return -1;
     852                 :            :                 }
     853         [ -  + ]:          4 :                 if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) {
     854                 :          0 :                         wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA "
     855                 :            :                                    "Responder's SPI");
     856                 :          0 :                         return -1;
     857                 :            :                 }
     858                 :            :         }
     859                 :            : 
     860                 :          8 :         pos = (const u8 *) (hdr + 1);
     861         [ -  + ]:          8 :         if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0)
     862                 :          0 :                 return -1;
     863                 :            : 
     864   [ +  +  -  - ]:          8 :         switch (data->state) {
     865                 :            :         case SA_INIT:
     866         [ -  + ]:          4 :                 if (ikev2_process_sa_init(data, hdr, &pl) < 0)
     867                 :          0 :                         return -1;
     868                 :          4 :                 wpabuf_free(data->r_sign_msg);
     869                 :          4 :                 data->r_sign_msg = wpabuf_dup(buf);
     870                 :          4 :                 break;
     871                 :            :         case SA_AUTH:
     872         [ +  + ]:          4 :                 if (ikev2_process_sa_auth(data, hdr, &pl) < 0)
     873                 :          1 :                         return -1;
     874                 :          3 :                 break;
     875                 :            :         case CHILD_SA:
     876                 :            :         case IKEV2_DONE:
     877                 :          0 :                 break;
     878                 :            :         }
     879                 :            : 
     880                 :          8 :         return 0;
     881                 :            : }
     882                 :            : 
     883                 :            : 
     884                 :          8 : static void ikev2_build_hdr(struct ikev2_initiator_data *data,
     885                 :            :                             struct wpabuf *msg, u8 exchange_type,
     886                 :            :                             u8 next_payload, u32 message_id)
     887                 :            : {
     888                 :            :         struct ikev2_hdr *hdr;
     889                 :            : 
     890                 :          8 :         wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR");
     891                 :            : 
     892                 :            :         /* HDR - RFC 4306, Sect. 3.1 */
     893                 :          8 :         hdr = wpabuf_put(msg, sizeof(*hdr));
     894                 :          8 :         os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN);
     895                 :          8 :         os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN);
     896                 :          8 :         hdr->next_payload = next_payload;
     897                 :          8 :         hdr->version = IKEV2_VERSION;
     898                 :          8 :         hdr->exchange_type = exchange_type;
     899                 :          8 :         hdr->flags = IKEV2_HDR_INITIATOR;
     900                 :          8 :         WPA_PUT_BE32(hdr->message_id, message_id);
     901                 :          8 : }
     902                 :            : 
     903                 :            : 
     904                 :          4 : static int ikev2_build_sai(struct ikev2_initiator_data *data,
     905                 :            :                             struct wpabuf *msg, u8 next_payload)
     906                 :            : {
     907                 :            :         struct ikev2_payload_hdr *phdr;
     908                 :            :         size_t plen;
     909                 :            :         struct ikev2_proposal *p;
     910                 :            :         struct ikev2_transform *t;
     911                 :            : 
     912                 :          4 :         wpa_printf(MSG_DEBUG, "IKEV2: Adding SAi payload");
     913                 :            : 
     914                 :            :         /* SAi1 - RFC 4306, Sect. 2.7 and 3.3 */
     915                 :          4 :         phdr = wpabuf_put(msg, sizeof(*phdr));
     916                 :          4 :         phdr->next_payload = next_payload;
     917                 :          4 :         phdr->flags = 0;
     918                 :            : 
     919                 :            :         /* TODO: support for multiple proposals */
     920                 :          4 :         p = wpabuf_put(msg, sizeof(*p));
     921                 :          4 :         p->proposal_num = data->proposal.proposal_num;
     922                 :          4 :         p->protocol_id = IKEV2_PROTOCOL_IKE;
     923                 :          4 :         p->num_transforms = 4;
     924                 :            : 
     925                 :          4 :         t = wpabuf_put(msg, sizeof(*t));
     926                 :          4 :         t->type = 3;
     927                 :          4 :         t->transform_type = IKEV2_TRANSFORM_ENCR;
     928                 :          4 :         WPA_PUT_BE16(t->transform_id, data->proposal.encr);
     929         [ +  - ]:          4 :         if (data->proposal.encr == ENCR_AES_CBC) {
     930                 :            :                 /* Transform Attribute: Key Len = 128 bits */
     931                 :          4 :                 wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */
     932                 :          4 :                 wpabuf_put_be16(msg, 128); /* 128-bit key */
     933                 :            :         }
     934                 :          4 :         plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t;
     935                 :          4 :         WPA_PUT_BE16(t->transform_length, plen);
     936                 :            : 
     937                 :          4 :         t = wpabuf_put(msg, sizeof(*t));
     938                 :          4 :         t->type = 3;
     939                 :          4 :         WPA_PUT_BE16(t->transform_length, sizeof(*t));
     940                 :          4 :         t->transform_type = IKEV2_TRANSFORM_PRF;
     941                 :          4 :         WPA_PUT_BE16(t->transform_id, data->proposal.prf);
     942                 :            : 
     943                 :          4 :         t = wpabuf_put(msg, sizeof(*t));
     944                 :          4 :         t->type = 3;
     945                 :          4 :         WPA_PUT_BE16(t->transform_length, sizeof(*t));
     946                 :          4 :         t->transform_type = IKEV2_TRANSFORM_INTEG;
     947                 :          4 :         WPA_PUT_BE16(t->transform_id, data->proposal.integ);
     948                 :            : 
     949                 :          4 :         t = wpabuf_put(msg, sizeof(*t));
     950                 :          4 :         WPA_PUT_BE16(t->transform_length, sizeof(*t));
     951                 :          4 :         t->transform_type = IKEV2_TRANSFORM_DH;
     952                 :          4 :         WPA_PUT_BE16(t->transform_id, data->proposal.dh);
     953                 :            : 
     954                 :          4 :         plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p;
     955                 :          4 :         WPA_PUT_BE16(p->proposal_length, plen);
     956                 :            : 
     957                 :          4 :         plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
     958                 :          4 :         WPA_PUT_BE16(phdr->payload_length, plen);
     959                 :            : 
     960                 :          4 :         return 0;
     961                 :            : }
     962                 :            : 
     963                 :            : 
     964                 :          4 : static int ikev2_build_kei(struct ikev2_initiator_data *data,
     965                 :            :                            struct wpabuf *msg, u8 next_payload)
     966                 :            : {
     967                 :            :         struct ikev2_payload_hdr *phdr;
     968                 :            :         size_t plen;
     969                 :            :         struct wpabuf *pv;
     970                 :            : 
     971                 :          4 :         wpa_printf(MSG_DEBUG, "IKEV2: Adding KEi payload");
     972                 :            : 
     973                 :          4 :         data->dh = dh_groups_get(data->proposal.dh);
     974                 :          4 :         pv = dh_init(data->dh, &data->i_dh_private);
     975         [ -  + ]:          4 :         if (pv == NULL) {
     976                 :          0 :                 wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH");
     977                 :          0 :                 return -1;
     978                 :            :         }
     979                 :            : 
     980                 :            :         /* KEi - RFC 4306, Sect. 3.4 */
     981                 :          4 :         phdr = wpabuf_put(msg, sizeof(*phdr));
     982                 :          4 :         phdr->next_payload = next_payload;
     983                 :          4 :         phdr->flags = 0;
     984                 :            : 
     985                 :          4 :         wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */
     986                 :          4 :         wpabuf_put(msg, 2); /* RESERVED */
     987                 :            :         /*
     988                 :            :          * RFC 4306, Sect. 3.4: possible zero padding for public value to
     989                 :            :          * match the length of the prime.
     990                 :            :          */
     991                 :          4 :         wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv));
     992                 :          4 :         wpabuf_put_buf(msg, pv);
     993                 :          4 :         wpabuf_free(pv);
     994                 :            : 
     995                 :          4 :         plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
     996                 :          4 :         WPA_PUT_BE16(phdr->payload_length, plen);
     997                 :          4 :         return 0;
     998                 :            : }
     999                 :            : 
    1000                 :            : 
    1001                 :          4 : static int ikev2_build_ni(struct ikev2_initiator_data *data,
    1002                 :            :                           struct wpabuf *msg, u8 next_payload)
    1003                 :            : {
    1004                 :            :         struct ikev2_payload_hdr *phdr;
    1005                 :            :         size_t plen;
    1006                 :            : 
    1007                 :          4 :         wpa_printf(MSG_DEBUG, "IKEV2: Adding Ni payload");
    1008                 :            : 
    1009                 :            :         /* Ni - RFC 4306, Sect. 3.9 */
    1010                 :          4 :         phdr = wpabuf_put(msg, sizeof(*phdr));
    1011                 :          4 :         phdr->next_payload = next_payload;
    1012                 :          4 :         phdr->flags = 0;
    1013                 :          4 :         wpabuf_put_data(msg, data->i_nonce, data->i_nonce_len);
    1014                 :          4 :         plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
    1015                 :          4 :         WPA_PUT_BE16(phdr->payload_length, plen);
    1016                 :          4 :         return 0;
    1017                 :            : }
    1018                 :            : 
    1019                 :            : 
    1020                 :          4 : static int ikev2_build_idi(struct ikev2_initiator_data *data,
    1021                 :            :                            struct wpabuf *msg, u8 next_payload)
    1022                 :            : {
    1023                 :            :         struct ikev2_payload_hdr *phdr;
    1024                 :            :         size_t plen;
    1025                 :            : 
    1026                 :          4 :         wpa_printf(MSG_DEBUG, "IKEV2: Adding IDi payload");
    1027                 :            : 
    1028         [ -  + ]:          4 :         if (data->IDi == NULL) {
    1029                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: No IDi available");
    1030                 :          0 :                 return -1;
    1031                 :            :         }
    1032                 :            : 
    1033                 :            :         /* IDi - RFC 4306, Sect. 3.5 */
    1034                 :          4 :         phdr = wpabuf_put(msg, sizeof(*phdr));
    1035                 :          4 :         phdr->next_payload = next_payload;
    1036                 :          4 :         phdr->flags = 0;
    1037                 :          4 :         wpabuf_put_u8(msg, ID_KEY_ID);
    1038                 :          4 :         wpabuf_put(msg, 3); /* RESERVED */
    1039                 :          4 :         wpabuf_put_data(msg, data->IDi, data->IDi_len);
    1040                 :          4 :         plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
    1041                 :          4 :         WPA_PUT_BE16(phdr->payload_length, plen);
    1042                 :          4 :         return 0;
    1043                 :            : }
    1044                 :            : 
    1045                 :            : 
    1046                 :          4 : static int ikev2_build_auth(struct ikev2_initiator_data *data,
    1047                 :            :                             struct wpabuf *msg, u8 next_payload)
    1048                 :            : {
    1049                 :            :         struct ikev2_payload_hdr *phdr;
    1050                 :            :         size_t plen;
    1051                 :            :         const struct ikev2_prf_alg *prf;
    1052                 :            : 
    1053                 :          4 :         wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload");
    1054                 :            : 
    1055                 :          4 :         prf = ikev2_get_prf(data->proposal.prf);
    1056         [ -  + ]:          4 :         if (prf == NULL)
    1057                 :          0 :                 return -1;
    1058                 :            : 
    1059                 :            :         /* Authentication - RFC 4306, Sect. 3.8 */
    1060                 :          4 :         phdr = wpabuf_put(msg, sizeof(*phdr));
    1061                 :          4 :         phdr->next_payload = next_payload;
    1062                 :          4 :         phdr->flags = 0;
    1063                 :          4 :         wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC);
    1064                 :          4 :         wpabuf_put(msg, 3); /* RESERVED */
    1065                 :            : 
    1066                 :            :         /* msg | Nr | prf(SK_pi,IDi') */
    1067         [ -  + ]:          4 :         if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg,
    1068                 :          4 :                                    data->IDi, data->IDi_len, ID_KEY_ID,
    1069                 :          4 :                                    &data->keys, 1, data->shared_secret,
    1070                 :            :                                    data->shared_secret_len,
    1071                 :          4 :                                    data->r_nonce, data->r_nonce_len,
    1072                 :          4 :                                    data->key_pad, data->key_pad_len,
    1073                 :          4 :                                    wpabuf_put(msg, prf->hash_len)) < 0) {
    1074                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
    1075                 :          0 :                 return -1;
    1076                 :            :         }
    1077                 :          4 :         wpabuf_free(data->i_sign_msg);
    1078                 :          4 :         data->i_sign_msg = NULL;
    1079                 :            : 
    1080                 :          4 :         plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
    1081                 :          4 :         WPA_PUT_BE16(phdr->payload_length, plen);
    1082                 :          4 :         return 0;
    1083                 :            : }
    1084                 :            : 
    1085                 :            : 
    1086                 :          4 : static struct wpabuf * ikev2_build_sa_init(struct ikev2_initiator_data *data)
    1087                 :            : {
    1088                 :            :         struct wpabuf *msg;
    1089                 :            : 
    1090                 :            :         /* build IKE_SA_INIT: HDR, SAi, KEi, Ni */
    1091                 :            : 
    1092         [ -  + ]:          4 :         if (os_get_random(data->i_spi, IKEV2_SPI_LEN))
    1093                 :          0 :                 return NULL;
    1094                 :          4 :         wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI",
    1095                 :          4 :                     data->i_spi, IKEV2_SPI_LEN);
    1096                 :            : 
    1097                 :          4 :         data->i_nonce_len = IKEV2_NONCE_MIN_LEN;
    1098         [ -  + ]:          4 :         if (random_get_bytes(data->i_nonce, data->i_nonce_len))
    1099                 :          0 :                 return NULL;
    1100                 :          4 :         wpa_hexdump(MSG_DEBUG, "IKEV2: Ni", data->i_nonce, data->i_nonce_len);
    1101                 :            : 
    1102                 :          4 :         msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000);
    1103         [ -  + ]:          4 :         if (msg == NULL)
    1104                 :          0 :                 return NULL;
    1105                 :            : 
    1106                 :          4 :         ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0);
    1107   [ +  -  +  - ]:          8 :         if (ikev2_build_sai(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) ||
    1108         [ -  + ]:          8 :             ikev2_build_kei(data, msg, IKEV2_PAYLOAD_NONCE) ||
    1109                 :          4 :             ikev2_build_ni(data, msg, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) {
    1110                 :          0 :                 wpabuf_free(msg);
    1111                 :          0 :                 return NULL;
    1112                 :            :         }
    1113                 :            : 
    1114                 :          4 :         ikev2_update_hdr(msg);
    1115                 :            : 
    1116                 :          4 :         wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg);
    1117                 :            : 
    1118                 :          4 :         wpabuf_free(data->i_sign_msg);
    1119                 :          4 :         data->i_sign_msg = wpabuf_dup(msg);
    1120                 :            : 
    1121                 :          4 :         return msg;
    1122                 :            : }
    1123                 :            : 
    1124                 :            : 
    1125                 :          4 : static struct wpabuf * ikev2_build_sa_auth(struct ikev2_initiator_data *data)
    1126                 :            : {
    1127                 :            :         struct wpabuf *msg, *plain;
    1128                 :            :         const u8 *secret;
    1129                 :            :         size_t secret_len;
    1130                 :            : 
    1131                 :          4 :         secret = data->get_shared_secret(data->cb_ctx, data->IDr,
    1132                 :            :                                          data->IDr_len, &secret_len);
    1133         [ -  + ]:          4 :         if (secret == NULL) {
    1134                 :          0 :                 wpa_printf(MSG_INFO, "IKEV2: Could not get shared secret - "
    1135                 :            :                            "use fake value");
    1136                 :            :                 /* RFC 5106, Sect. 7:
    1137                 :            :                  * Use a random key to fake AUTH generation in order to prevent
    1138                 :            :                  * probing of user identities.
    1139                 :            :                  */
    1140                 :          0 :                 data->unknown_user = 1;
    1141                 :          0 :                 os_free(data->shared_secret);
    1142                 :          0 :                 data->shared_secret = os_malloc(16);
    1143         [ #  # ]:          0 :                 if (data->shared_secret == NULL)
    1144                 :          0 :                         return NULL;
    1145                 :          0 :                 data->shared_secret_len = 16;
    1146         [ #  # ]:          0 :                 if (random_get_bytes(data->shared_secret, 16))
    1147                 :          0 :                         return NULL;
    1148                 :            :         } else {
    1149                 :          4 :                 os_free(data->shared_secret);
    1150                 :          4 :                 data->shared_secret = os_malloc(secret_len);
    1151         [ -  + ]:          4 :                 if (data->shared_secret == NULL)
    1152                 :          0 :                         return NULL;
    1153                 :          4 :                 os_memcpy(data->shared_secret, secret, secret_len);
    1154                 :          4 :                 data->shared_secret_len = secret_len;
    1155                 :            :         }
    1156                 :            : 
    1157                 :            :         /* build IKE_SA_AUTH: HDR, SK {IDi, [CERT,] [CERTREQ,] AUTH} */
    1158                 :            : 
    1159                 :          4 :         msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000);
    1160         [ -  + ]:          4 :         if (msg == NULL)
    1161                 :          0 :                 return NULL;
    1162                 :          4 :         ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1);
    1163                 :            : 
    1164                 :          4 :         plain = wpabuf_alloc(data->IDr_len + 1000);
    1165         [ -  + ]:          4 :         if (plain == NULL) {
    1166                 :          0 :                 wpabuf_free(msg);
    1167                 :          0 :                 return NULL;
    1168                 :            :         }
    1169                 :            : 
    1170   [ +  -  +  - ]:          8 :         if (ikev2_build_idi(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) ||
    1171         [ -  + ]:          8 :             ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
    1172                 :          4 :             ikev2_build_encrypted(data->proposal.encr, data->proposal.integ,
    1173                 :            :                                   &data->keys, 1, msg, plain,
    1174                 :            :                                   IKEV2_PAYLOAD_IDi)) {
    1175                 :          0 :                 wpabuf_free(plain);
    1176                 :          0 :                 wpabuf_free(msg);
    1177                 :          0 :                 return NULL;
    1178                 :            :         }
    1179                 :          4 :         wpabuf_free(plain);
    1180                 :            : 
    1181                 :          4 :         wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg);
    1182                 :            : 
    1183                 :          4 :         return msg;
    1184                 :            : }
    1185                 :            : 
    1186                 :            : 
    1187                 :          8 : struct wpabuf * ikev2_initiator_build(struct ikev2_initiator_data *data)
    1188                 :            : {
    1189   [ +  +  -  -  :          8 :         switch (data->state) {
                      - ]
    1190                 :            :         case SA_INIT:
    1191                 :          4 :                 return ikev2_build_sa_init(data);
    1192                 :            :         case SA_AUTH:
    1193                 :          4 :                 return ikev2_build_sa_auth(data);
    1194                 :            :         case CHILD_SA:
    1195                 :          0 :                 return NULL;
    1196                 :            :         case IKEV2_DONE:
    1197                 :          0 :                 return NULL;
    1198                 :            :         }
    1199                 :          8 :         return NULL;
    1200                 :            : }

Generated by: LCOV version 1.9