2 * RADIUS message processing
3 * Copyright (c) 2002-2009, 2011-2015, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
11 #include "utils/common.h"
12 #include "utils/wpabuf.h"
13 #include "crypto/md5.h"
14 #include "crypto/crypto.h"
19 * struct radius_msg - RADIUS message structure for new and parsed messages
23 * buf - Allocated buffer for RADIUS message
28 * hdr - Pointer to the RADIUS header in buf
30 struct radius_hdr
*hdr
;
33 * attr_pos - Array of indexes to attributes
35 * The values are number of bytes from buf to the beginning of
36 * struct radius_attr_hdr.
41 * attr_size - Total size of the attribute pointer array
46 * attr_used - Total number of attributes in the array
52 struct radius_hdr
* radius_msg_get_hdr(struct radius_msg
*msg
)
58 struct wpabuf
* radius_msg_get_buf(struct radius_msg
*msg
)
64 static struct radius_attr_hdr
*
65 radius_get_attr_hdr(struct radius_msg
*msg
, int idx
)
67 return (struct radius_attr_hdr
*)
68 (wpabuf_mhead_u8(msg
->buf
) + msg
->attr_pos
[idx
]);
72 static void radius_msg_set_hdr(struct radius_msg
*msg
, u8 code
, u8 identifier
)
74 msg
->hdr
->code
= code
;
75 msg
->hdr
->identifier
= identifier
;
79 static int radius_msg_initialize(struct radius_msg
*msg
)
81 msg
->attr_pos
= os_calloc(RADIUS_DEFAULT_ATTR_COUNT
,
82 sizeof(*msg
->attr_pos
));
83 if (msg
->attr_pos
== NULL
)
86 msg
->attr_size
= RADIUS_DEFAULT_ATTR_COUNT
;
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
99 * The caller is responsible for freeing the returned data with
102 struct radius_msg
* radius_msg_new(u8 code
, u8 identifier
)
104 struct radius_msg
*msg
;
106 msg
= os_zalloc(sizeof(*msg
));
110 msg
->buf
= wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE
);
111 if (msg
->buf
== NULL
|| radius_msg_initialize(msg
)) {
112 radius_msg_free(msg
);
115 msg
->hdr
= wpabuf_put(msg
->buf
, sizeof(struct radius_hdr
));
117 radius_msg_set_hdr(msg
, code
, identifier
);
124 * radius_msg_free - Free a RADIUS message
125 * @msg: RADIUS message from radius_msg_new() or radius_msg_parse()
127 void radius_msg_free(struct radius_msg
*msg
)
132 wpabuf_free(msg
->buf
);
133 os_free(msg
->attr_pos
);
138 static const char *radius_code_string(u8 code
)
141 case RADIUS_CODE_ACCESS_REQUEST
: return "Access-Request";
142 case RADIUS_CODE_ACCESS_ACCEPT
: return "Access-Accept";
143 case RADIUS_CODE_ACCESS_REJECT
: return "Access-Reject";
144 case RADIUS_CODE_ACCOUNTING_REQUEST
: return "Accounting-Request";
145 case RADIUS_CODE_ACCOUNTING_RESPONSE
: return "Accounting-Response";
146 case RADIUS_CODE_ACCESS_CHALLENGE
: return "Access-Challenge";
147 case RADIUS_CODE_STATUS_SERVER
: return "Status-Server";
148 case RADIUS_CODE_STATUS_CLIENT
: return "Status-Client";
149 case RADIUS_CODE_RESERVED
: return "Reserved";
150 case RADIUS_CODE_DISCONNECT_REQUEST
: return "Disconnect-Request";
151 case RADIUS_CODE_DISCONNECT_ACK
: return "Disconnect-ACK";
152 case RADIUS_CODE_DISCONNECT_NAK
: return "Disconnect-NAK";
153 case RADIUS_CODE_COA_REQUEST
: return "CoA-Request";
154 case RADIUS_CODE_COA_ACK
: return "CoA-ACK";
155 case RADIUS_CODE_COA_NAK
: return "CoA-NAK";
156 default: return "?Unknown?";
161 struct radius_attr_type
{
165 RADIUS_ATTR_UNDIST
, RADIUS_ATTR_TEXT
, RADIUS_ATTR_IP
,
166 RADIUS_ATTR_HEXDUMP
, RADIUS_ATTR_INT32
, RADIUS_ATTR_IPV6
170 static const struct radius_attr_type radius_attrs
[] =
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_SERVICE_TYPE
, "Service-Type", RADIUS_ATTR_INT32
},
177 { RADIUS_ATTR_FRAMED_IP_ADDRESS
, "Framed-IP-Address", RADIUS_ATTR_IP
},
178 { RADIUS_ATTR_FRAMED_MTU
, "Framed-MTU", RADIUS_ATTR_INT32
},
179 { RADIUS_ATTR_REPLY_MESSAGE
, "Reply-Message", RADIUS_ATTR_TEXT
},
180 { RADIUS_ATTR_STATE
, "State", RADIUS_ATTR_UNDIST
},
181 { RADIUS_ATTR_CLASS
, "Class", RADIUS_ATTR_UNDIST
},
182 { RADIUS_ATTR_VENDOR_SPECIFIC
, "Vendor-Specific", RADIUS_ATTR_UNDIST
},
183 { RADIUS_ATTR_SESSION_TIMEOUT
, "Session-Timeout", RADIUS_ATTR_INT32
},
184 { RADIUS_ATTR_IDLE_TIMEOUT
, "Idle-Timeout", RADIUS_ATTR_INT32
},
185 { RADIUS_ATTR_TERMINATION_ACTION
, "Termination-Action",
187 { RADIUS_ATTR_CALLED_STATION_ID
, "Called-Station-Id",
189 { RADIUS_ATTR_CALLING_STATION_ID
, "Calling-Station-Id",
191 { RADIUS_ATTR_NAS_IDENTIFIER
, "NAS-Identifier", RADIUS_ATTR_TEXT
},
192 { RADIUS_ATTR_PROXY_STATE
, "Proxy-State", RADIUS_ATTR_UNDIST
},
193 { RADIUS_ATTR_ACCT_STATUS_TYPE
, "Acct-Status-Type",
195 { RADIUS_ATTR_ACCT_DELAY_TIME
, "Acct-Delay-Time", RADIUS_ATTR_INT32
},
196 { RADIUS_ATTR_ACCT_INPUT_OCTETS
, "Acct-Input-Octets",
198 { RADIUS_ATTR_ACCT_OUTPUT_OCTETS
, "Acct-Output-Octets",
200 { RADIUS_ATTR_ACCT_SESSION_ID
, "Acct-Session-Id", RADIUS_ATTR_TEXT
},
201 { RADIUS_ATTR_ACCT_AUTHENTIC
, "Acct-Authentic", RADIUS_ATTR_INT32
},
202 { RADIUS_ATTR_ACCT_SESSION_TIME
, "Acct-Session-Time",
204 { RADIUS_ATTR_ACCT_INPUT_PACKETS
, "Acct-Input-Packets",
206 { RADIUS_ATTR_ACCT_OUTPUT_PACKETS
, "Acct-Output-Packets",
208 { RADIUS_ATTR_ACCT_TERMINATE_CAUSE
, "Acct-Terminate-Cause",
210 { RADIUS_ATTR_ACCT_MULTI_SESSION_ID
, "Acct-Multi-Session-Id",
212 { RADIUS_ATTR_ACCT_LINK_COUNT
, "Acct-Link-Count", RADIUS_ATTR_INT32
},
213 { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS
, "Acct-Input-Gigawords",
215 { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS
, "Acct-Output-Gigawords",
217 { RADIUS_ATTR_EVENT_TIMESTAMP
, "Event-Timestamp",
219 { RADIUS_ATTR_EGRESS_VLANID
, "EGRESS-VLANID", RADIUS_ATTR_HEXDUMP
},
220 { RADIUS_ATTR_NAS_PORT_TYPE
, "NAS-Port-Type", RADIUS_ATTR_INT32
},
221 { RADIUS_ATTR_TUNNEL_TYPE
, "Tunnel-Type", RADIUS_ATTR_HEXDUMP
},
222 { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE
, "Tunnel-Medium-Type",
223 RADIUS_ATTR_HEXDUMP
},
224 { RADIUS_ATTR_TUNNEL_PASSWORD
, "Tunnel-Password",
225 RADIUS_ATTR_UNDIST
},
226 { RADIUS_ATTR_CONNECT_INFO
, "Connect-Info", RADIUS_ATTR_TEXT
},
227 { RADIUS_ATTR_EAP_MESSAGE
, "EAP-Message", RADIUS_ATTR_UNDIST
},
228 { RADIUS_ATTR_MESSAGE_AUTHENTICATOR
, "Message-Authenticator",
229 RADIUS_ATTR_UNDIST
},
230 { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID
, "Tunnel-Private-Group-Id",
231 RADIUS_ATTR_HEXDUMP
},
232 { RADIUS_ATTR_ACCT_INTERIM_INTERVAL
, "Acct-Interim-Interval",
234 { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY
, "Chargeable-User-Identity",
236 { RADIUS_ATTR_NAS_IPV6_ADDRESS
, "NAS-IPv6-Address", RADIUS_ATTR_IPV6
},
237 { RADIUS_ATTR_ERROR_CAUSE
, "Error-Cause", RADIUS_ATTR_INT32
},
238 { RADIUS_ATTR_EAP_KEY_NAME
, "EAP-Key-Name", RADIUS_ATTR_HEXDUMP
},
239 { RADIUS_ATTR_OPERATOR_NAME
, "Operator-Name", RADIUS_ATTR_TEXT
},
240 { RADIUS_ATTR_LOCATION_INFO
, "Location-Information",
241 RADIUS_ATTR_HEXDUMP
},
242 { RADIUS_ATTR_LOCATION_DATA
, "Location-Data", RADIUS_ATTR_HEXDUMP
},
243 { RADIUS_ATTR_BASIC_LOCATION_POLICY_RULES
,
244 "Basic-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP
},
245 { RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES
,
246 "Extended-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP
},
247 { RADIUS_ATTR_LOCATION_CAPABLE
, "Location-Capable", RADIUS_ATTR_INT32
},
248 { RADIUS_ATTR_REQUESTED_LOCATION_INFO
, "Requested-Location-Info",
250 { RADIUS_ATTR_MOBILITY_DOMAIN_ID
, "Mobility-Domain-Id",
252 { RADIUS_ATTR_WLAN_HESSID
, "WLAN-HESSID", RADIUS_ATTR_TEXT
},
253 { RADIUS_ATTR_WLAN_PAIRWISE_CIPHER
, "WLAN-Pairwise-Cipher",
254 RADIUS_ATTR_HEXDUMP
},
255 { RADIUS_ATTR_WLAN_GROUP_CIPHER
, "WLAN-Group-Cipher",
256 RADIUS_ATTR_HEXDUMP
},
257 { RADIUS_ATTR_WLAN_AKM_SUITE
, "WLAN-AKM-Suite",
258 RADIUS_ATTR_HEXDUMP
},
259 { RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER
, "WLAN-Group-Mgmt-Pairwise-Cipher",
260 RADIUS_ATTR_HEXDUMP
},
262 #define RADIUS_ATTRS ARRAY_SIZE(radius_attrs)
265 static const struct radius_attr_type
*radius_get_attr_type(u8 type
)
269 for (i
= 0; i
< RADIUS_ATTRS
; i
++) {
270 if (type
== radius_attrs
[i
].type
)
271 return &radius_attrs
[i
];
278 static void radius_msg_dump_attr(struct radius_attr_hdr
*hdr
)
280 const struct radius_attr_type
*attr
;
285 attr
= radius_get_attr_type(hdr
->type
);
287 wpa_printf(MSG_INFO
, " Attribute %d (%s) length=%d",
288 hdr
->type
, attr
? attr
->name
: "?Unknown?", hdr
->length
);
290 if (attr
== NULL
|| hdr
->length
< sizeof(struct radius_attr_hdr
))
293 len
= hdr
->length
- sizeof(struct radius_attr_hdr
);
294 pos
= (unsigned char *) (hdr
+ 1);
296 switch (attr
->data_type
) {
297 case RADIUS_ATTR_TEXT
:
298 printf_encode(buf
, sizeof(buf
), pos
, len
);
299 wpa_printf(MSG_INFO
, " Value: '%s'", buf
);
305 os_memcpy(&addr
, pos
, 4);
306 wpa_printf(MSG_INFO
, " Value: %s",
309 wpa_printf(MSG_INFO
, " Invalid IP address length %d",
315 case RADIUS_ATTR_IPV6
:
318 struct in6_addr
*addr
= (struct in6_addr
*) pos
;
319 atxt
= inet_ntop(AF_INET6
, addr
, buf
, sizeof(buf
));
320 wpa_printf(MSG_INFO
, " Value: %s",
323 wpa_printf(MSG_INFO
, " Invalid IPv6 address length %d",
327 #endif /* CONFIG_IPV6 */
329 case RADIUS_ATTR_HEXDUMP
:
330 case RADIUS_ATTR_UNDIST
:
331 wpa_snprintf_hex(buf
, sizeof(buf
), pos
, len
);
332 wpa_printf(MSG_INFO
, " Value: %s", buf
);
335 case RADIUS_ATTR_INT32
:
337 wpa_printf(MSG_INFO
, " Value: %u",
340 wpa_printf(MSG_INFO
, " Invalid INT32 length %d",
350 void radius_msg_dump(struct radius_msg
*msg
)
354 wpa_printf(MSG_INFO
, "RADIUS message: code=%d (%s) identifier=%d length=%d",
355 msg
->hdr
->code
, radius_code_string(msg
->hdr
->code
),
356 msg
->hdr
->identifier
, be_to_host16(msg
->hdr
->length
));
358 for (i
= 0; i
< msg
->attr_used
; i
++) {
359 struct radius_attr_hdr
*attr
= radius_get_attr_hdr(msg
, i
);
360 radius_msg_dump_attr(attr
);
365 int radius_msg_finish(struct radius_msg
*msg
, const u8
*secret
,
369 u8 auth
[MD5_MAC_LEN
];
370 struct radius_attr_hdr
*attr
;
372 os_memset(auth
, 0, MD5_MAC_LEN
);
373 attr
= radius_msg_add_attr(msg
,
374 RADIUS_ATTR_MESSAGE_AUTHENTICATOR
,
377 wpa_printf(MSG_WARNING
, "RADIUS: Could not add "
378 "Message-Authenticator");
381 msg
->hdr
->length
= host_to_be16(wpabuf_len(msg
->buf
));
382 hmac_md5(secret
, secret_len
, wpabuf_head(msg
->buf
),
383 wpabuf_len(msg
->buf
), (u8
*) (attr
+ 1));
385 msg
->hdr
->length
= host_to_be16(wpabuf_len(msg
->buf
));
387 if (wpabuf_len(msg
->buf
) > 0xffff) {
388 wpa_printf(MSG_WARNING
, "RADIUS: Too long message (%lu)",
389 (unsigned long) wpabuf_len(msg
->buf
));
396 int radius_msg_finish_srv(struct radius_msg
*msg
, const u8
*secret
,
397 size_t secret_len
, const u8
*req_authenticator
)
399 u8 auth
[MD5_MAC_LEN
];
400 struct radius_attr_hdr
*attr
;
404 os_memset(auth
, 0, MD5_MAC_LEN
);
405 attr
= radius_msg_add_attr(msg
, RADIUS_ATTR_MESSAGE_AUTHENTICATOR
,
408 wpa_printf(MSG_ERROR
, "WARNING: Could not add Message-Authenticator");
411 msg
->hdr
->length
= host_to_be16(wpabuf_len(msg
->buf
));
412 os_memcpy(msg
->hdr
->authenticator
, req_authenticator
,
413 sizeof(msg
->hdr
->authenticator
));
414 hmac_md5(secret
, secret_len
, wpabuf_head(msg
->buf
),
415 wpabuf_len(msg
->buf
), (u8
*) (attr
+ 1));
417 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
418 addr
[0] = (u8
*) msg
->hdr
;
420 addr
[1] = req_authenticator
;
421 len
[1] = MD5_MAC_LEN
;
422 addr
[2] = wpabuf_head_u8(msg
->buf
) + sizeof(struct radius_hdr
);
423 len
[2] = wpabuf_len(msg
->buf
) - sizeof(struct radius_hdr
);
426 md5_vector(4, addr
, len
, msg
->hdr
->authenticator
);
428 if (wpabuf_len(msg
->buf
) > 0xffff) {
429 wpa_printf(MSG_WARNING
, "RADIUS: Too long message (%lu)",
430 (unsigned long) wpabuf_len(msg
->buf
));
437 int radius_msg_finish_das_resp(struct radius_msg
*msg
, const u8
*secret
,
439 const struct radius_hdr
*req_hdr
)
443 u8 auth
[MD5_MAC_LEN
];
444 struct radius_attr_hdr
*attr
;
446 os_memset(auth
, 0, MD5_MAC_LEN
);
447 attr
= radius_msg_add_attr(msg
, RADIUS_ATTR_MESSAGE_AUTHENTICATOR
,
450 wpa_printf(MSG_WARNING
, "Could not add Message-Authenticator");
454 msg
->hdr
->length
= host_to_be16(wpabuf_len(msg
->buf
));
455 os_memcpy(msg
->hdr
->authenticator
, req_hdr
->authenticator
, 16);
456 hmac_md5(secret
, secret_len
, wpabuf_head(msg
->buf
),
457 wpabuf_len(msg
->buf
), (u8
*) (attr
+ 1));
459 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
460 addr
[0] = wpabuf_head_u8(msg
->buf
);
461 len
[0] = wpabuf_len(msg
->buf
);
464 if (md5_vector(2, addr
, len
, msg
->hdr
->authenticator
) < 0)
467 if (wpabuf_len(msg
->buf
) > 0xffff) {
468 wpa_printf(MSG_WARNING
, "RADIUS: Too long message (%lu)",
469 (unsigned long) wpabuf_len(msg
->buf
));
476 void radius_msg_finish_acct(struct radius_msg
*msg
, const u8
*secret
,
482 msg
->hdr
->length
= host_to_be16(wpabuf_len(msg
->buf
));
483 os_memset(msg
->hdr
->authenticator
, 0, MD5_MAC_LEN
);
484 addr
[0] = wpabuf_head(msg
->buf
);
485 len
[0] = wpabuf_len(msg
->buf
);
488 md5_vector(2, addr
, len
, msg
->hdr
->authenticator
);
490 if (wpabuf_len(msg
->buf
) > 0xffff) {
491 wpa_printf(MSG_WARNING
, "RADIUS: Too long messages (%lu)",
492 (unsigned long) wpabuf_len(msg
->buf
));
497 void radius_msg_finish_acct_resp(struct radius_msg
*msg
, const u8
*secret
,
498 size_t secret_len
, const u8
*req_authenticator
)
503 msg
->hdr
->length
= host_to_be16(wpabuf_len(msg
->buf
));
504 os_memcpy(msg
->hdr
->authenticator
, req_authenticator
, MD5_MAC_LEN
);
505 addr
[0] = wpabuf_head(msg
->buf
);
506 len
[0] = wpabuf_len(msg
->buf
);
509 md5_vector(2, addr
, len
, msg
->hdr
->authenticator
);
511 if (wpabuf_len(msg
->buf
) > 0xffff) {
512 wpa_printf(MSG_WARNING
, "RADIUS: Too long messages (%lu)",
513 (unsigned long) wpabuf_len(msg
->buf
));
518 int radius_msg_verify_acct_req(struct radius_msg
*msg
, const u8
*secret
,
523 u8 zero
[MD5_MAC_LEN
];
524 u8 hash
[MD5_MAC_LEN
];
526 os_memset(zero
, 0, sizeof(zero
));
527 addr
[0] = (u8
*) msg
->hdr
;
528 len
[0] = sizeof(struct radius_hdr
) - MD5_MAC_LEN
;
530 len
[1] = MD5_MAC_LEN
;
531 addr
[2] = (u8
*) (msg
->hdr
+ 1);
532 len
[2] = wpabuf_len(msg
->buf
) - sizeof(struct radius_hdr
);
535 md5_vector(4, addr
, len
, hash
);
536 return os_memcmp_const(msg
->hdr
->authenticator
, hash
, MD5_MAC_LEN
) != 0;
540 int radius_msg_verify_das_req(struct radius_msg
*msg
, const u8
*secret
,
542 int require_message_authenticator
)
546 u8 zero
[MD5_MAC_LEN
];
547 u8 hash
[MD5_MAC_LEN
];
548 u8 auth
[MD5_MAC_LEN
], orig
[MD5_MAC_LEN
];
549 u8 orig_authenticator
[16];
551 struct radius_attr_hdr
*attr
= NULL
, *tmp
;
554 os_memset(zero
, 0, sizeof(zero
));
555 addr
[0] = (u8
*) msg
->hdr
;
556 len
[0] = sizeof(struct radius_hdr
) - MD5_MAC_LEN
;
558 len
[1] = MD5_MAC_LEN
;
559 addr
[2] = (u8
*) (msg
->hdr
+ 1);
560 len
[2] = wpabuf_len(msg
->buf
) - sizeof(struct radius_hdr
);
563 md5_vector(4, addr
, len
, hash
);
564 if (os_memcmp_const(msg
->hdr
->authenticator
, hash
, MD5_MAC_LEN
) != 0)
567 for (i
= 0; i
< msg
->attr_used
; i
++) {
568 tmp
= radius_get_attr_hdr(msg
, i
);
569 if (tmp
->type
== RADIUS_ATTR_MESSAGE_AUTHENTICATOR
) {
571 wpa_printf(MSG_WARNING
, "Multiple "
572 "Message-Authenticator attributes "
573 "in RADIUS message");
581 if (require_message_authenticator
) {
582 wpa_printf(MSG_WARNING
,
583 "Missing Message-Authenticator attribute in RADIUS message");
589 os_memcpy(orig
, attr
+ 1, MD5_MAC_LEN
);
590 os_memset(attr
+ 1, 0, MD5_MAC_LEN
);
591 os_memcpy(orig_authenticator
, msg
->hdr
->authenticator
,
592 sizeof(orig_authenticator
));
593 os_memset(msg
->hdr
->authenticator
, 0,
594 sizeof(msg
->hdr
->authenticator
));
595 hmac_md5(secret
, secret_len
, wpabuf_head(msg
->buf
),
596 wpabuf_len(msg
->buf
), auth
);
597 os_memcpy(attr
+ 1, orig
, MD5_MAC_LEN
);
598 os_memcpy(msg
->hdr
->authenticator
, orig_authenticator
,
599 sizeof(orig_authenticator
));
601 return os_memcmp_const(orig
, auth
, MD5_MAC_LEN
) != 0;
605 static int radius_msg_add_attr_to_array(struct radius_msg
*msg
,
606 struct radius_attr_hdr
*attr
)
608 if (msg
->attr_used
>= msg
->attr_size
) {
610 int nlen
= msg
->attr_size
* 2;
612 nattr_pos
= os_realloc_array(msg
->attr_pos
, nlen
,
613 sizeof(*msg
->attr_pos
));
614 if (nattr_pos
== NULL
)
617 msg
->attr_pos
= nattr_pos
;
618 msg
->attr_size
= nlen
;
621 msg
->attr_pos
[msg
->attr_used
++] =
622 (unsigned char *) attr
- wpabuf_head_u8(msg
->buf
);
628 struct radius_attr_hdr
*radius_msg_add_attr(struct radius_msg
*msg
, u8 type
,
629 const u8
*data
, size_t data_len
)
632 struct radius_attr_hdr
*attr
;
634 if (data_len
> RADIUS_MAX_ATTR_LEN
) {
635 wpa_printf(MSG_ERROR
, "radius_msg_add_attr: too long attribute (%lu bytes)",
636 (unsigned long) data_len
);
640 buf_needed
= sizeof(*attr
) + data_len
;
642 if (wpabuf_tailroom(msg
->buf
) < buf_needed
) {
643 /* allocate more space for message buffer */
644 if (wpabuf_resize(&msg
->buf
, buf_needed
) < 0)
646 msg
->hdr
= wpabuf_mhead(msg
->buf
);
649 attr
= wpabuf_put(msg
->buf
, sizeof(struct radius_attr_hdr
));
651 attr
->length
= sizeof(*attr
) + data_len
;
652 wpabuf_put_data(msg
->buf
, data
, data_len
);
654 if (radius_msg_add_attr_to_array(msg
, attr
))
662 * radius_msg_parse - Parse a RADIUS message
663 * @data: RADIUS message to be parsed
664 * @len: Length of data buffer in octets
665 * Returns: Parsed RADIUS message or %NULL on failure
667 * This parses a RADIUS message and makes a copy of its data. The caller is
668 * responsible for freeing the returned data with radius_msg_free().
670 struct radius_msg
* radius_msg_parse(const u8
*data
, size_t len
)
672 struct radius_msg
*msg
;
673 struct radius_hdr
*hdr
;
674 struct radius_attr_hdr
*attr
;
676 unsigned char *pos
, *end
;
678 if (data
== NULL
|| len
< sizeof(*hdr
))
681 hdr
= (struct radius_hdr
*) data
;
683 msg_len
= be_to_host16(hdr
->length
);
684 if (msg_len
< sizeof(*hdr
) || msg_len
> len
) {
685 wpa_printf(MSG_INFO
, "RADIUS: Invalid message length");
690 wpa_printf(MSG_DEBUG
, "RADIUS: Ignored %lu extra bytes after "
691 "RADIUS message", (unsigned long) len
- msg_len
);
694 msg
= os_zalloc(sizeof(*msg
));
698 msg
->buf
= wpabuf_alloc_copy(data
, msg_len
);
699 if (msg
->buf
== NULL
|| radius_msg_initialize(msg
)) {
700 radius_msg_free(msg
);
703 msg
->hdr
= wpabuf_mhead(msg
->buf
);
705 /* parse attributes */
706 pos
= wpabuf_mhead_u8(msg
->buf
) + sizeof(struct radius_hdr
);
707 end
= wpabuf_mhead_u8(msg
->buf
) + wpabuf_len(msg
->buf
);
709 if ((size_t) (end
- pos
) < sizeof(*attr
))
712 attr
= (struct radius_attr_hdr
*) pos
;
714 if (attr
->length
> end
- pos
|| attr
->length
< sizeof(*attr
))
717 /* TODO: check that attr->length is suitable for attr->type */
719 if (radius_msg_add_attr_to_array(msg
, attr
))
728 radius_msg_free(msg
);
733 int radius_msg_add_eap(struct radius_msg
*msg
, const u8
*data
, size_t data_len
)
735 const u8
*pos
= data
;
736 size_t left
= data_len
;
740 if (left
> RADIUS_MAX_ATTR_LEN
)
741 len
= RADIUS_MAX_ATTR_LEN
;
745 if (!radius_msg_add_attr(msg
, RADIUS_ATTR_EAP_MESSAGE
,
757 struct wpabuf
* radius_msg_get_eap(struct radius_msg
*msg
)
761 struct radius_attr_hdr
*attr
;
767 for (i
= 0; i
< msg
->attr_used
; i
++) {
768 attr
= radius_get_attr_hdr(msg
, i
);
769 if (attr
->type
== RADIUS_ATTR_EAP_MESSAGE
&&
770 attr
->length
> sizeof(struct radius_attr_hdr
))
771 len
+= attr
->length
- sizeof(struct radius_attr_hdr
);
777 eap
= wpabuf_alloc(len
);
781 for (i
= 0; i
< msg
->attr_used
; i
++) {
782 attr
= radius_get_attr_hdr(msg
, i
);
783 if (attr
->type
== RADIUS_ATTR_EAP_MESSAGE
&&
784 attr
->length
> sizeof(struct radius_attr_hdr
)) {
785 int flen
= attr
->length
- sizeof(*attr
);
786 wpabuf_put_data(eap
, attr
+ 1, flen
);
794 int radius_msg_verify_msg_auth(struct radius_msg
*msg
, const u8
*secret
,
795 size_t secret_len
, const u8
*req_auth
)
797 u8 auth
[MD5_MAC_LEN
], orig
[MD5_MAC_LEN
];
798 u8 orig_authenticator
[16];
799 struct radius_attr_hdr
*attr
= NULL
, *tmp
;
802 for (i
= 0; i
< msg
->attr_used
; i
++) {
803 tmp
= radius_get_attr_hdr(msg
, i
);
804 if (tmp
->type
== RADIUS_ATTR_MESSAGE_AUTHENTICATOR
) {
806 wpa_printf(MSG_INFO
, "Multiple Message-Authenticator attributes in RADIUS message");
814 wpa_printf(MSG_INFO
, "No Message-Authenticator attribute found");
818 os_memcpy(orig
, attr
+ 1, MD5_MAC_LEN
);
819 os_memset(attr
+ 1, 0, MD5_MAC_LEN
);
821 os_memcpy(orig_authenticator
, msg
->hdr
->authenticator
,
822 sizeof(orig_authenticator
));
823 os_memcpy(msg
->hdr
->authenticator
, req_auth
,
824 sizeof(msg
->hdr
->authenticator
));
826 if (hmac_md5(secret
, secret_len
, wpabuf_head(msg
->buf
),
827 wpabuf_len(msg
->buf
), auth
) < 0)
829 os_memcpy(attr
+ 1, orig
, MD5_MAC_LEN
);
831 os_memcpy(msg
->hdr
->authenticator
, orig_authenticator
,
832 sizeof(orig_authenticator
));
835 if (os_memcmp_const(orig
, auth
, MD5_MAC_LEN
) != 0) {
836 wpa_printf(MSG_INFO
, "Invalid Message-Authenticator!");
844 int radius_msg_verify(struct radius_msg
*msg
, const u8
*secret
,
845 size_t secret_len
, struct radius_msg
*sent_msg
, int auth
)
849 u8 hash
[MD5_MAC_LEN
];
851 if (sent_msg
== NULL
) {
852 wpa_printf(MSG_INFO
, "No matching Access-Request message found");
857 radius_msg_verify_msg_auth(msg
, secret
, secret_len
,
858 sent_msg
->hdr
->authenticator
)) {
862 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
863 addr
[0] = (u8
*) msg
->hdr
;
865 addr
[1] = sent_msg
->hdr
->authenticator
;
866 len
[1] = MD5_MAC_LEN
;
867 addr
[2] = wpabuf_head_u8(msg
->buf
) + sizeof(struct radius_hdr
);
868 len
[2] = wpabuf_len(msg
->buf
) - sizeof(struct radius_hdr
);
871 if (md5_vector(4, addr
, len
, hash
) < 0 ||
872 os_memcmp_const(hash
, msg
->hdr
->authenticator
, MD5_MAC_LEN
) != 0) {
873 wpa_printf(MSG_INFO
, "Response Authenticator invalid!");
881 int radius_msg_copy_attr(struct radius_msg
*dst
, struct radius_msg
*src
,
884 struct radius_attr_hdr
*attr
;
888 for (i
= 0; i
< src
->attr_used
; i
++) {
889 attr
= radius_get_attr_hdr(src
, i
);
890 if (attr
->type
== type
&& attr
->length
>= sizeof(*attr
)) {
891 if (!radius_msg_add_attr(dst
, type
, (u8
*) (attr
+ 1),
892 attr
->length
- sizeof(*attr
)))
902 /* Create Request Authenticator. The value should be unique over the lifetime
903 * of the shared secret between authenticator and authentication server.
905 int radius_msg_make_authenticator(struct radius_msg
*msg
)
907 return os_get_random((u8
*) &msg
->hdr
->authenticator
,
908 sizeof(msg
->hdr
->authenticator
));
912 /* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
913 * Returns the Attribute payload and sets alen to indicate the length of the
914 * payload if a vendor attribute with subtype is found, otherwise returns NULL.
915 * The returned payload is allocated with os_malloc() and caller must free it
916 * by calling os_free().
918 static u8
*radius_msg_get_vendor_attr(struct radius_msg
*msg
, u32 vendor
,
919 u8 subtype
, size_t *alen
)
927 for (i
= 0; i
< msg
->attr_used
; i
++) {
928 struct radius_attr_hdr
*attr
= radius_get_attr_hdr(msg
, i
);
931 struct radius_attr_vendor
*vhdr
;
933 if (attr
->type
!= RADIUS_ATTR_VENDOR_SPECIFIC
||
934 attr
->length
< sizeof(*attr
))
937 left
= attr
->length
- sizeof(*attr
);
941 pos
= (u8
*) (attr
+ 1);
943 os_memcpy(&vendor_id
, pos
, 4);
947 if (ntohl(vendor_id
) != vendor
)
950 while (left
>= sizeof(*vhdr
)) {
951 vhdr
= (struct radius_attr_vendor
*) pos
;
952 if (vhdr
->vendor_length
> left
||
953 vhdr
->vendor_length
< sizeof(*vhdr
)) {
956 if (vhdr
->vendor_type
!= subtype
) {
957 pos
+= vhdr
->vendor_length
;
958 left
-= vhdr
->vendor_length
;
962 len
= vhdr
->vendor_length
- sizeof(*vhdr
);
963 data
= os_malloc(len
);
966 os_memcpy(data
, pos
+ sizeof(*vhdr
), len
);
977 static u8
* decrypt_ms_key(const u8
*key
, size_t len
,
978 const u8
*req_authenticator
,
979 const u8
*secret
, size_t secret_len
, size_t *reslen
)
981 u8
*plain
, *ppos
, *res
;
984 u8 hash
[MD5_MAC_LEN
];
989 /* key: 16-bit salt followed by encrypted key info */
992 wpa_printf(MSG_DEBUG
, "RADIUS: %s: Len is too small: %d",
993 __func__
, (int) len
);
1000 wpa_printf(MSG_INFO
, "RADIUS: Invalid ms key len %lu",
1001 (unsigned long) left
);
1006 ppos
= plain
= os_malloc(plen
);
1012 /* b(1) = MD5(Secret + Request-Authenticator + Salt)
1013 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
1016 elen
[0] = secret_len
;
1018 addr
[1] = req_authenticator
;
1019 elen
[1] = MD5_MAC_LEN
;
1021 elen
[2] = 2; /* Salt */
1023 addr
[1] = pos
- MD5_MAC_LEN
;
1024 elen
[1] = MD5_MAC_LEN
;
1026 if (md5_vector(first
? 3 : 2, addr
, elen
, hash
) < 0) {
1032 for (i
= 0; i
< MD5_MAC_LEN
; i
++)
1033 *ppos
++ = *pos
++ ^ hash
[i
];
1034 left
-= MD5_MAC_LEN
;
1037 if (plain
[0] == 0 || plain
[0] > plen
- 1) {
1038 wpa_printf(MSG_INFO
, "RADIUS: Failed to decrypt MPPE key");
1043 res
= os_malloc(plain
[0]);
1048 os_memcpy(res
, plain
+ 1, plain
[0]);
1056 static void encrypt_ms_key(const u8
*key
, size_t key_len
, u16 salt
,
1057 const u8
*req_authenticator
,
1058 const u8
*secret
, size_t secret_len
,
1059 u8
*ebuf
, size_t *elen
)
1061 int i
, len
, first
= 1;
1062 u8 hash
[MD5_MAC_LEN
], saltbuf
[2], *pos
;
1066 WPA_PUT_BE16(saltbuf
, salt
);
1070 len
= (len
& 0xf0) + 16;
1072 os_memset(ebuf
, 0, len
);
1074 os_memcpy(ebuf
+ 1, key
, key_len
);
1080 /* b(1) = MD5(Secret + Request-Authenticator + Salt)
1081 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
1083 _len
[0] = secret_len
;
1085 addr
[1] = req_authenticator
;
1086 _len
[1] = MD5_MAC_LEN
;
1088 _len
[2] = sizeof(saltbuf
);
1090 addr
[1] = pos
- MD5_MAC_LEN
;
1091 _len
[1] = MD5_MAC_LEN
;
1093 md5_vector(first
? 3 : 2, addr
, _len
, hash
);
1096 for (i
= 0; i
< MD5_MAC_LEN
; i
++)
1104 struct radius_ms_mppe_keys
*
1105 radius_msg_get_ms_keys(struct radius_msg
*msg
, struct radius_msg
*sent_msg
,
1106 const u8
*secret
, size_t secret_len
)
1110 struct radius_ms_mppe_keys
*keys
;
1112 if (msg
== NULL
|| sent_msg
== NULL
)
1115 keys
= os_zalloc(sizeof(*keys
));
1119 key
= radius_msg_get_vendor_attr(msg
, RADIUS_VENDOR_ID_MICROSOFT
,
1120 RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY
,
1123 keys
->send
= decrypt_ms_key(key
, keylen
,
1124 sent_msg
->hdr
->authenticator
,
1128 wpa_printf(MSG_DEBUG
,
1129 "RADIUS: Failed to decrypt send key");
1134 key
= radius_msg_get_vendor_attr(msg
, RADIUS_VENDOR_ID_MICROSOFT
,
1135 RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY
,
1138 keys
->recv
= decrypt_ms_key(key
, keylen
,
1139 sent_msg
->hdr
->authenticator
,
1143 wpa_printf(MSG_DEBUG
,
1144 "RADIUS: Failed to decrypt recv key");
1153 struct radius_ms_mppe_keys
*
1154 radius_msg_get_cisco_keys(struct radius_msg
*msg
, struct radius_msg
*sent_msg
,
1155 const u8
*secret
, size_t secret_len
)
1159 struct radius_ms_mppe_keys
*keys
;
1161 if (msg
== NULL
|| sent_msg
== NULL
)
1164 keys
= os_zalloc(sizeof(*keys
));
1168 key
= radius_msg_get_vendor_attr(msg
, RADIUS_VENDOR_ID_CISCO
,
1169 RADIUS_CISCO_AV_PAIR
, &keylen
);
1170 if (key
&& keylen
== 51 &&
1171 os_memcmp(key
, "leap:session-key=", 17) == 0) {
1172 keys
->recv
= decrypt_ms_key(key
+ 17, keylen
- 17,
1173 sent_msg
->hdr
->authenticator
,
1183 int radius_msg_add_mppe_keys(struct radius_msg
*msg
,
1184 const u8
*req_authenticator
,
1185 const u8
*secret
, size_t secret_len
,
1186 const u8
*send_key
, size_t send_key_len
,
1187 const u8
*recv_key
, size_t recv_key_len
)
1189 struct radius_attr_hdr
*attr
;
1190 u32 vendor_id
= htonl(RADIUS_VENDOR_ID_MICROSOFT
);
1192 struct radius_attr_vendor
*vhdr
;
1198 hlen
= sizeof(vendor_id
) + sizeof(*vhdr
) + 2;
1200 /* MS-MPPE-Send-Key */
1201 buf
= os_malloc(hlen
+ send_key_len
+ 16);
1206 os_memcpy(pos
, &vendor_id
, sizeof(vendor_id
));
1207 pos
+= sizeof(vendor_id
);
1208 vhdr
= (struct radius_attr_vendor
*) pos
;
1209 vhdr
->vendor_type
= RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY
;
1210 pos
= (u8
*) (vhdr
+ 1);
1211 if (os_get_random((u8
*) &salt
, sizeof(salt
)) < 0) {
1216 WPA_PUT_BE16(pos
, salt
);
1218 encrypt_ms_key(send_key
, send_key_len
, salt
, req_authenticator
, secret
,
1219 secret_len
, pos
, &elen
);
1220 vhdr
->vendor_length
= hlen
+ elen
- sizeof(vendor_id
);
1222 attr
= radius_msg_add_attr(msg
, RADIUS_ATTR_VENDOR_SPECIFIC
,
1229 /* MS-MPPE-Recv-Key */
1230 buf
= os_malloc(hlen
+ recv_key_len
+ 16);
1235 os_memcpy(pos
, &vendor_id
, sizeof(vendor_id
));
1236 pos
+= sizeof(vendor_id
);
1237 vhdr
= (struct radius_attr_vendor
*) pos
;
1238 vhdr
->vendor_type
= RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY
;
1239 pos
= (u8
*) (vhdr
+ 1);
1241 WPA_PUT_BE16(pos
, salt
);
1243 encrypt_ms_key(recv_key
, recv_key_len
, salt
, req_authenticator
, secret
,
1244 secret_len
, pos
, &elen
);
1245 vhdr
->vendor_length
= hlen
+ elen
- sizeof(vendor_id
);
1247 attr
= radius_msg_add_attr(msg
, RADIUS_ATTR_VENDOR_SPECIFIC
,
1258 int radius_msg_add_wfa(struct radius_msg
*msg
, u8 subtype
, const u8
*data
,
1261 struct radius_attr_hdr
*attr
;
1266 buf
= os_malloc(alen
);
1270 WPA_PUT_BE32(pos
, RADIUS_VENDOR_ID_WFA
);
1274 os_memcpy(pos
, data
, len
);
1275 attr
= radius_msg_add_attr(msg
, RADIUS_ATTR_VENDOR_SPECIFIC
,
1285 int radius_user_password_hide(struct radius_msg
*msg
,
1286 const u8
*data
, size_t data_len
,
1287 const u8
*secret
, size_t secret_len
,
1288 u8
*buf
, size_t buf_len
)
1290 size_t padlen
, i
, pos
;
1295 if (data_len
+ 16 > buf_len
)
1298 os_memcpy(buf
, data
, data_len
);
1300 padlen
= data_len
% 16;
1301 if (padlen
&& data_len
< buf_len
) {
1302 padlen
= 16 - padlen
;
1303 os_memset(buf
+ data_len
, 0, padlen
);
1304 buf_len
= data_len
+ padlen
;
1310 len
[0] = secret_len
;
1311 addr
[1] = msg
->hdr
->authenticator
;
1313 md5_vector(2, addr
, len
, hash
);
1315 for (i
= 0; i
< 16; i
++)
1319 while (pos
< buf_len
) {
1321 len
[0] = secret_len
;
1322 addr
[1] = &buf
[pos
- 16];
1324 md5_vector(2, addr
, len
, hash
);
1326 for (i
= 0; i
< 16; i
++)
1327 buf
[pos
+ i
] ^= hash
[i
];
1336 /* Add User-Password attribute to a RADIUS message and encrypt it as specified
1337 * in RFC 2865, Chap. 5.2 */
1338 struct radius_attr_hdr
*
1339 radius_msg_add_attr_user_password(struct radius_msg
*msg
,
1340 const u8
*data
, size_t data_len
,
1341 const u8
*secret
, size_t secret_len
)
1346 res
= radius_user_password_hide(msg
, data
, data_len
,
1347 secret
, secret_len
, buf
, sizeof(buf
));
1351 return radius_msg_add_attr(msg
, RADIUS_ATTR_USER_PASSWORD
,
1356 int radius_msg_get_attr(struct radius_msg
*msg
, u8 type
, u8
*buf
, size_t len
)
1358 struct radius_attr_hdr
*attr
= NULL
, *tmp
;
1361 for (i
= 0; i
< msg
->attr_used
; i
++) {
1362 tmp
= radius_get_attr_hdr(msg
, i
);
1363 if (tmp
->type
== type
) {
1369 if (!attr
|| attr
->length
< sizeof(*attr
))
1372 dlen
= attr
->length
- sizeof(*attr
);
1374 os_memcpy(buf
, (attr
+ 1), dlen
> len
? len
: dlen
);
1379 int radius_msg_get_attr_ptr(struct radius_msg
*msg
, u8 type
, u8
**buf
,
1380 size_t *len
, const u8
*start
)
1383 struct radius_attr_hdr
*attr
= NULL
, *tmp
;
1385 for (i
= 0; i
< msg
->attr_used
; i
++) {
1386 tmp
= radius_get_attr_hdr(msg
, i
);
1387 if (tmp
->type
== type
&&
1388 (start
== NULL
|| (u8
*) tmp
> start
)) {
1394 if (!attr
|| attr
->length
< sizeof(*attr
))
1397 *buf
= (u8
*) (attr
+ 1);
1398 *len
= attr
->length
- sizeof(*attr
);
1403 int radius_msg_count_attr(struct radius_msg
*msg
, u8 type
, int min_len
)
1408 for (count
= 0, i
= 0; i
< msg
->attr_used
; i
++) {
1409 struct radius_attr_hdr
*attr
= radius_get_attr_hdr(msg
, i
);
1410 if (attr
->type
== type
&&
1411 attr
->length
>= sizeof(struct radius_attr_hdr
) + min_len
)
1419 struct radius_tunnel_attrs
{
1421 int type
; /* Tunnel-Type */
1422 int medium_type
; /* Tunnel-Medium-Type */
1427 static int cmp_int(const void *a
, const void *b
)
1438 * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
1439 * The k tagged vlans found are sorted by vlan_id and stored in the first k
1442 * @msg: RADIUS message
1443 * @untagged: Pointer to store untagged vid
1444 * @numtagged: Size of tagged
1445 * @tagged: Pointer to store tagged list
1447 * Returns: 0 if neither tagged nor untagged configuration is found, 1 otherwise
1449 int radius_msg_get_vlanid(struct radius_msg
*msg
, int *untagged
, int numtagged
,
1452 struct radius_tunnel_attrs tunnel
[RADIUS_TUNNEL_TAGS
], *tun
;
1454 struct radius_attr_hdr
*attr
= NULL
;
1458 int j
, taggedidx
= 0, vlan_id
;
1460 os_memset(&tunnel
, 0, sizeof(tunnel
));
1461 for (j
= 0; j
< numtagged
; j
++)
1465 for (i
= 0; i
< msg
->attr_used
; i
++) {
1466 attr
= radius_get_attr_hdr(msg
, i
);
1467 if (attr
->length
< sizeof(*attr
))
1469 data
= (const u8
*) (attr
+ 1);
1470 dlen
= attr
->length
- sizeof(*attr
);
1471 if (attr
->length
< 3)
1473 if (data
[0] >= RADIUS_TUNNEL_TAGS
)
1476 tun
= &tunnel
[data
[0]];
1478 switch (attr
->type
) {
1479 case RADIUS_ATTR_TUNNEL_TYPE
:
1480 if (attr
->length
!= 6)
1483 tun
->type
= WPA_GET_BE24(data
+ 1);
1485 case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE
:
1486 if (attr
->length
!= 6)
1489 tun
->medium_type
= WPA_GET_BE24(data
+ 1);
1491 case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID
:
1492 if (data
[0] < RADIUS_TUNNEL_TAGS
) {
1496 if (dlen
>= sizeof(buf
))
1498 os_memcpy(buf
, data
, dlen
);
1500 vlan_id
= atoi(buf
);
1504 tun
->vlanid
= vlan_id
;
1506 case RADIUS_ATTR_EGRESS_VLANID
: /* RFC 4675 */
1507 if (attr
->length
!= 6)
1509 vlan_id
= WPA_GET_BE24(data
+ 1);
1512 if (data
[0] == 0x32)
1513 *untagged
= vlan_id
;
1514 else if (data
[0] == 0x31 && tagged
&&
1515 taggedidx
< numtagged
)
1516 tagged
[taggedidx
++] = vlan_id
;
1521 /* Use tunnel with the lowest tag for untagged VLAN id */
1522 for (i
= 0; i
< RADIUS_TUNNEL_TAGS
; i
++) {
1524 if (tun
->tag_used
&&
1525 tun
->type
== RADIUS_TUNNEL_TYPE_VLAN
&&
1526 tun
->medium_type
== RADIUS_TUNNEL_MEDIUM_TYPE_802
&&
1528 *untagged
= tun
->vlanid
;
1534 qsort(tagged
, taggedidx
, sizeof(int), cmp_int
);
1536 if (*untagged
> 0 || taggedidx
)
1543 * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password
1544 * @msg: Received RADIUS message
1545 * @keylen: Length of returned password
1546 * @secret: RADIUS shared secret
1547 * @secret_len: Length of secret
1548 * @sent_msg: Sent RADIUS message
1549 * @n: Number of password attribute to return (starting with 0)
1550 * Returns: Pointer to n-th password (free with os_free) or %NULL
1552 char * radius_msg_get_tunnel_password(struct radius_msg
*msg
, int *keylen
,
1553 const u8
*secret
, size_t secret_len
,
1554 struct radius_msg
*sent_msg
, size_t n
)
1565 struct radius_attr_hdr
*attr
;
1568 const u8
*fdata
= NULL
; /* points to found item */
1572 /* find n-th valid Tunnel-Password attribute */
1573 for (i
= 0; i
< msg
->attr_used
; i
++) {
1574 attr
= radius_get_attr_hdr(msg
, i
);
1576 attr
->type
!= RADIUS_ATTR_TUNNEL_PASSWORD
) {
1579 if (attr
->length
<= 5)
1581 data
= (const u8
*) (attr
+ 1);
1582 dlen
= attr
->length
- sizeof(*attr
);
1583 if (dlen
<= 3 || dlen
% 16 != 3)
1596 /* alloc writable memory for decryption */
1597 buf
= os_malloc(fdlen
);
1600 os_memcpy(buf
, fdata
, fdlen
);
1607 /* decrypt blocks */
1608 pos
= buf
+ buflen
- 16; /* last block */
1609 while (pos
>= str
+ 16) { /* all but the first block */
1611 len
[0] = secret_len
;
1614 md5_vector(2, addr
, len
, hash
);
1616 for (i
= 0; i
< 16; i
++)
1622 /* decrypt first block */
1626 len
[0] = secret_len
;
1627 addr
[1] = sent_msg
->hdr
->authenticator
;
1631 md5_vector(3, addr
, len
, hash
);
1633 for (i
= 0; i
< 16; i
++)
1636 /* derive plaintext length from first subfield */
1637 *keylen
= (unsigned char) str
[0];
1638 if ((u8
*) (str
+ *keylen
) >= (u8
*) (buf
+ buflen
)) {
1639 /* decryption error - invalid key length */
1643 /* empty password */
1647 /* copy passphrase into new buffer */
1648 ret
= os_malloc(*keylen
);
1650 os_memcpy(ret
, str
+ 1, *keylen
);
1653 /* return new buffer */
1659 void radius_free_class(struct radius_class_data
*c
)
1664 for (i
= 0; i
< c
->count
; i
++)
1665 os_free(c
->attr
[i
].data
);
1672 int radius_copy_class(struct radius_class_data
*dst
,
1673 const struct radius_class_data
*src
)
1677 if (src
->attr
== NULL
)
1680 dst
->attr
= os_calloc(src
->count
, sizeof(struct radius_attr_data
));
1681 if (dst
->attr
== NULL
)
1686 for (i
= 0; i
< src
->count
; i
++) {
1687 dst
->attr
[i
].data
= os_malloc(src
->attr
[i
].len
);
1688 if (dst
->attr
[i
].data
== NULL
)
1691 os_memcpy(dst
->attr
[i
].data
, src
->attr
[i
].data
,
1693 dst
->attr
[i
].len
= src
->attr
[i
].len
;
1700 u8
radius_msg_find_unlisted_attr(struct radius_msg
*msg
, u8
*attrs
)
1703 struct radius_attr_hdr
*attr
;
1705 for (i
= 0; i
< msg
->attr_used
; i
++) {
1706 attr
= radius_get_attr_hdr(msg
, i
);
1708 for (j
= 0; attrs
[j
]; j
++) {
1709 if (attr
->type
== attrs
[j
])
1714 return attr
->type
; /* unlisted attr */
1721 int radius_gen_session_id(u8
*id
, size_t len
)
1724 * Acct-Session-Id and Acct-Multi-Session-Id should be globally and
1725 * temporarily unique. A high quality random number is required
1726 * therefore. This could be be improved by switching to a GUID.
1728 return os_get_random(id
, len
);