LCOV - code coverage report
Current view: top level - src/radius - radius.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1393793999 Lines: 515 775 66.5 %
Date: 2014-03-02 Functions: 39 43 90.7 %
Branches: 196 386 50.8 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * RADIUS message processing
       3                 :            :  * Copyright (c) 2002-2009, 2011-2014, 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 "utils/includes.h"
      10                 :            : 
      11                 :            : #include "utils/common.h"
      12                 :            : #include "utils/wpabuf.h"
      13                 :            : #include "crypto/md5.h"
      14                 :            : #include "crypto/crypto.h"
      15                 :            : #include "radius.h"
      16                 :            : 
      17                 :            : 
      18                 :            : /**
      19                 :            :  * struct radius_msg - RADIUS message structure for new and parsed messages
      20                 :            :  */
      21                 :            : struct radius_msg {
      22                 :            :         /**
      23                 :            :          * buf - Allocated buffer for RADIUS message
      24                 :            :          */
      25                 :            :         struct wpabuf *buf;
      26                 :            : 
      27                 :            :         /**
      28                 :            :          * hdr - Pointer to the RADIUS header in buf
      29                 :            :          */
      30                 :            :         struct radius_hdr *hdr;
      31                 :            : 
      32                 :            :         /**
      33                 :            :          * attr_pos - Array of indexes to attributes
      34                 :            :          *
      35                 :            :          * The values are number of bytes from buf to the beginning of
      36                 :            :          * struct radius_attr_hdr.
      37                 :            :          */
      38                 :            :         size_t *attr_pos;
      39                 :            : 
      40                 :            :         /**
      41                 :            :          * attr_size - Total size of the attribute pointer array
      42                 :            :          */
      43                 :            :         size_t attr_size;
      44                 :            : 
      45                 :            :         /**
      46                 :            :          * attr_used - Total number of attributes in the array
      47                 :            :          */
      48                 :            :         size_t attr_used;
      49                 :            : };
      50                 :            : 
      51                 :            : 
      52                 :      10219 : struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg)
      53                 :            : {
      54                 :      10219 :         return msg->hdr;
      55                 :            : }
      56                 :            : 
      57                 :            : 
      58                 :       2134 : struct wpabuf * radius_msg_get_buf(struct radius_msg *msg)
      59                 :            : {
      60                 :       2134 :         return msg->buf;
      61                 :            : }
      62                 :            : 
      63                 :            : 
      64                 :            : static struct radius_attr_hdr *
      65                 :     108892 : radius_get_attr_hdr(struct radius_msg *msg, int idx)
      66                 :            : {
      67                 :     108892 :         return (struct radius_attr_hdr *)
      68                 :     108892 :                 (wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]);
      69                 :            : }
      70                 :            : 
      71                 :            : 
      72                 :       2131 : static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
      73                 :            : {
      74                 :       2131 :         msg->hdr->code = code;
      75                 :       2131 :         msg->hdr->identifier = identifier;
      76                 :       2131 : }
      77                 :            : 
      78                 :            : 
      79                 :       4258 : static int radius_msg_initialize(struct radius_msg *msg)
      80                 :            : {
      81                 :       4258 :         msg->attr_pos = os_calloc(RADIUS_DEFAULT_ATTR_COUNT,
      82                 :            :                                   sizeof(*msg->attr_pos));
      83         [ -  + ]:       4258 :         if (msg->attr_pos == NULL)
      84                 :          0 :                 return -1;
      85                 :            : 
      86                 :       4258 :         msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
      87                 :       4258 :         msg->attr_used = 0;
      88                 :            : 
      89                 :       4258 :         return 0;
      90                 :            : }
      91                 :            : 
      92                 :            : 
      93                 :            : /**
      94                 :            :  * radius_msg_new - Create a new RADIUS message
      95                 :            :  * @code: Code for RADIUS header
      96                 :            :  * @identifier: Identifier for RADIUS header
      97                 :            :  * Returns: Context for RADIUS message or %NULL on failure
      98                 :            :  *
      99                 :            :  * The caller is responsible for freeing the returned data with
     100                 :            :  * radius_msg_free().
     101                 :            :  */
     102                 :       2131 : struct radius_msg * radius_msg_new(u8 code, u8 identifier)
     103                 :            : {
     104                 :            :         struct radius_msg *msg;
     105                 :            : 
     106                 :       2131 :         msg = os_zalloc(sizeof(*msg));
     107         [ -  + ]:       2131 :         if (msg == NULL)
     108                 :          0 :                 return NULL;
     109                 :            : 
     110                 :       2131 :         msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE);
     111 [ -  + ][ +  - ]:       2131 :         if (msg->buf == NULL || radius_msg_initialize(msg)) {
     112                 :          0 :                 radius_msg_free(msg);
     113                 :          0 :                 return NULL;
     114                 :            :         }
     115                 :       2131 :         msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr));
     116                 :            : 
     117                 :       2131 :         radius_msg_set_hdr(msg, code, identifier);
     118                 :            : 
     119                 :       2131 :         return msg;
     120                 :            : }
     121                 :            : 
     122                 :            : 
     123                 :            : /**
     124                 :            :  * radius_msg_free - Free a RADIUS message
     125                 :            :  * @msg: RADIUS message from radius_msg_new() or radius_msg_parse()
     126                 :            :  */
     127                 :       4905 : void radius_msg_free(struct radius_msg *msg)
     128                 :            : {
     129         [ +  + ]:       4905 :         if (msg == NULL)
     130                 :       4905 :                 return;
     131                 :            : 
     132                 :       4258 :         wpabuf_free(msg->buf);
     133                 :       4258 :         os_free(msg->attr_pos);
     134                 :       4258 :         os_free(msg);
     135                 :            : }
     136                 :            : 
     137                 :            : 
     138                 :       2141 : static const char *radius_code_string(u8 code)
     139                 :            : {
     140   [ +  +  +  +  :       2141 :         switch (code) {
          +  +  -  -  -  
          +  +  +  +  -  
                   +  - ]
     141                 :       1049 :         case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request";
     142                 :        170 :         case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept";
     143                 :         21 :         case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject";
     144                 :          8 :         case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request";
     145                 :          8 :         case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response";
     146                 :        858 :         case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge";
     147                 :          0 :         case RADIUS_CODE_STATUS_SERVER: return "Status-Server";
     148                 :          0 :         case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";
     149                 :          0 :         case RADIUS_CODE_RESERVED: return "Reserved";
     150                 :         14 :         case RADIUS_CODE_DISCONNECT_REQUEST: return "Disconnect-Request";
     151                 :          4 :         case RADIUS_CODE_DISCONNECT_ACK: return "Disconnect-ACK";
     152                 :          7 :         case RADIUS_CODE_DISCONNECT_NAK: return "Disconnect-NAK";
     153                 :          1 :         case RADIUS_CODE_COA_REQUEST: return "CoA-Request";
     154                 :          0 :         case RADIUS_CODE_COA_ACK: return "CoA-ACK";
     155                 :          1 :         case RADIUS_CODE_COA_NAK: return "CoA-NAK";
     156                 :       2141 :         default: return "?Unknown?";
     157                 :            :         }
     158                 :            : }
     159                 :            : 
     160                 :            : 
     161                 :            : struct radius_attr_type {
     162                 :            :         u8 type;
     163                 :            :         char *name;
     164                 :            :         enum {
     165                 :            :                 RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
     166                 :            :                 RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6
     167                 :            :         } data_type;
     168                 :            : };
     169                 :            : 
     170                 :            : static struct radius_attr_type radius_attrs[] =
     171                 :            : {
     172                 :            :         { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT },
     173                 :            :         { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST },
     174                 :            :         { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP },
     175                 :            :         { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 },
     176                 :            :         { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 },
     177                 :            :         { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT },
     178                 :            :         { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST },
     179                 :            :         { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST },
     180                 :            :         { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST },
     181                 :            :         { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 },
     182                 :            :         { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 },
     183                 :            :         { RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action",
     184                 :            :           RADIUS_ATTR_INT32 },
     185                 :            :         { RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id",
     186                 :            :           RADIUS_ATTR_TEXT },
     187                 :            :         { RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id",
     188                 :            :           RADIUS_ATTR_TEXT },
     189                 :            :         { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT },
     190                 :            :         { RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST },
     191                 :            :         { RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type",
     192                 :            :           RADIUS_ATTR_INT32 },
     193                 :            :         { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 },
     194                 :            :         { RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets",
     195                 :            :           RADIUS_ATTR_INT32 },
     196                 :            :         { RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets",
     197                 :            :           RADIUS_ATTR_INT32 },
     198                 :            :         { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT },
     199                 :            :         { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 },
     200                 :            :         { RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time",
     201                 :            :           RADIUS_ATTR_INT32 },
     202                 :            :         { RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets",
     203                 :            :           RADIUS_ATTR_INT32 },
     204                 :            :         { RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets",
     205                 :            :           RADIUS_ATTR_INT32 },
     206                 :            :         { RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause",
     207                 :            :           RADIUS_ATTR_INT32 },
     208                 :            :         { RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
     209                 :            :           RADIUS_ATTR_TEXT },
     210                 :            :         { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
     211                 :            :         { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords", 
     212                 :            :           RADIUS_ATTR_INT32 },
     213                 :            :         { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
     214                 :            :           RADIUS_ATTR_INT32 },
     215                 :            :         { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
     216                 :            :           RADIUS_ATTR_INT32 },
     217                 :            :         { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
     218                 :            :         { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
     219                 :            :         { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
     220                 :            :           RADIUS_ATTR_HEXDUMP },
     221                 :            :         { RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password",
     222                 :            :           RADIUS_ATTR_UNDIST },
     223                 :            :         { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
     224                 :            :         { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
     225                 :            :         { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
     226                 :            :           RADIUS_ATTR_UNDIST },
     227                 :            :         { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id",
     228                 :            :           RADIUS_ATTR_HEXDUMP },
     229                 :            :         { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
     230                 :            :           RADIUS_ATTR_INT32 },
     231                 :            :         { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity",
     232                 :            :           RADIUS_ATTR_TEXT },
     233                 :            :         { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
     234                 :            :         { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 }
     235                 :            : };
     236                 :            : #define RADIUS_ATTRS ARRAY_SIZE(radius_attrs)
     237                 :            : 
     238                 :            : 
     239                 :      17106 : static struct radius_attr_type *radius_get_attr_type(u8 type)
     240                 :            : {
     241                 :            :         size_t i;
     242                 :            : 
     243         [ +  - ]:     355324 :         for (i = 0; i < RADIUS_ATTRS; i++) {
     244         [ +  + ]:     355324 :                 if (type == radius_attrs[i].type)
     245                 :      17106 :                         return &radius_attrs[i];
     246                 :            :         }
     247                 :            : 
     248                 :      17106 :         return NULL;
     249                 :            : }
     250                 :            : 
     251                 :            : 
     252                 :      17106 : static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
     253                 :            : {
     254                 :            :         struct radius_attr_type *attr;
     255                 :            :         int len;
     256                 :            :         unsigned char *pos;
     257                 :            :         char buf[1000];
     258                 :            : 
     259                 :      17106 :         attr = radius_get_attr_type(hdr->type);
     260                 :            : 
     261         [ +  - ]:      17106 :         wpa_printf(MSG_INFO, "   Attribute %d (%s) length=%d",
     262                 :      34212 :                    hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
     263                 :            : 
     264 [ -  + ][ +  - ]:      17106 :         if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr))
     265                 :      17106 :                 return;
     266                 :            : 
     267                 :      17106 :         len = hdr->length - sizeof(struct radius_attr_hdr);
     268                 :      17106 :         pos = (unsigned char *) (hdr + 1);
     269                 :            : 
     270   [ +  +  +  +  :      17106 :         switch (attr->data_type) {
                   +  - ]
     271                 :            :         case RADIUS_ATTR_TEXT:
     272                 :       5900 :                 printf_encode(buf, sizeof(buf), pos, len);
     273                 :       5900 :                 wpa_printf(MSG_INFO, "      Value: '%s'", buf);
     274                 :       5900 :                 break;
     275                 :            : 
     276                 :            :         case RADIUS_ATTR_IP:
     277         [ +  - ]:         18 :                 if (len == 4) {
     278                 :            :                         struct in_addr addr;
     279                 :         18 :                         os_memcpy(&addr, pos, 4);
     280                 :         18 :                         wpa_printf(MSG_INFO, "      Value: %s",
     281                 :            :                                    inet_ntoa(addr));
     282                 :            :                 } else {
     283                 :          0 :                         wpa_printf(MSG_INFO, "      Invalid IP address length %d",
     284                 :            :                                    len);
     285                 :            :                 }
     286                 :         18 :                 break;
     287                 :            : 
     288                 :            : #ifdef CONFIG_IPV6
     289                 :            :         case RADIUS_ATTR_IPV6:
     290         [ +  - ]:          7 :                 if (len == 16) {
     291                 :            :                         const char *atxt;
     292                 :          7 :                         struct in6_addr *addr = (struct in6_addr *) pos;
     293                 :          7 :                         atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
     294         [ +  - ]:          7 :                         wpa_printf(MSG_INFO, "      Value: %s",
     295                 :            :                                    atxt ? atxt : "?");
     296                 :            :                 } else {
     297                 :          0 :                         wpa_printf(MSG_INFO, "      Invalid IPv6 address length %d",
     298                 :            :                                    len);
     299                 :            :                 }
     300                 :          7 :                 break;
     301                 :            : #endif /* CONFIG_IPV6 */
     302                 :            : 
     303                 :            :         case RADIUS_ATTR_HEXDUMP:
     304                 :            :         case RADIUS_ATTR_UNDIST:
     305                 :       7954 :                 wpa_snprintf_hex(buf, sizeof(buf), pos, len);
     306                 :       7954 :                 wpa_printf(MSG_INFO, "      Value: %s", buf);
     307                 :       7954 :                 break;
     308                 :            : 
     309                 :            :         case RADIUS_ATTR_INT32:
     310         [ +  - ]:       3227 :                 if (len == 4)
     311                 :       3227 :                         wpa_printf(MSG_INFO, "      Value: %u",
     312                 :            :                                    WPA_GET_BE32(pos));
     313                 :            :                 else
     314                 :          0 :                         wpa_printf(MSG_INFO, "      Invalid INT32 length %d",
     315                 :            :                                    len);
     316                 :       3227 :                 break;
     317                 :            : 
     318                 :            :         default:
     319                 :          0 :                 break;
     320                 :            :         }
     321                 :            : }
     322                 :            : 
     323                 :            : 
     324                 :       2141 : void radius_msg_dump(struct radius_msg *msg)
     325                 :            : {
     326                 :            :         size_t i;
     327                 :            : 
     328                 :       2141 :         wpa_printf(MSG_INFO, "RADIUS message: code=%d (%s) identifier=%d length=%d",
     329                 :       4282 :                    msg->hdr->code, radius_code_string(msg->hdr->code),
     330                 :       4282 :                    msg->hdr->identifier, be_to_host16(msg->hdr->length));
     331                 :            : 
     332         [ +  + ]:      19247 :         for (i = 0; i < msg->attr_used; i++) {
     333                 :      17106 :                 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
     334                 :      17106 :                 radius_msg_dump_attr(attr);
     335                 :            :         }
     336                 :       2141 : }
     337                 :            : 
     338                 :            : 
     339                 :       1050 : int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
     340                 :            :                       size_t secret_len)
     341                 :            : {
     342         [ +  - ]:       1050 :         if (secret) {
     343                 :            :                 u8 auth[MD5_MAC_LEN];
     344                 :            :                 struct radius_attr_hdr *attr;
     345                 :            : 
     346                 :       1050 :                 os_memset(auth, 0, MD5_MAC_LEN);
     347                 :       1050 :                 attr = radius_msg_add_attr(msg,
     348                 :            :                                            RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
     349                 :            :                                            auth, MD5_MAC_LEN);
     350         [ -  + ]:       1050 :                 if (attr == NULL) {
     351                 :          0 :                         wpa_printf(MSG_WARNING, "RADIUS: Could not add "
     352                 :            :                                    "Message-Authenticator");
     353                 :          0 :                         return -1;
     354                 :            :                 }
     355                 :       1050 :                 msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
     356                 :       1050 :                 hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
     357                 :       1050 :                          wpabuf_len(msg->buf), (u8 *) (attr + 1));
     358                 :            :         } else
     359                 :          0 :                 msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
     360                 :            : 
     361         [ -  + ]:       1050 :         if (wpabuf_len(msg->buf) > 0xffff) {
     362                 :          0 :                 wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
     363                 :          0 :                            (unsigned long) wpabuf_len(msg->buf));
     364                 :          0 :                 return -1;
     365                 :            :         }
     366                 :       1050 :         return 0;
     367                 :            : }
     368                 :            : 
     369                 :            : 
     370                 :       1049 : int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
     371                 :            :                           size_t secret_len, const u8 *req_authenticator)
     372                 :            : {
     373                 :            :         u8 auth[MD5_MAC_LEN];
     374                 :            :         struct radius_attr_hdr *attr;
     375                 :            :         const u8 *addr[4];
     376                 :            :         size_t len[4];
     377                 :            : 
     378                 :       1049 :         os_memset(auth, 0, MD5_MAC_LEN);
     379                 :       1049 :         attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
     380                 :            :                                    auth, MD5_MAC_LEN);
     381         [ -  + ]:       1049 :         if (attr == NULL) {
     382                 :          0 :                 wpa_printf(MSG_ERROR, "WARNING: Could not add Message-Authenticator");
     383                 :          0 :                 return -1;
     384                 :            :         }
     385                 :       1049 :         msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
     386                 :       1049 :         os_memcpy(msg->hdr->authenticator, req_authenticator,
     387                 :            :                   sizeof(msg->hdr->authenticator));
     388                 :       1049 :         hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
     389                 :       1049 :                  wpabuf_len(msg->buf), (u8 *) (attr + 1));
     390                 :            : 
     391                 :            :         /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
     392                 :       1049 :         addr[0] = (u8 *) msg->hdr;
     393                 :       1049 :         len[0] = 1 + 1 + 2;
     394                 :       1049 :         addr[1] = req_authenticator;
     395                 :       1049 :         len[1] = MD5_MAC_LEN;
     396                 :       1049 :         addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
     397                 :       1049 :         len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
     398                 :       1049 :         addr[3] = secret;
     399                 :       1049 :         len[3] = secret_len;
     400                 :       1049 :         md5_vector(4, addr, len, msg->hdr->authenticator);
     401                 :            : 
     402         [ -  + ]:       1049 :         if (wpabuf_len(msg->buf) > 0xffff) {
     403                 :          0 :                 wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
     404                 :          0 :                            (unsigned long) wpabuf_len(msg->buf));
     405                 :          0 :                 return -1;
     406                 :            :         }
     407                 :       1049 :         return 0;
     408                 :            : }
     409                 :            : 
     410                 :            : 
     411                 :         12 : int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
     412                 :            :                                size_t secret_len,
     413                 :            :                                const struct radius_hdr *req_hdr)
     414                 :            : {
     415                 :            :         const u8 *addr[2];
     416                 :            :         size_t len[2];
     417                 :            :         u8 auth[MD5_MAC_LEN];
     418                 :            :         struct radius_attr_hdr *attr;
     419                 :            : 
     420                 :         12 :         os_memset(auth, 0, MD5_MAC_LEN);
     421                 :         12 :         attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
     422                 :            :                                    auth, MD5_MAC_LEN);
     423         [ -  + ]:         12 :         if (attr == NULL) {
     424                 :          0 :                 wpa_printf(MSG_WARNING, "Could not add Message-Authenticator");
     425                 :          0 :                 return -1;
     426                 :            :         }
     427                 :            : 
     428                 :         12 :         msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
     429                 :         12 :         os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16);
     430                 :         12 :         hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
     431                 :         12 :                  wpabuf_len(msg->buf), (u8 *) (attr + 1));
     432                 :            : 
     433                 :            :         /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
     434                 :         12 :         addr[0] = wpabuf_head_u8(msg->buf);
     435                 :         12 :         len[0] = wpabuf_len(msg->buf);
     436                 :         12 :         addr[1] = secret;
     437                 :         12 :         len[1] = secret_len;
     438         [ -  + ]:         12 :         if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0)
     439                 :          0 :                 return -1;
     440                 :            : 
     441         [ -  + ]:         12 :         if (wpabuf_len(msg->buf) > 0xffff) {
     442                 :          0 :                 wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
     443                 :          0 :                            (unsigned long) wpabuf_len(msg->buf));
     444                 :          0 :                 return -1;
     445                 :            :         }
     446                 :         12 :         return 0;
     447                 :            : }
     448                 :            : 
     449                 :            : 
     450                 :         12 : void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
     451                 :            :                             size_t secret_len)
     452                 :            : {
     453                 :            :         const u8 *addr[2];
     454                 :            :         size_t len[2];
     455                 :            : 
     456                 :         12 :         msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
     457                 :         12 :         os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
     458                 :         12 :         addr[0] = wpabuf_head(msg->buf);
     459                 :         12 :         len[0] = wpabuf_len(msg->buf);
     460                 :         12 :         addr[1] = secret;
     461                 :         12 :         len[1] = secret_len;
     462                 :         12 :         md5_vector(2, addr, len, msg->hdr->authenticator);
     463                 :            : 
     464         [ -  + ]:         12 :         if (wpabuf_len(msg->buf) > 0xffff) {
     465                 :          0 :                 wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
     466                 :          0 :                            (unsigned long) wpabuf_len(msg->buf));
     467                 :            :         }
     468                 :         12 : }
     469                 :            : 
     470                 :            : 
     471                 :          8 : void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
     472                 :            :                                  size_t secret_len, const u8 *req_authenticator)
     473                 :            : {
     474                 :            :         const u8 *addr[2];
     475                 :            :         size_t len[2];
     476                 :            : 
     477                 :          8 :         msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
     478                 :          8 :         os_memcpy(msg->hdr->authenticator, req_authenticator, MD5_MAC_LEN);
     479                 :          8 :         addr[0] = wpabuf_head(msg->buf);
     480                 :          8 :         len[0] = wpabuf_len(msg->buf);
     481                 :          8 :         addr[1] = secret;
     482                 :          8 :         len[1] = secret_len;
     483                 :          8 :         md5_vector(2, addr, len, msg->hdr->authenticator);
     484                 :            : 
     485         [ -  + ]:          8 :         if (wpabuf_len(msg->buf) > 0xffff) {
     486                 :          0 :                 wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
     487                 :          0 :                            (unsigned long) wpabuf_len(msg->buf));
     488                 :            :         }
     489                 :          8 : }
     490                 :            : 
     491                 :            : 
     492                 :          8 : int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
     493                 :            :                                size_t secret_len)
     494                 :            : {
     495                 :            :         const u8 *addr[4];
     496                 :            :         size_t len[4];
     497                 :            :         u8 zero[MD5_MAC_LEN];
     498                 :            :         u8 hash[MD5_MAC_LEN];
     499                 :            : 
     500                 :          8 :         os_memset(zero, 0, sizeof(zero));
     501                 :          8 :         addr[0] = (u8 *) msg->hdr;
     502                 :          8 :         len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
     503                 :          8 :         addr[1] = zero;
     504                 :          8 :         len[1] = MD5_MAC_LEN;
     505                 :          8 :         addr[2] = (u8 *) (msg->hdr + 1);
     506                 :          8 :         len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
     507                 :          8 :         addr[3] = secret;
     508                 :          8 :         len[3] = secret_len;
     509                 :          8 :         md5_vector(4, addr, len, hash);
     510                 :          8 :         return os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0;
     511                 :            : }
     512                 :            : 
     513                 :            : 
     514                 :         15 : int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
     515                 :            :                               size_t secret_len)
     516                 :            : {
     517                 :            :         const u8 *addr[4];
     518                 :            :         size_t len[4];
     519                 :            :         u8 zero[MD5_MAC_LEN];
     520                 :            :         u8 hash[MD5_MAC_LEN];
     521                 :            :         u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
     522                 :            :         u8 orig_authenticator[16];
     523                 :            : 
     524                 :         15 :         struct radius_attr_hdr *attr = NULL, *tmp;
     525                 :            :         size_t i;
     526                 :            : 
     527                 :         15 :         os_memset(zero, 0, sizeof(zero));
     528                 :         15 :         addr[0] = (u8 *) msg->hdr;
     529                 :         15 :         len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
     530                 :         15 :         addr[1] = zero;
     531                 :         15 :         len[1] = MD5_MAC_LEN;
     532                 :         15 :         addr[2] = (u8 *) (msg->hdr + 1);
     533                 :         15 :         len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
     534                 :         15 :         addr[3] = secret;
     535                 :         15 :         len[3] = secret_len;
     536                 :         15 :         md5_vector(4, addr, len, hash);
     537         [ +  + ]:         15 :         if (os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0)
     538                 :          1 :                 return 1;
     539                 :            : 
     540         [ +  + ]:         50 :         for (i = 0; i < msg->attr_used; i++) {
     541                 :         36 :                 tmp = radius_get_attr_hdr(msg, i);
     542         [ -  + ]:         36 :                 if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
     543         [ #  # ]:          0 :                         if (attr != NULL) {
     544                 :          0 :                                 wpa_printf(MSG_WARNING, "Multiple "
     545                 :            :                                            "Message-Authenticator attributes "
     546                 :            :                                            "in RADIUS message");
     547                 :          0 :                                 return 1;
     548                 :            :                         }
     549                 :          0 :                         attr = tmp;
     550                 :            :                 }
     551                 :            :         }
     552                 :            : 
     553         [ +  - ]:         14 :         if (attr == NULL) {
     554                 :            :                 /* Message-Authenticator is MAY; not required */
     555                 :         14 :                 return 0;
     556                 :            :         }
     557                 :            : 
     558                 :          0 :         os_memcpy(orig, attr + 1, MD5_MAC_LEN);
     559                 :          0 :         os_memset(attr + 1, 0, MD5_MAC_LEN);
     560                 :          0 :         os_memcpy(orig_authenticator, msg->hdr->authenticator,
     561                 :            :                   sizeof(orig_authenticator));
     562                 :          0 :         os_memset(msg->hdr->authenticator, 0,
     563                 :            :                   sizeof(msg->hdr->authenticator));
     564                 :          0 :         hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
     565                 :          0 :                  wpabuf_len(msg->buf), auth);
     566                 :          0 :         os_memcpy(attr + 1, orig, MD5_MAC_LEN);
     567                 :          0 :         os_memcpy(msg->hdr->authenticator, orig_authenticator,
     568                 :            :                   sizeof(orig_authenticator));
     569                 :            : 
     570                 :         15 :         return os_memcmp(orig, auth, MD5_MAC_LEN) != 0;
     571                 :            : }
     572                 :            : 
     573                 :            : 
     574                 :      34193 : static int radius_msg_add_attr_to_array(struct radius_msg *msg,
     575                 :            :                                         struct radius_attr_hdr *attr)
     576                 :            : {
     577         [ +  + ]:      34193 :         if (msg->attr_used >= msg->attr_size) {
     578                 :            :                 size_t *nattr_pos;
     579                 :         21 :                 int nlen = msg->attr_size * 2;
     580                 :            : 
     581                 :         21 :                 nattr_pos = os_realloc_array(msg->attr_pos, nlen,
     582                 :            :                                              sizeof(*msg->attr_pos));
     583         [ -  + ]:         21 :                 if (nattr_pos == NULL)
     584                 :          0 :                         return -1;
     585                 :            : 
     586                 :         21 :                 msg->attr_pos = nattr_pos;
     587                 :         21 :                 msg->attr_size = nlen;
     588                 :            :         }
     589                 :            : 
     590                 :      68386 :         msg->attr_pos[msg->attr_used++] =
     591                 :      34193 :                 (unsigned char *) attr - wpabuf_head_u8(msg->buf);
     592                 :            : 
     593                 :      34193 :         return 0;
     594                 :            : }
     595                 :            : 
     596                 :            : 
     597                 :      17119 : struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
     598                 :            :                                             const u8 *data, size_t data_len)
     599                 :            : {
     600                 :            :         size_t buf_needed;
     601                 :            :         struct radius_attr_hdr *attr;
     602                 :            : 
     603         [ -  + ]:      17119 :         if (data_len > RADIUS_MAX_ATTR_LEN) {
     604                 :          0 :                 wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)",
     605                 :            :                        (unsigned long) data_len);
     606                 :          0 :                 return NULL;
     607                 :            :         }
     608                 :            : 
     609                 :      17119 :         buf_needed = sizeof(*attr) + data_len;
     610                 :            : 
     611         [ +  + ]:      17119 :         if (wpabuf_tailroom(msg->buf) < buf_needed) {
     612                 :            :                 /* allocate more space for message buffer */
     613         [ -  + ]:        518 :                 if (wpabuf_resize(&msg->buf, buf_needed) < 0)
     614                 :          0 :                         return NULL;
     615                 :        518 :                 msg->hdr = wpabuf_mhead(msg->buf);
     616                 :            :         }
     617                 :            : 
     618                 :      17119 :         attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
     619                 :      17119 :         attr->type = type;
     620                 :      17119 :         attr->length = sizeof(*attr) + data_len;
     621                 :      17119 :         wpabuf_put_data(msg->buf, data, data_len);
     622                 :            : 
     623         [ -  + ]:      17119 :         if (radius_msg_add_attr_to_array(msg, attr))
     624                 :          0 :                 return NULL;
     625                 :            : 
     626                 :      17119 :         return attr;
     627                 :            : }
     628                 :            : 
     629                 :            : 
     630                 :            : /**
     631                 :            :  * radius_msg_parse - Parse a RADIUS message
     632                 :            :  * @data: RADIUS message to be parsed
     633                 :            :  * @len: Length of data buffer in octets
     634                 :            :  * Returns: Parsed RADIUS message or %NULL on failure
     635                 :            :  *
     636                 :            :  * This parses a RADIUS message and makes a copy of its data. The caller is
     637                 :            :  * responsible for freeing the returned data with radius_msg_free().
     638                 :            :  */
     639                 :       2127 : struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
     640                 :            : {
     641                 :            :         struct radius_msg *msg;
     642                 :            :         struct radius_hdr *hdr;
     643                 :            :         struct radius_attr_hdr *attr;
     644                 :            :         size_t msg_len;
     645                 :            :         unsigned char *pos, *end;
     646                 :            : 
     647 [ +  - ][ -  + ]:       2127 :         if (data == NULL || len < sizeof(*hdr))
     648                 :          0 :                 return NULL;
     649                 :            : 
     650                 :       2127 :         hdr = (struct radius_hdr *) data;
     651                 :            : 
     652                 :       2127 :         msg_len = be_to_host16(hdr->length);
     653 [ +  - ][ -  + ]:       2127 :         if (msg_len < sizeof(*hdr) || msg_len > len) {
     654                 :          0 :                 wpa_printf(MSG_INFO, "RADIUS: Invalid message length");
     655                 :          0 :                 return NULL;
     656                 :            :         }
     657                 :            : 
     658         [ -  + ]:       2127 :         if (msg_len < len) {
     659                 :          0 :                 wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after "
     660                 :            :                            "RADIUS message", (unsigned long) len - msg_len);
     661                 :            :         }
     662                 :            : 
     663                 :       2127 :         msg = os_zalloc(sizeof(*msg));
     664         [ -  + ]:       2127 :         if (msg == NULL)
     665                 :          0 :                 return NULL;
     666                 :            : 
     667                 :       2127 :         msg->buf = wpabuf_alloc_copy(data, msg_len);
     668 [ -  + ][ +  - ]:       2127 :         if (msg->buf == NULL || radius_msg_initialize(msg)) {
     669                 :          0 :                 radius_msg_free(msg);
     670                 :          0 :                 return NULL;
     671                 :            :         }
     672                 :       2127 :         msg->hdr = wpabuf_mhead(msg->buf);
     673                 :            : 
     674                 :            :         /* parse attributes */
     675                 :       2127 :         pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr);
     676                 :       2127 :         end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf);
     677         [ +  + ]:      19201 :         while (pos < end) {
     678         [ -  + ]:      17074 :                 if ((size_t) (end - pos) < sizeof(*attr))
     679                 :          0 :                         goto fail;
     680                 :            : 
     681                 :      17074 :                 attr = (struct radius_attr_hdr *) pos;
     682                 :            : 
     683 [ +  - ][ +  - ]:      17074 :                 if (pos + attr->length > end || attr->length < sizeof(*attr))
     684                 :            :                         goto fail;
     685                 :            : 
     686                 :            :                 /* TODO: check that attr->length is suitable for attr->type */
     687                 :            : 
     688         [ -  + ]:      17074 :                 if (radius_msg_add_attr_to_array(msg, attr))
     689                 :          0 :                         goto fail;
     690                 :            : 
     691                 :      17074 :                 pos += attr->length;
     692                 :            :         }
     693                 :            : 
     694                 :       2127 :         return msg;
     695                 :            : 
     696                 :            :  fail:
     697                 :          0 :         radius_msg_free(msg);
     698                 :       2127 :         return NULL;
     699                 :            : }
     700                 :            : 
     701                 :            : 
     702                 :       2099 : int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)
     703                 :            : {
     704                 :       2099 :         const u8 *pos = data;
     705                 :       2099 :         size_t left = data_len;
     706                 :            : 
     707         [ +  + ]:       5009 :         while (left > 0) {
     708                 :            :                 int len;
     709         [ +  + ]:       2910 :                 if (left > RADIUS_MAX_ATTR_LEN)
     710                 :        811 :                         len = RADIUS_MAX_ATTR_LEN;
     711                 :            :                 else
     712                 :       2099 :                         len = left;
     713                 :            : 
     714         [ -  + ]:       2910 :                 if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE,
     715                 :            :                                          pos, len))
     716                 :          0 :                         return 0;
     717                 :            : 
     718                 :       2910 :                 pos += len;
     719                 :       2910 :                 left -= len;
     720                 :            :         }
     721                 :            : 
     722                 :       2099 :         return 1;
     723                 :            : }
     724                 :            : 
     725                 :            : 
     726                 :       2114 : struct wpabuf * radius_msg_get_eap(struct radius_msg *msg)
     727                 :            : {
     728                 :            :         struct wpabuf *eap;
     729                 :            :         size_t len, i;
     730                 :            :         struct radius_attr_hdr *attr;
     731                 :            : 
     732         [ -  + ]:       2114 :         if (msg == NULL)
     733                 :          0 :                 return NULL;
     734                 :            : 
     735                 :       2114 :         len = 0;
     736         [ +  + ]:      19264 :         for (i = 0; i < msg->attr_used; i++) {
     737                 :      17150 :                 attr = radius_get_attr_hdr(msg, i);
     738 [ +  - ][ +  + ]:      17150 :                 if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
     739                 :       2925 :                     attr->length > sizeof(struct radius_attr_hdr))
     740                 :       2925 :                         len += attr->length - sizeof(struct radius_attr_hdr);
     741                 :            :         }
     742                 :            : 
     743         [ -  + ]:       2114 :         if (len == 0)
     744                 :          0 :                 return NULL;
     745                 :            : 
     746                 :       2114 :         eap = wpabuf_alloc(len);
     747         [ -  + ]:       2114 :         if (eap == NULL)
     748                 :          0 :                 return NULL;
     749                 :            : 
     750         [ +  + ]:      19264 :         for (i = 0; i < msg->attr_used; i++) {
     751                 :      17150 :                 attr = radius_get_attr_hdr(msg, i);
     752 [ +  - ][ +  + ]:      17150 :                 if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
     753                 :       2925 :                     attr->length > sizeof(struct radius_attr_hdr)) {
     754                 :       2925 :                         int flen = attr->length - sizeof(*attr);
     755                 :       2925 :                         wpabuf_put_data(eap, attr + 1, flen);
     756                 :            :                 }
     757                 :            :         }
     758                 :            : 
     759                 :       2114 :         return eap;
     760                 :            : }
     761                 :            : 
     762                 :            : 
     763                 :       2098 : int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
     764                 :            :                                size_t secret_len, const u8 *req_auth)
     765                 :            : {
     766                 :            :         u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
     767                 :            :         u8 orig_authenticator[16];
     768                 :       2098 :         struct radius_attr_hdr *attr = NULL, *tmp;
     769                 :            :         size_t i;
     770                 :            : 
     771         [ +  + ]:      19047 :         for (i = 0; i < msg->attr_used; i++) {
     772                 :      16949 :                 tmp = radius_get_attr_hdr(msg, i);
     773         [ +  + ]:      16949 :                 if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
     774         [ -  + ]:       2098 :                         if (attr != NULL) {
     775                 :          0 :                                 wpa_printf(MSG_INFO, "Multiple Message-Authenticator attributes in RADIUS message");
     776                 :          0 :                                 return 1;
     777                 :            :                         }
     778                 :       2098 :                         attr = tmp;
     779                 :            :                 }
     780                 :            :         }
     781                 :            : 
     782         [ -  + ]:       2098 :         if (attr == NULL) {
     783                 :          0 :                 wpa_printf(MSG_INFO, "No Message-Authenticator attribute found");
     784                 :          0 :                 return 1;
     785                 :            :         }
     786                 :            : 
     787                 :       2098 :         os_memcpy(orig, attr + 1, MD5_MAC_LEN);
     788                 :       2098 :         os_memset(attr + 1, 0, MD5_MAC_LEN);
     789         [ +  + ]:       2098 :         if (req_auth) {
     790                 :       1049 :                 os_memcpy(orig_authenticator, msg->hdr->authenticator,
     791                 :            :                           sizeof(orig_authenticator));
     792                 :       1049 :                 os_memcpy(msg->hdr->authenticator, req_auth,
     793                 :            :                           sizeof(msg->hdr->authenticator));
     794                 :            :         }
     795                 :       2098 :         hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
     796                 :       2098 :                  wpabuf_len(msg->buf), auth);
     797                 :       2098 :         os_memcpy(attr + 1, orig, MD5_MAC_LEN);
     798         [ +  + ]:       2098 :         if (req_auth) {
     799                 :       1049 :                 os_memcpy(msg->hdr->authenticator, orig_authenticator,
     800                 :            :                           sizeof(orig_authenticator));
     801                 :            :         }
     802                 :            : 
     803         [ -  + ]:       2098 :         if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
     804                 :          0 :                 wpa_printf(MSG_INFO, "Invalid Message-Authenticator!");
     805                 :          0 :                 return 1;
     806                 :            :         }
     807                 :            : 
     808                 :       2098 :         return 0;
     809                 :            : }
     810                 :            : 
     811                 :            : 
     812                 :       1055 : int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
     813                 :            :                       size_t secret_len, struct radius_msg *sent_msg, int auth)
     814                 :            : {
     815                 :            :         const u8 *addr[4];
     816                 :            :         size_t len[4];
     817                 :            :         u8 hash[MD5_MAC_LEN];
     818                 :            : 
     819         [ -  + ]:       1055 :         if (sent_msg == NULL) {
     820                 :          0 :                 wpa_printf(MSG_INFO, "No matching Access-Request message found");
     821                 :          0 :                 return 1;
     822                 :            :         }
     823                 :            : 
     824   [ +  +  -  + ]:       2104 :         if (auth &&
     825                 :       1049 :             radius_msg_verify_msg_auth(msg, secret, secret_len,
     826                 :       1049 :                                        sent_msg->hdr->authenticator)) {
     827                 :          0 :                 return 1;
     828                 :            :         }
     829                 :            : 
     830                 :            :         /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
     831                 :       1055 :         addr[0] = (u8 *) msg->hdr;
     832                 :       1055 :         len[0] = 1 + 1 + 2;
     833                 :       1055 :         addr[1] = sent_msg->hdr->authenticator;
     834                 :       1055 :         len[1] = MD5_MAC_LEN;
     835                 :       1055 :         addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
     836                 :       1055 :         len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
     837                 :       1055 :         addr[3] = secret;
     838                 :       1055 :         len[3] = secret_len;
     839                 :       1055 :         md5_vector(4, addr, len, hash);
     840         [ -  + ]:       1055 :         if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
     841                 :          0 :                 wpa_printf(MSG_INFO, "Response Authenticator invalid!");
     842                 :          0 :                 return 1;
     843                 :            :         }
     844                 :            : 
     845                 :       1055 :         return 0;
     846                 :            : }
     847                 :            : 
     848                 :            : 
     849                 :       1905 : int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
     850                 :            :                          u8 type)
     851                 :            : {
     852                 :            :         struct radius_attr_hdr *attr;
     853                 :            :         size_t i;
     854                 :       1905 :         int count = 0;
     855                 :            : 
     856         [ +  + ]:      18126 :         for (i = 0; i < src->attr_used; i++) {
     857                 :      16221 :                 attr = radius_get_attr_hdr(src, i);
     858 [ +  - ][ +  + ]:      16221 :                 if (attr->type == type && attr->length >= sizeof(*attr)) {
     859         [ -  + ]:        856 :                         if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1),
     860                 :        856 :                                                  attr->length - sizeof(*attr)))
     861                 :          0 :                                 return -1;
     862                 :        856 :                         count++;
     863                 :            :                 }
     864                 :            :         }
     865                 :            : 
     866                 :       1905 :         return count;
     867                 :            : }
     868                 :            : 
     869                 :            : 
     870                 :            : /* Create Request Authenticator. The value should be unique over the lifetime
     871                 :            :  * of the shared secret between authenticator and authentication server.
     872                 :            :  * Use one-way MD5 hash calculated from current timestamp and some data given
     873                 :            :  * by the caller. */
     874                 :       1062 : void radius_msg_make_authenticator(struct radius_msg *msg,
     875                 :            :                                    const u8 *data, size_t len)
     876                 :            : {
     877                 :            :         struct os_time tv;
     878                 :            :         long int l;
     879                 :            :         const u8 *addr[3];
     880                 :            :         size_t elen[3];
     881                 :            : 
     882                 :       1062 :         os_get_time(&tv);
     883                 :       1062 :         l = os_random();
     884                 :       1062 :         addr[0] = (u8 *) &tv;
     885                 :       1062 :         elen[0] = sizeof(tv);
     886                 :       1062 :         addr[1] = data;
     887                 :       1062 :         elen[1] = len;
     888                 :       1062 :         addr[2] = (u8 *) &l;
     889                 :       1062 :         elen[2] = sizeof(l);
     890                 :       1062 :         md5_vector(3, addr, elen, msg->hdr->authenticator);
     891                 :       1062 : }
     892                 :            : 
     893                 :            : 
     894                 :            : /* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
     895                 :            :  * Returns the Attribute payload and sets alen to indicate the length of the
     896                 :            :  * payload if a vendor attribute with subtype is found, otherwise returns NULL.
     897                 :            :  * The returned payload is allocated with os_malloc() and caller must free it
     898                 :            :  * by calling os_free().
     899                 :            :  */
     900                 :        340 : static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
     901                 :            :                                       u8 subtype, size_t *alen)
     902                 :            : {
     903                 :            :         u8 *data, *pos;
     904                 :            :         size_t i, len;
     905                 :            : 
     906         [ -  + ]:        340 :         if (msg == NULL)
     907                 :          0 :                 return NULL;
     908                 :            : 
     909         [ +  - ]:        850 :         for (i = 0; i < msg->attr_used; i++) {
     910                 :        850 :                 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
     911                 :            :                 size_t left;
     912                 :            :                 u32 vendor_id;
     913                 :            :                 struct radius_attr_vendor *vhdr;
     914                 :            : 
     915 [ -  + ][ +  + ]:        850 :                 if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC ||
     916                 :        510 :                     attr->length < sizeof(*attr))
     917                 :        340 :                         continue;
     918                 :            : 
     919                 :        510 :                 left = attr->length - sizeof(*attr);
     920         [ -  + ]:        510 :                 if (left < 4)
     921                 :          0 :                         continue;
     922                 :            : 
     923                 :        510 :                 pos = (u8 *) (attr + 1);
     924                 :            : 
     925                 :        510 :                 os_memcpy(&vendor_id, pos, 4);
     926                 :        510 :                 pos += 4;
     927                 :        510 :                 left -= 4;
     928                 :            : 
     929         [ -  + ]:        510 :                 if (ntohl(vendor_id) != vendor)
     930                 :          0 :                         continue;
     931                 :            : 
     932         [ +  + ]:        680 :                 while (left >= sizeof(*vhdr)) {
     933                 :        510 :                         vhdr = (struct radius_attr_vendor *) pos;
     934 [ +  - ][ -  + ]:        510 :                         if (vhdr->vendor_length > left ||
     935                 :        510 :                             vhdr->vendor_length < sizeof(*vhdr)) {
     936                 :          0 :                                 left = 0;
     937                 :          0 :                                 break;
     938                 :            :                         }
     939         [ +  + ]:        510 :                         if (vhdr->vendor_type != subtype) {
     940                 :        170 :                                 pos += vhdr->vendor_length;
     941                 :        170 :                                 left -= vhdr->vendor_length;
     942                 :        170 :                                 continue;
     943                 :            :                         }
     944                 :            : 
     945                 :        340 :                         len = vhdr->vendor_length - sizeof(*vhdr);
     946                 :        340 :                         data = os_malloc(len);
     947         [ -  + ]:        340 :                         if (data == NULL)
     948                 :          0 :                                 return NULL;
     949                 :        340 :                         os_memcpy(data, pos + sizeof(*vhdr), len);
     950         [ +  - ]:        340 :                         if (alen)
     951                 :        340 :                                 *alen = len;
     952                 :        340 :                         return data;
     953                 :            :                 }
     954                 :            :         }
     955                 :            : 
     956                 :        340 :         return NULL;
     957                 :            : }
     958                 :            : 
     959                 :            : 
     960                 :        340 : static u8 * decrypt_ms_key(const u8 *key, size_t len,
     961                 :            :                            const u8 *req_authenticator,
     962                 :            :                            const u8 *secret, size_t secret_len, size_t *reslen)
     963                 :            : {
     964                 :            :         u8 *plain, *ppos, *res;
     965                 :            :         const u8 *pos;
     966                 :            :         size_t left, plen;
     967                 :            :         u8 hash[MD5_MAC_LEN];
     968                 :        340 :         int i, first = 1;
     969                 :            :         const u8 *addr[3];
     970                 :            :         size_t elen[3];
     971                 :            : 
     972                 :            :         /* key: 16-bit salt followed by encrypted key info */
     973                 :            : 
     974         [ -  + ]:        340 :         if (len < 2 + 16)
     975                 :          0 :                 return NULL;
     976                 :            : 
     977                 :        340 :         pos = key + 2;
     978                 :        340 :         left = len - 2;
     979         [ -  + ]:        340 :         if (left % 16) {
     980                 :          0 :                 wpa_printf(MSG_INFO, "Invalid ms key len %lu",
     981                 :            :                            (unsigned long) left);
     982                 :          0 :                 return NULL;
     983                 :            :         }
     984                 :            : 
     985                 :        340 :         plen = left;
     986                 :        340 :         ppos = plain = os_malloc(plen);
     987         [ -  + ]:        340 :         if (plain == NULL)
     988                 :          0 :                 return NULL;
     989                 :        340 :         plain[0] = 0;
     990                 :            : 
     991         [ +  + ]:       1360 :         while (left > 0) {
     992                 :            :                 /* b(1) = MD5(Secret + Request-Authenticator + Salt)
     993                 :            :                  * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
     994                 :            : 
     995                 :       1020 :                 addr[0] = secret;
     996                 :       1020 :                 elen[0] = secret_len;
     997         [ +  + ]:       1020 :                 if (first) {
     998                 :        340 :                         addr[1] = req_authenticator;
     999                 :        340 :                         elen[1] = MD5_MAC_LEN;
    1000                 :        340 :                         addr[2] = key;
    1001                 :        340 :                         elen[2] = 2; /* Salt */
    1002                 :            :                 } else {
    1003                 :        680 :                         addr[1] = pos - MD5_MAC_LEN;
    1004                 :        680 :                         elen[1] = MD5_MAC_LEN;
    1005                 :            :                 }
    1006         [ +  + ]:       1020 :                 md5_vector(first ? 3 : 2, addr, elen, hash);
    1007                 :       1020 :                 first = 0;
    1008                 :            : 
    1009         [ +  + ]:      17340 :                 for (i = 0; i < MD5_MAC_LEN; i++)
    1010                 :      16320 :                         *ppos++ = *pos++ ^ hash[i];
    1011                 :       1020 :                 left -= MD5_MAC_LEN;
    1012                 :            :         }
    1013                 :            : 
    1014 [ +  - ][ -  + ]:        340 :         if (plain[0] == 0 || plain[0] > plen - 1) {
    1015                 :          0 :                 wpa_printf(MSG_INFO, "Failed to decrypt MPPE key");
    1016                 :          0 :                 os_free(plain);
    1017                 :          0 :                 return NULL;
    1018                 :            :         }
    1019                 :            : 
    1020                 :        340 :         res = os_malloc(plain[0]);
    1021         [ -  + ]:        340 :         if (res == NULL) {
    1022                 :          0 :                 os_free(plain);
    1023                 :          0 :                 return NULL;
    1024                 :            :         }
    1025                 :        340 :         os_memcpy(res, plain + 1, plain[0]);
    1026         [ +  - ]:        340 :         if (reslen)
    1027                 :        340 :                 *reslen = plain[0];
    1028                 :        340 :         os_free(plain);
    1029                 :        340 :         return res;
    1030                 :            : }
    1031                 :            : 
    1032                 :            : 
    1033                 :        340 : static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
    1034                 :            :                            const u8 *req_authenticator,
    1035                 :            :                            const u8 *secret, size_t secret_len,
    1036                 :            :                            u8 *ebuf, size_t *elen)
    1037                 :            : {
    1038                 :        340 :         int i, len, first = 1;
    1039                 :            :         u8 hash[MD5_MAC_LEN], saltbuf[2], *pos;
    1040                 :            :         const u8 *addr[3];
    1041                 :            :         size_t _len[3];
    1042                 :            : 
    1043                 :        340 :         WPA_PUT_BE16(saltbuf, salt);
    1044                 :            : 
    1045                 :        340 :         len = 1 + key_len;
    1046         [ +  - ]:        340 :         if (len & 0x0f) {
    1047                 :        340 :                 len = (len & 0xf0) + 16;
    1048                 :            :         }
    1049                 :        340 :         os_memset(ebuf, 0, len);
    1050                 :        340 :         ebuf[0] = key_len;
    1051                 :        340 :         os_memcpy(ebuf + 1, key, key_len);
    1052                 :            : 
    1053                 :        340 :         *elen = len;
    1054                 :            : 
    1055                 :        340 :         pos = ebuf;
    1056         [ +  + ]:       1360 :         while (len > 0) {
    1057                 :            :                 /* b(1) = MD5(Secret + Request-Authenticator + Salt)
    1058                 :            :                  * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
    1059                 :       1020 :                 addr[0] = secret;
    1060                 :       1020 :                 _len[0] = secret_len;
    1061         [ +  + ]:       1020 :                 if (first) {
    1062                 :        340 :                         addr[1] = req_authenticator;
    1063                 :        340 :                         _len[1] = MD5_MAC_LEN;
    1064                 :        340 :                         addr[2] = saltbuf;
    1065                 :        340 :                         _len[2] = sizeof(saltbuf);
    1066                 :            :                 } else {
    1067                 :        680 :                         addr[1] = pos - MD5_MAC_LEN;
    1068                 :        680 :                         _len[1] = MD5_MAC_LEN;
    1069                 :            :                 }
    1070         [ +  + ]:       1020 :                 md5_vector(first ? 3 : 2, addr, _len, hash);
    1071                 :       1020 :                 first = 0;
    1072                 :            : 
    1073         [ +  + ]:      17340 :                 for (i = 0; i < MD5_MAC_LEN; i++)
    1074                 :      16320 :                         *pos++ ^= hash[i];
    1075                 :            : 
    1076                 :       1020 :                 len -= MD5_MAC_LEN;
    1077                 :            :         }
    1078                 :        340 : }
    1079                 :            : 
    1080                 :            : 
    1081                 :            : struct radius_ms_mppe_keys *
    1082                 :        170 : radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
    1083                 :            :                        const u8 *secret, size_t secret_len)
    1084                 :            : {
    1085                 :            :         u8 *key;
    1086                 :            :         size_t keylen;
    1087                 :            :         struct radius_ms_mppe_keys *keys;
    1088                 :            : 
    1089 [ +  - ][ -  + ]:        170 :         if (msg == NULL || sent_msg == NULL)
    1090                 :          0 :                 return NULL;
    1091                 :            : 
    1092                 :        170 :         keys = os_zalloc(sizeof(*keys));
    1093         [ -  + ]:        170 :         if (keys == NULL)
    1094                 :          0 :                 return NULL;
    1095                 :            : 
    1096                 :        170 :         key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
    1097                 :            :                                          RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
    1098                 :            :                                          &keylen);
    1099         [ +  - ]:        170 :         if (key) {
    1100                 :        170 :                 keys->send = decrypt_ms_key(key, keylen,
    1101                 :        170 :                                             sent_msg->hdr->authenticator,
    1102                 :            :                                             secret, secret_len,
    1103                 :            :                                             &keys->send_len);
    1104                 :        170 :                 os_free(key);
    1105                 :            :         }
    1106                 :            : 
    1107                 :        170 :         key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
    1108                 :            :                                          RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY,
    1109                 :            :                                          &keylen);
    1110         [ +  - ]:        170 :         if (key) {
    1111                 :        170 :                 keys->recv = decrypt_ms_key(key, keylen,
    1112                 :        170 :                                             sent_msg->hdr->authenticator,
    1113                 :            :                                             secret, secret_len,
    1114                 :            :                                             &keys->recv_len);
    1115                 :        170 :                 os_free(key);
    1116                 :            :         }
    1117                 :            : 
    1118                 :        170 :         return keys;
    1119                 :            : }
    1120                 :            : 
    1121                 :            : 
    1122                 :            : struct radius_ms_mppe_keys *
    1123                 :          0 : radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
    1124                 :            :                           const u8 *secret, size_t secret_len)
    1125                 :            : {
    1126                 :            :         u8 *key;
    1127                 :            :         size_t keylen;
    1128                 :            :         struct radius_ms_mppe_keys *keys;
    1129                 :            : 
    1130 [ #  # ][ #  # ]:          0 :         if (msg == NULL || sent_msg == NULL)
    1131                 :          0 :                 return NULL;
    1132                 :            : 
    1133                 :          0 :         keys = os_zalloc(sizeof(*keys));
    1134         [ #  # ]:          0 :         if (keys == NULL)
    1135                 :          0 :                 return NULL;
    1136                 :            : 
    1137                 :          0 :         key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO,
    1138                 :            :                                          RADIUS_CISCO_AV_PAIR, &keylen);
    1139 [ #  # ][ #  # ]:          0 :         if (key && keylen == 51 &&
                 [ #  # ]
    1140                 :          0 :             os_memcmp(key, "leap:session-key=", 17) == 0) {
    1141                 :          0 :                 keys->recv = decrypt_ms_key(key + 17, keylen - 17,
    1142                 :          0 :                                             sent_msg->hdr->authenticator,
    1143                 :            :                                             secret, secret_len,
    1144                 :            :                                             &keys->recv_len);
    1145                 :            :         }
    1146                 :          0 :         os_free(key);
    1147                 :            : 
    1148                 :          0 :         return keys;
    1149                 :            : }
    1150                 :            : 
    1151                 :            : 
    1152                 :        170 : int radius_msg_add_mppe_keys(struct radius_msg *msg,
    1153                 :            :                              const u8 *req_authenticator,
    1154                 :            :                              const u8 *secret, size_t secret_len,
    1155                 :            :                              const u8 *send_key, size_t send_key_len,
    1156                 :            :                              const u8 *recv_key, size_t recv_key_len)
    1157                 :            : {
    1158                 :            :         struct radius_attr_hdr *attr;
    1159                 :        170 :         u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT);
    1160                 :            :         u8 *buf;
    1161                 :            :         struct radius_attr_vendor *vhdr;
    1162                 :            :         u8 *pos;
    1163                 :            :         size_t elen;
    1164                 :            :         int hlen;
    1165                 :            :         u16 salt;
    1166                 :            : 
    1167                 :        170 :         hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2;
    1168                 :            : 
    1169                 :            :         /* MS-MPPE-Send-Key */
    1170                 :        170 :         buf = os_malloc(hlen + send_key_len + 16);
    1171         [ -  + ]:        170 :         if (buf == NULL) {
    1172                 :          0 :                 return 0;
    1173                 :            :         }
    1174                 :        170 :         pos = buf;
    1175                 :        170 :         os_memcpy(pos, &vendor_id, sizeof(vendor_id));
    1176                 :        170 :         pos += sizeof(vendor_id);
    1177                 :        170 :         vhdr = (struct radius_attr_vendor *) pos;
    1178                 :        170 :         vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
    1179                 :        170 :         pos = (u8 *) (vhdr + 1);
    1180                 :        170 :         salt = os_random() | 0x8000;
    1181                 :        170 :         WPA_PUT_BE16(pos, salt);
    1182                 :        170 :         pos += 2;
    1183                 :        170 :         encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
    1184                 :            :                        secret_len, pos, &elen);
    1185                 :        170 :         vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
    1186                 :            : 
    1187                 :        170 :         attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
    1188                 :            :                                    buf, hlen + elen);
    1189                 :        170 :         os_free(buf);
    1190         [ -  + ]:        170 :         if (attr == NULL) {
    1191                 :          0 :                 return 0;
    1192                 :            :         }
    1193                 :            : 
    1194                 :            :         /* MS-MPPE-Recv-Key */
    1195                 :        170 :         buf = os_malloc(hlen + send_key_len + 16);
    1196         [ -  + ]:        170 :         if (buf == NULL) {
    1197                 :          0 :                 return 0;
    1198                 :            :         }
    1199                 :        170 :         pos = buf;
    1200                 :        170 :         os_memcpy(pos, &vendor_id, sizeof(vendor_id));
    1201                 :        170 :         pos += sizeof(vendor_id);
    1202                 :        170 :         vhdr = (struct radius_attr_vendor *) pos;
    1203                 :        170 :         vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY;
    1204                 :        170 :         pos = (u8 *) (vhdr + 1);
    1205                 :        170 :         salt ^= 1;
    1206                 :        170 :         WPA_PUT_BE16(pos, salt);
    1207                 :        170 :         pos += 2;
    1208                 :        170 :         encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret,
    1209                 :            :                        secret_len, pos, &elen);
    1210                 :        170 :         vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
    1211                 :            : 
    1212                 :        170 :         attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
    1213                 :            :                                    buf, hlen + elen);
    1214                 :        170 :         os_free(buf);
    1215         [ -  + ]:        170 :         if (attr == NULL) {
    1216                 :          0 :                 return 0;
    1217                 :            :         }
    1218                 :            : 
    1219                 :        170 :         return 1;
    1220                 :            : }
    1221                 :            : 
    1222                 :            : 
    1223                 :        880 : int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data,
    1224                 :            :                        size_t len)
    1225                 :            : {
    1226                 :            :         struct radius_attr_hdr *attr;
    1227                 :            :         u8 *buf, *pos;
    1228                 :            :         size_t alen;
    1229                 :            : 
    1230                 :        880 :         alen = 4 + 2 + len;
    1231                 :        880 :         buf = os_malloc(alen);
    1232         [ -  + ]:        880 :         if (buf == NULL)
    1233                 :          0 :                 return 0;
    1234                 :        880 :         pos = buf;
    1235                 :        880 :         WPA_PUT_BE32(pos, RADIUS_VENDOR_ID_WFA);
    1236                 :        880 :         pos += 4;
    1237                 :        880 :         *pos++ = subtype;
    1238                 :        880 :         *pos++ = 2 + len;
    1239                 :        880 :         os_memcpy(pos, data, len);
    1240                 :        880 :         attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
    1241                 :            :                                    buf, alen);
    1242                 :        880 :         os_free(buf);
    1243         [ -  + ]:        880 :         if (attr == NULL)
    1244                 :          0 :                 return 0;
    1245                 :            : 
    1246                 :        880 :         return 1;
    1247                 :            : }
    1248                 :            : 
    1249                 :            : 
    1250                 :            : /* Add User-Password attribute to a RADIUS message and encrypt it as specified
    1251                 :            :  * in RFC 2865, Chap. 5.2 */
    1252                 :            : struct radius_attr_hdr *
    1253                 :          0 : radius_msg_add_attr_user_password(struct radius_msg *msg,
    1254                 :            :                                   const u8 *data, size_t data_len,
    1255                 :            :                                   const u8 *secret, size_t secret_len)
    1256                 :            : {
    1257                 :            :         u8 buf[128];
    1258                 :            :         size_t padlen, i, buf_len, pos;
    1259                 :            :         const u8 *addr[2];
    1260                 :            :         size_t len[2];
    1261                 :            :         u8 hash[16];
    1262                 :            : 
    1263         [ #  # ]:          0 :         if (data_len > 128)
    1264                 :          0 :                 return NULL;
    1265                 :            : 
    1266                 :          0 :         os_memcpy(buf, data, data_len);
    1267                 :          0 :         buf_len = data_len;
    1268                 :            : 
    1269                 :          0 :         padlen = data_len % 16;
    1270 [ #  # ][ #  # ]:          0 :         if (padlen && data_len < sizeof(buf)) {
    1271                 :          0 :                 padlen = 16 - padlen;
    1272                 :          0 :                 os_memset(buf + data_len, 0, padlen);
    1273                 :          0 :                 buf_len += padlen;
    1274                 :            :         }
    1275                 :            : 
    1276                 :          0 :         addr[0] = secret;
    1277                 :          0 :         len[0] = secret_len;
    1278                 :          0 :         addr[1] = msg->hdr->authenticator;
    1279                 :          0 :         len[1] = 16;
    1280                 :          0 :         md5_vector(2, addr, len, hash);
    1281                 :            : 
    1282         [ #  # ]:          0 :         for (i = 0; i < 16; i++)
    1283                 :          0 :                 buf[i] ^= hash[i];
    1284                 :          0 :         pos = 16;
    1285                 :            : 
    1286         [ #  # ]:          0 :         while (pos < buf_len) {
    1287                 :          0 :                 addr[0] = secret;
    1288                 :          0 :                 len[0] = secret_len;
    1289                 :          0 :                 addr[1] = &buf[pos - 16];
    1290                 :          0 :                 len[1] = 16;
    1291                 :          0 :                 md5_vector(2, addr, len, hash);
    1292                 :            : 
    1293         [ #  # ]:          0 :                 for (i = 0; i < 16; i++)
    1294                 :          0 :                         buf[pos + i] ^= hash[i];
    1295                 :            : 
    1296                 :          0 :                 pos += 16;
    1297                 :            :         }
    1298                 :            : 
    1299                 :          0 :         return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD,
    1300                 :            :                                    buf, buf_len);
    1301                 :            : }
    1302                 :            : 
    1303                 :            : 
    1304                 :       3545 : int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
    1305                 :            : {
    1306                 :       3545 :         struct radius_attr_hdr *attr = NULL, *tmp;
    1307                 :            :         size_t i, dlen;
    1308                 :            : 
    1309         [ +  + ]:      22793 :         for (i = 0; i < msg->attr_used; i++) {
    1310                 :      20331 :                 tmp = radius_get_attr_hdr(msg, i);
    1311         [ +  + ]:      20331 :                 if (tmp->type == type) {
    1312                 :       1083 :                         attr = tmp;
    1313                 :       1083 :                         break;
    1314                 :            :                 }
    1315                 :            :         }
    1316                 :            : 
    1317 [ +  + ][ -  + ]:       3545 :         if (!attr || attr->length < sizeof(*attr))
    1318                 :       2462 :                 return -1;
    1319                 :            : 
    1320                 :       1083 :         dlen = attr->length - sizeof(*attr);
    1321         [ +  + ]:       1083 :         if (buf)
    1322                 :       1062 :                 os_memcpy(buf, (attr + 1), dlen > len ? len : dlen);
    1323                 :       3545 :         return dlen;
    1324                 :            : }
    1325                 :            : 
    1326                 :            : 
    1327                 :        917 : int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
    1328                 :            :                             size_t *len, const u8 *start)
    1329                 :            : {
    1330                 :            :         size_t i;
    1331                 :        917 :         struct radius_attr_hdr *attr = NULL, *tmp;
    1332                 :            : 
    1333         [ +  + ]:       3617 :         for (i = 0; i < msg->attr_used; i++) {
    1334                 :       3057 :                 tmp = radius_get_attr_hdr(msg, i);
    1335 [ +  + ][ +  + ]:       3057 :                 if (tmp->type == type &&
    1336         [ +  + ]:        680 :                     (start == NULL || (u8 *) tmp > start)) {
    1337                 :        357 :                         attr = tmp;
    1338                 :        357 :                         break;
    1339                 :            :                 }
    1340                 :            :         }
    1341                 :            : 
    1342 [ +  + ][ -  + ]:        917 :         if (!attr || attr->length < sizeof(*attr))
    1343                 :        560 :                 return -1;
    1344                 :            : 
    1345                 :        357 :         *buf = (u8 *) (attr + 1);
    1346                 :        357 :         *len = attr->length - sizeof(*attr);
    1347                 :        917 :         return 0;
    1348                 :            : }
    1349                 :            : 
    1350                 :            : 
    1351                 :          3 : int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
    1352                 :            : {
    1353                 :            :         size_t i;
    1354                 :            :         int count;
    1355                 :            : 
    1356         [ +  + ]:         15 :         for (count = 0, i = 0; i < msg->attr_used; i++) {
    1357                 :         12 :                 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
    1358 [ #  # ][ -  + ]:         12 :                 if (attr->type == type &&
    1359                 :          0 :                     attr->length >= sizeof(struct radius_attr_hdr) + min_len)
    1360                 :          0 :                         count++;
    1361                 :            :         }
    1362                 :            : 
    1363                 :          3 :         return count;
    1364                 :            : }
    1365                 :            : 
    1366                 :            : 
    1367                 :            : struct radius_tunnel_attrs {
    1368                 :            :         int tag_used;
    1369                 :            :         int type; /* Tunnel-Type */
    1370                 :            :         int medium_type; /* Tunnel-Medium-Type */
    1371                 :            :         int vlanid;
    1372                 :            : };
    1373                 :            : 
    1374                 :            : 
    1375                 :            : /**
    1376                 :            :  * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
    1377                 :            :  * @msg: RADIUS message
    1378                 :            :  * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
    1379                 :            :  */
    1380                 :          0 : int radius_msg_get_vlanid(struct radius_msg *msg)
    1381                 :            : {
    1382                 :            :         struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
    1383                 :            :         size_t i;
    1384                 :          0 :         struct radius_attr_hdr *attr = NULL;
    1385                 :            :         const u8 *data;
    1386                 :            :         char buf[10];
    1387                 :            :         size_t dlen;
    1388                 :            : 
    1389                 :          0 :         os_memset(&tunnel, 0, sizeof(tunnel));
    1390                 :            : 
    1391         [ #  # ]:          0 :         for (i = 0; i < msg->attr_used; i++) {
    1392                 :          0 :                 attr = radius_get_attr_hdr(msg, i);
    1393         [ #  # ]:          0 :                 if (attr->length < sizeof(*attr))
    1394                 :          0 :                         return -1;
    1395                 :          0 :                 data = (const u8 *) (attr + 1);
    1396                 :          0 :                 dlen = attr->length - sizeof(*attr);
    1397         [ #  # ]:          0 :                 if (attr->length < 3)
    1398                 :          0 :                         continue;
    1399         [ #  # ]:          0 :                 if (data[0] >= RADIUS_TUNNEL_TAGS)
    1400                 :          0 :                         tun = &tunnel[0];
    1401                 :            :                 else
    1402                 :          0 :                         tun = &tunnel[data[0]];
    1403                 :            : 
    1404   [ #  #  #  # ]:          0 :                 switch (attr->type) {
    1405                 :            :                 case RADIUS_ATTR_TUNNEL_TYPE:
    1406         [ #  # ]:          0 :                         if (attr->length != 6)
    1407                 :          0 :                                 break;
    1408                 :          0 :                         tun->tag_used++;
    1409                 :          0 :                         tun->type = WPA_GET_BE24(data + 1);
    1410                 :          0 :                         break;
    1411                 :            :                 case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
    1412         [ #  # ]:          0 :                         if (attr->length != 6)
    1413                 :          0 :                                 break;
    1414                 :          0 :                         tun->tag_used++;
    1415                 :          0 :                         tun->medium_type = WPA_GET_BE24(data + 1);
    1416                 :          0 :                         break;
    1417                 :            :                 case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
    1418         [ #  # ]:          0 :                         if (data[0] < RADIUS_TUNNEL_TAGS) {
    1419                 :          0 :                                 data++;
    1420                 :          0 :                                 dlen--;
    1421                 :            :                         }
    1422         [ #  # ]:          0 :                         if (dlen >= sizeof(buf))
    1423                 :          0 :                                 break;
    1424                 :          0 :                         os_memcpy(buf, data, dlen);
    1425                 :          0 :                         buf[dlen] = '\0';
    1426                 :          0 :                         tun->tag_used++;
    1427                 :          0 :                         tun->vlanid = atoi(buf);
    1428                 :          0 :                         break;
    1429                 :            :                 }
    1430                 :            :         }
    1431                 :            : 
    1432         [ #  # ]:          0 :         for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) {
    1433                 :          0 :                 tun = &tunnel[i];
    1434 [ #  # ][ #  # ]:          0 :                 if (tun->tag_used &&
    1435         [ #  # ]:          0 :                     tun->type == RADIUS_TUNNEL_TYPE_VLAN &&
    1436         [ #  # ]:          0 :                     tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 &&
    1437                 :          0 :                     tun->vlanid > 0)
    1438                 :          0 :                         return tun->vlanid;
    1439                 :            :         }
    1440                 :            : 
    1441                 :          0 :         return -1;
    1442                 :            : }
    1443                 :            : 
    1444                 :            : 
    1445                 :            : /**
    1446                 :            :  * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password
    1447                 :            :  * @msg: Received RADIUS message
    1448                 :            :  * @keylen: Length of returned password
    1449                 :            :  * @secret: RADIUS shared secret
    1450                 :            :  * @secret_len: Length of secret
    1451                 :            :  * @sent_msg: Sent RADIUS message
    1452                 :            :  * @n: Number of password attribute to return (starting with 0)
    1453                 :            :  * Returns: Pointer to n-th password (free with os_free) or %NULL
    1454                 :            :  */
    1455                 :          0 : char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
    1456                 :            :                                       const u8 *secret, size_t secret_len,
    1457                 :            :                                       struct radius_msg *sent_msg, size_t n)
    1458                 :            : {
    1459                 :          0 :         u8 *buf = NULL;
    1460                 :            :         size_t buflen;
    1461                 :            :         const u8 *salt;
    1462                 :            :         u8 *str;
    1463                 :            :         const u8 *addr[3];
    1464                 :            :         size_t len[3];
    1465                 :            :         u8 hash[16];
    1466                 :            :         u8 *pos;
    1467                 :          0 :         size_t i, j = 0;
    1468                 :            :         struct radius_attr_hdr *attr;
    1469                 :            :         const u8 *data;
    1470                 :            :         size_t dlen;
    1471                 :          0 :         const u8 *fdata = NULL; /* points to found item */
    1472                 :          0 :         size_t fdlen = -1;
    1473                 :          0 :         char *ret = NULL;
    1474                 :            : 
    1475                 :            :         /* find n-th valid Tunnel-Password attribute */
    1476         [ #  # ]:          0 :         for (i = 0; i < msg->attr_used; i++) {
    1477                 :          0 :                 attr = radius_get_attr_hdr(msg, i);
    1478 [ #  # ][ #  # ]:          0 :                 if (attr == NULL ||
    1479                 :          0 :                     attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) {
    1480                 :          0 :                         continue;
    1481                 :            :                 }
    1482         [ #  # ]:          0 :                 if (attr->length <= 5)
    1483                 :          0 :                         continue;
    1484                 :          0 :                 data = (const u8 *) (attr + 1);
    1485                 :          0 :                 dlen = attr->length - sizeof(*attr);
    1486 [ #  # ][ #  # ]:          0 :                 if (dlen <= 3 || dlen % 16 != 3)
    1487                 :          0 :                         continue;
    1488                 :          0 :                 j++;
    1489         [ #  # ]:          0 :                 if (j <= n)
    1490                 :          0 :                         continue;
    1491                 :            : 
    1492                 :          0 :                 fdata = data;
    1493                 :          0 :                 fdlen = dlen;
    1494                 :          0 :                 break;
    1495                 :            :         }
    1496         [ #  # ]:          0 :         if (fdata == NULL)
    1497                 :          0 :                 goto out;
    1498                 :            : 
    1499                 :            :         /* alloc writable memory for decryption */
    1500                 :          0 :         buf = os_malloc(fdlen);
    1501         [ #  # ]:          0 :         if (buf == NULL)
    1502                 :          0 :                 goto out;
    1503                 :          0 :         os_memcpy(buf, fdata, fdlen);
    1504                 :          0 :         buflen = fdlen;
    1505                 :            : 
    1506                 :            :         /* init pointers */
    1507                 :          0 :         salt = buf + 1;
    1508                 :          0 :         str = buf + 3;
    1509                 :            : 
    1510                 :            :         /* decrypt blocks */
    1511                 :          0 :         pos = buf + buflen - 16; /* last block */
    1512         [ #  # ]:          0 :         while (pos >= str + 16) { /* all but the first block */
    1513                 :          0 :                 addr[0] = secret;
    1514                 :          0 :                 len[0] = secret_len;
    1515                 :          0 :                 addr[1] = pos - 16;
    1516                 :          0 :                 len[1] = 16;
    1517                 :          0 :                 md5_vector(2, addr, len, hash);
    1518                 :            : 
    1519         [ #  # ]:          0 :                 for (i = 0; i < 16; i++)
    1520                 :          0 :                         pos[i] ^= hash[i];
    1521                 :            : 
    1522                 :          0 :                 pos -= 16;
    1523                 :            :         }
    1524                 :            : 
    1525                 :            :         /* decrypt first block */
    1526         [ #  # ]:          0 :         if (str != pos)
    1527                 :          0 :                 goto out;
    1528                 :          0 :         addr[0] = secret;
    1529                 :          0 :         len[0] = secret_len;
    1530                 :          0 :         addr[1] = sent_msg->hdr->authenticator;
    1531                 :          0 :         len[1] = 16;
    1532                 :          0 :         addr[2] = salt;
    1533                 :          0 :         len[2] = 2;
    1534                 :          0 :         md5_vector(3, addr, len, hash);
    1535                 :            : 
    1536         [ #  # ]:          0 :         for (i = 0; i < 16; i++)
    1537                 :          0 :                 pos[i] ^= hash[i];
    1538                 :            : 
    1539                 :            :         /* derive plaintext length from first subfield */
    1540                 :          0 :         *keylen = (unsigned char) str[0];
    1541         [ #  # ]:          0 :         if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) {
    1542                 :            :                 /* decryption error - invalid key length */
    1543                 :          0 :                 goto out;
    1544                 :            :         }
    1545         [ #  # ]:          0 :         if (*keylen == 0) {
    1546                 :            :                 /* empty password */
    1547                 :          0 :                 goto out;
    1548                 :            :         }
    1549                 :            : 
    1550                 :            :         /* copy passphrase into new buffer */
    1551                 :          0 :         ret = os_malloc(*keylen);
    1552         [ #  # ]:          0 :         if (ret)
    1553                 :          0 :                 os_memcpy(ret, str + 1, *keylen);
    1554                 :            : 
    1555                 :            : out:
    1556                 :            :         /* return new buffer */
    1557                 :          0 :         os_free(buf);
    1558                 :          0 :         return ret;
    1559                 :            : }
    1560                 :            : 
    1561                 :            : 
    1562                 :        422 : void radius_free_class(struct radius_class_data *c)
    1563                 :            : {
    1564                 :            :         size_t i;
    1565         [ -  + ]:        422 :         if (c == NULL)
    1566                 :        422 :                 return;
    1567         [ -  + ]:        422 :         for (i = 0; i < c->count; i++)
    1568                 :          0 :                 os_free(c->attr[i].data);
    1569                 :        422 :         os_free(c->attr);
    1570                 :        422 :         c->attr = NULL;
    1571                 :        422 :         c->count = 0;
    1572                 :            : }
    1573                 :            : 
    1574                 :            : 
    1575                 :        178 : int radius_copy_class(struct radius_class_data *dst,
    1576                 :            :                       const struct radius_class_data *src)
    1577                 :            : {
    1578                 :            :         size_t i;
    1579                 :            : 
    1580         [ +  - ]:        178 :         if (src->attr == NULL)
    1581                 :        178 :                 return 0;
    1582                 :            : 
    1583                 :          0 :         dst->attr = os_calloc(src->count, sizeof(struct radius_attr_data));
    1584         [ #  # ]:          0 :         if (dst->attr == NULL)
    1585                 :          0 :                 return -1;
    1586                 :            : 
    1587                 :          0 :         dst->count = 0;
    1588                 :            : 
    1589         [ #  # ]:          0 :         for (i = 0; i < src->count; i++) {
    1590                 :          0 :                 dst->attr[i].data = os_malloc(src->attr[i].len);
    1591         [ #  # ]:          0 :                 if (dst->attr[i].data == NULL)
    1592                 :          0 :                         break;
    1593                 :          0 :                 dst->count++;
    1594                 :          0 :                 os_memcpy(dst->attr[i].data, src->attr[i].data,
    1595                 :            :                           src->attr[i].len);
    1596                 :          0 :                 dst->attr[i].len = src->attr[i].len;
    1597                 :            :         }
    1598                 :            : 
    1599                 :        178 :         return 0;
    1600                 :            : }
    1601                 :            : 
    1602                 :            : 
    1603                 :         11 : u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs)
    1604                 :            : {
    1605                 :            :         size_t i, j;
    1606                 :            :         struct radius_attr_hdr *attr;
    1607                 :            : 
    1608         [ +  + ]:         40 :         for (i = 0; i < msg->attr_used; i++) {
    1609                 :         30 :                 attr = radius_get_attr_hdr(msg, i);
    1610                 :            : 
    1611         [ +  + ]:        132 :                 for (j = 0; attrs[j]; j++) {
    1612         [ +  + ]:        131 :                         if (attr->type == attrs[j])
    1613                 :         29 :                                 break;
    1614                 :            :                 }
    1615                 :            : 
    1616         [ +  + ]:         30 :                 if (attrs[j] == 0)
    1617                 :          1 :                         return attr->type; /* unlisted attr */
    1618                 :            :         }
    1619                 :            : 
    1620                 :         11 :         return 0;
    1621                 :            : }

Generated by: LCOV version 1.9