2 * hostapd / RADIUS message processing
3 * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
23 static struct radius_attr_hdr
*
24 radius_get_attr_hdr(struct radius_msg
*msg
, int idx
)
26 return (struct radius_attr_hdr
*) (msg
->buf
+ msg
->attr_pos
[idx
]);
30 struct radius_msg
*radius_msg_new(u8 code
, u8 identifier
)
32 struct radius_msg
*msg
;
34 msg
= os_malloc(sizeof(*msg
));
38 if (radius_msg_initialize(msg
, RADIUS_DEFAULT_MSG_SIZE
)) {
43 radius_msg_set_hdr(msg
, code
, identifier
);
49 int radius_msg_initialize(struct radius_msg
*msg
, size_t init_len
)
51 if (msg
== NULL
|| init_len
< sizeof(struct radius_hdr
))
54 os_memset(msg
, 0, sizeof(*msg
));
55 msg
->buf
= os_zalloc(init_len
);
59 msg
->buf_size
= init_len
;
60 msg
->hdr
= (struct radius_hdr
*) msg
->buf
;
61 msg
->buf_used
= sizeof(*msg
->hdr
);
64 os_zalloc(RADIUS_DEFAULT_ATTR_COUNT
* sizeof(*msg
->attr_pos
));
65 if (msg
->attr_pos
== NULL
) {
72 msg
->attr_size
= RADIUS_DEFAULT_ATTR_COUNT
;
79 void radius_msg_set_hdr(struct radius_msg
*msg
, u8 code
, u8 identifier
)
81 msg
->hdr
->code
= code
;
82 msg
->hdr
->identifier
= identifier
;
86 void radius_msg_free(struct radius_msg
*msg
)
91 msg
->buf_size
= msg
->buf_used
= 0;
93 os_free(msg
->attr_pos
);
95 msg
->attr_size
= msg
->attr_used
= 0;
99 static const char *radius_code_string(u8 code
)
102 case RADIUS_CODE_ACCESS_REQUEST
: return "Access-Request";
103 case RADIUS_CODE_ACCESS_ACCEPT
: return "Access-Accept";
104 case RADIUS_CODE_ACCESS_REJECT
: return "Access-Reject";
105 case RADIUS_CODE_ACCOUNTING_REQUEST
: return "Accounting-Request";
106 case RADIUS_CODE_ACCOUNTING_RESPONSE
: return "Accounting-Response";
107 case RADIUS_CODE_ACCESS_CHALLENGE
: return "Access-Challenge";
108 case RADIUS_CODE_STATUS_SERVER
: return "Status-Server";
109 case RADIUS_CODE_STATUS_CLIENT
: return "Status-Client";
110 case RADIUS_CODE_RESERVED
: return "Reserved";
111 default: return "?Unknown?";
116 struct radius_attr_type
{
120 RADIUS_ATTR_UNDIST
, RADIUS_ATTR_TEXT
, RADIUS_ATTR_IP
,
121 RADIUS_ATTR_HEXDUMP
, RADIUS_ATTR_INT32
, RADIUS_ATTR_IPV6
125 static struct radius_attr_type radius_attrs
[] =
127 { RADIUS_ATTR_USER_NAME
, "User-Name", RADIUS_ATTR_TEXT
},
128 { RADIUS_ATTR_USER_PASSWORD
, "User-Password", RADIUS_ATTR_UNDIST
},
129 { RADIUS_ATTR_NAS_IP_ADDRESS
, "NAS-IP-Address", RADIUS_ATTR_IP
},
130 { RADIUS_ATTR_NAS_PORT
, "NAS-Port", RADIUS_ATTR_INT32
},
131 { RADIUS_ATTR_FRAMED_MTU
, "Framed-MTU", RADIUS_ATTR_INT32
},
132 { RADIUS_ATTR_REPLY_MESSAGE
, "Reply-Message", RADIUS_ATTR_TEXT
},
133 { RADIUS_ATTR_STATE
, "State", RADIUS_ATTR_UNDIST
},
134 { RADIUS_ATTR_CLASS
, "Class", RADIUS_ATTR_UNDIST
},
135 { RADIUS_ATTR_VENDOR_SPECIFIC
, "Vendor-Specific", RADIUS_ATTR_UNDIST
},
136 { RADIUS_ATTR_SESSION_TIMEOUT
, "Session-Timeout", RADIUS_ATTR_INT32
},
137 { RADIUS_ATTR_IDLE_TIMEOUT
, "Idle-Timeout", RADIUS_ATTR_INT32
},
138 { RADIUS_ATTR_TERMINATION_ACTION
, "Termination-Action",
140 { RADIUS_ATTR_CALLED_STATION_ID
, "Called-Station-Id",
142 { RADIUS_ATTR_CALLING_STATION_ID
, "Calling-Station-Id",
144 { RADIUS_ATTR_NAS_IDENTIFIER
, "NAS-Identifier", RADIUS_ATTR_TEXT
},
145 { RADIUS_ATTR_PROXY_STATE
, "Proxy-State", RADIUS_ATTR_UNDIST
},
146 { RADIUS_ATTR_ACCT_STATUS_TYPE
, "Acct-Status-Type",
148 { RADIUS_ATTR_ACCT_DELAY_TIME
, "Acct-Delay-Time", RADIUS_ATTR_INT32
},
149 { RADIUS_ATTR_ACCT_INPUT_OCTETS
, "Acct-Input-Octets",
151 { RADIUS_ATTR_ACCT_OUTPUT_OCTETS
, "Acct-Output-Octets",
153 { RADIUS_ATTR_ACCT_SESSION_ID
, "Acct-Session-Id", RADIUS_ATTR_TEXT
},
154 { RADIUS_ATTR_ACCT_AUTHENTIC
, "Acct-Authentic", RADIUS_ATTR_INT32
},
155 { RADIUS_ATTR_ACCT_SESSION_TIME
, "Acct-Session-Time",
157 { RADIUS_ATTR_ACCT_INPUT_PACKETS
, "Acct-Input-Packets",
159 { RADIUS_ATTR_ACCT_OUTPUT_PACKETS
, "Acct-Output-Packets",
161 { RADIUS_ATTR_ACCT_TERMINATE_CAUSE
, "Acct-Terminate-Cause",
163 { RADIUS_ATTR_ACCT_MULTI_SESSION_ID
, "Acct-Multi-Session-Id",
165 { RADIUS_ATTR_ACCT_LINK_COUNT
, "Acct-Link-Count", RADIUS_ATTR_INT32
},
166 { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS
, "Acct-Input-Gigawords",
168 { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS
, "Acct-Output-Gigawords",
170 { RADIUS_ATTR_EVENT_TIMESTAMP
, "Event-Timestamp",
172 { RADIUS_ATTR_NAS_PORT_TYPE
, "NAS-Port-Type", RADIUS_ATTR_INT32
},
173 { RADIUS_ATTR_TUNNEL_TYPE
, "Tunnel-Type", RADIUS_ATTR_HEXDUMP
},
174 { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE
, "Tunnel-Medium-Type",
175 RADIUS_ATTR_HEXDUMP
},
176 { RADIUS_ATTR_CONNECT_INFO
, "Connect-Info", RADIUS_ATTR_TEXT
},
177 { RADIUS_ATTR_EAP_MESSAGE
, "EAP-Message", RADIUS_ATTR_UNDIST
},
178 { RADIUS_ATTR_MESSAGE_AUTHENTICATOR
, "Message-Authenticator",
179 RADIUS_ATTR_UNDIST
},
180 { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID
, "Tunnel-Private-Group-Id",
181 RADIUS_ATTR_HEXDUMP
},
182 { RADIUS_ATTR_ACCT_INTERIM_INTERVAL
, "Acct-Interim-Interval",
184 { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY
, "Chargable-User-Identity",
186 { RADIUS_ATTR_NAS_IPV6_ADDRESS
, "NAS-IPv6-Address", RADIUS_ATTR_IPV6
},
188 #define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
191 static struct radius_attr_type
*radius_get_attr_type(u8 type
)
195 for (i
= 0; i
< RADIUS_ATTRS
; i
++) {
196 if (type
== radius_attrs
[i
].type
)
197 return &radius_attrs
[i
];
204 static void print_char(char c
)
206 if (c
>= 32 && c
< 127)
213 static void radius_msg_dump_attr(struct radius_attr_hdr
*hdr
)
215 struct radius_attr_type
*attr
;
219 attr
= radius_get_attr_type(hdr
->type
);
221 printf(" Attribute %d (%s) length=%d\n",
222 hdr
->type
, attr
? attr
->name
: "?Unknown?", hdr
->length
);
227 len
= hdr
->length
- sizeof(struct radius_attr_hdr
);
228 pos
= (unsigned char *) (hdr
+ 1);
230 switch (attr
->data_type
) {
231 case RADIUS_ATTR_TEXT
:
233 for (i
= 0; i
< len
; i
++)
241 os_memcpy(&addr
, pos
, 4);
242 printf(" Value: %s\n", inet_ntoa(addr
));
244 printf(" Invalid IP address length %d\n", len
);
248 case RADIUS_ATTR_IPV6
:
252 struct in6_addr
*addr
= (struct in6_addr
*) pos
;
253 atxt
= inet_ntop(AF_INET6
, addr
, buf
, sizeof(buf
));
254 printf(" Value: %s\n", atxt
? atxt
: "?");
256 printf(" Invalid IPv6 address length %d\n", len
);
258 #endif /* CONFIG_IPV6 */
260 case RADIUS_ATTR_HEXDUMP
:
261 case RADIUS_ATTR_UNDIST
:
263 for (i
= 0; i
< len
; i
++)
264 printf(" %02x", pos
[i
]);
268 case RADIUS_ATTR_INT32
:
270 printf(" Value: %u\n", WPA_GET_BE32(pos
));
272 printf(" Invalid INT32 length %d\n", len
);
281 void radius_msg_dump(struct radius_msg
*msg
)
285 printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
286 msg
->hdr
->code
, radius_code_string(msg
->hdr
->code
),
287 msg
->hdr
->identifier
, ntohs(msg
->hdr
->length
));
289 for (i
= 0; i
< msg
->attr_used
; i
++) {
290 struct radius_attr_hdr
*attr
= radius_get_attr_hdr(msg
, i
);
291 radius_msg_dump_attr(attr
);
296 int radius_msg_finish(struct radius_msg
*msg
, const u8
*secret
,
300 u8 auth
[MD5_MAC_LEN
];
301 struct radius_attr_hdr
*attr
;
303 os_memset(auth
, 0, MD5_MAC_LEN
);
304 attr
= radius_msg_add_attr(msg
,
305 RADIUS_ATTR_MESSAGE_AUTHENTICATOR
,
308 printf("WARNING: Could not add "
309 "Message-Authenticator\n");
312 msg
->hdr
->length
= htons(msg
->buf_used
);
313 hmac_md5(secret
, secret_len
, msg
->buf
, msg
->buf_used
,
316 msg
->hdr
->length
= htons(msg
->buf_used
);
318 if (msg
->buf_used
> 0xffff) {
319 printf("WARNING: too long RADIUS message (%lu)\n",
320 (unsigned long) msg
->buf_used
);
327 int radius_msg_finish_srv(struct radius_msg
*msg
, const u8
*secret
,
328 size_t secret_len
, const u8
*req_authenticator
)
330 u8 auth
[MD5_MAC_LEN
];
331 struct radius_attr_hdr
*attr
;
335 os_memset(auth
, 0, MD5_MAC_LEN
);
336 attr
= radius_msg_add_attr(msg
, RADIUS_ATTR_MESSAGE_AUTHENTICATOR
,
339 printf("WARNING: Could not add Message-Authenticator\n");
342 msg
->hdr
->length
= htons(msg
->buf_used
);
343 os_memcpy(msg
->hdr
->authenticator
, req_authenticator
,
344 sizeof(msg
->hdr
->authenticator
));
345 hmac_md5(secret
, secret_len
, msg
->buf
, msg
->buf_used
,
348 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
349 addr
[0] = (u8
*) msg
->hdr
;
351 addr
[1] = req_authenticator
;
352 len
[1] = MD5_MAC_LEN
;
353 addr
[2] = (u8
*) (msg
->hdr
+ 1);
354 len
[2] = msg
->buf_used
- sizeof(*msg
->hdr
);
357 md5_vector(4, addr
, len
, msg
->hdr
->authenticator
);
359 if (msg
->buf_used
> 0xffff) {
360 printf("WARNING: too long RADIUS message (%lu)\n",
361 (unsigned long) msg
->buf_used
);
368 void radius_msg_finish_acct(struct radius_msg
*msg
, const u8
*secret
,
374 msg
->hdr
->length
= htons(msg
->buf_used
);
375 os_memset(msg
->hdr
->authenticator
, 0, MD5_MAC_LEN
);
377 len
[0] = msg
->buf_used
;
380 md5_vector(2, addr
, len
, msg
->hdr
->authenticator
);
382 if (msg
->buf_used
> 0xffff) {
383 printf("WARNING: too long RADIUS messages (%lu)\n",
384 (unsigned long) msg
->buf_used
);
389 static int radius_msg_add_attr_to_array(struct radius_msg
*msg
,
390 struct radius_attr_hdr
*attr
)
392 if (msg
->attr_used
>= msg
->attr_size
) {
394 int nlen
= msg
->attr_size
* 2;
396 nattr_pos
= os_realloc(msg
->attr_pos
,
397 nlen
* sizeof(*msg
->attr_pos
));
398 if (nattr_pos
== NULL
)
401 msg
->attr_pos
= nattr_pos
;
402 msg
->attr_size
= nlen
;
405 msg
->attr_pos
[msg
->attr_used
++] = (unsigned char *) attr
- msg
->buf
;
411 struct radius_attr_hdr
*radius_msg_add_attr(struct radius_msg
*msg
, u8 type
,
412 const u8
*data
, size_t data_len
)
415 struct radius_attr_hdr
*attr
;
417 if (data_len
> RADIUS_MAX_ATTR_LEN
) {
418 printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
419 (unsigned long) data_len
);
423 buf_needed
= msg
->buf_used
+ sizeof(*attr
) + data_len
;
425 if (msg
->buf_size
< buf_needed
) {
426 /* allocate more space for message buffer */
428 size_t nlen
= msg
->buf_size
;
430 while (nlen
< buf_needed
)
432 nbuf
= os_realloc(msg
->buf
, nlen
);
436 msg
->hdr
= (struct radius_hdr
*) msg
->buf
;
437 os_memset(msg
->buf
+ msg
->buf_size
, 0, nlen
- msg
->buf_size
);
438 msg
->buf_size
= nlen
;
441 attr
= (struct radius_attr_hdr
*) (msg
->buf
+ msg
->buf_used
);
443 attr
->length
= sizeof(*attr
) + data_len
;
445 os_memcpy(attr
+ 1, data
, data_len
);
447 msg
->buf_used
+= sizeof(*attr
) + data_len
;
449 if (radius_msg_add_attr_to_array(msg
, attr
))
456 struct radius_msg
*radius_msg_parse(const u8
*data
, size_t len
)
458 struct radius_msg
*msg
;
459 struct radius_hdr
*hdr
;
460 struct radius_attr_hdr
*attr
;
462 unsigned char *pos
, *end
;
464 if (data
== NULL
|| len
< sizeof(*hdr
))
467 hdr
= (struct radius_hdr
*) data
;
469 msg_len
= ntohs(hdr
->length
);
470 if (msg_len
< sizeof(*hdr
) || msg_len
> len
) {
471 printf("Invalid RADIUS message length\n");
476 printf("Ignored %lu extra bytes after RADIUS message\n",
477 (unsigned long) len
- msg_len
);
480 msg
= os_malloc(sizeof(*msg
));
484 if (radius_msg_initialize(msg
, msg_len
)) {
489 os_memcpy(msg
->buf
, data
, msg_len
);
490 msg
->buf_size
= msg
->buf_used
= msg_len
;
492 /* parse attributes */
493 pos
= (unsigned char *) (msg
->hdr
+ 1);
494 end
= msg
->buf
+ msg
->buf_used
;
496 if ((size_t) (end
- pos
) < sizeof(*attr
))
499 attr
= (struct radius_attr_hdr
*) pos
;
501 if (pos
+ attr
->length
> end
|| attr
->length
< sizeof(*attr
))
504 /* TODO: check that attr->length is suitable for attr->type */
506 if (radius_msg_add_attr_to_array(msg
, attr
))
515 radius_msg_free(msg
);
521 int radius_msg_add_eap(struct radius_msg
*msg
, const u8
*data
, size_t data_len
)
523 const u8
*pos
= data
;
524 size_t left
= data_len
;
528 if (left
> RADIUS_MAX_ATTR_LEN
)
529 len
= RADIUS_MAX_ATTR_LEN
;
533 if (!radius_msg_add_attr(msg
, RADIUS_ATTR_EAP_MESSAGE
,
545 u8
*radius_msg_get_eap(struct radius_msg
*msg
, size_t *eap_len
)
549 struct radius_attr_hdr
*attr
;
555 for (i
= 0; i
< msg
->attr_used
; i
++) {
556 attr
= radius_get_attr_hdr(msg
, i
);
557 if (attr
->type
== RADIUS_ATTR_EAP_MESSAGE
)
558 len
+= attr
->length
- sizeof(struct radius_attr_hdr
);
564 eap
= os_malloc(len
);
569 for (i
= 0; i
< msg
->attr_used
; i
++) {
570 attr
= radius_get_attr_hdr(msg
, i
);
571 if (attr
->type
== RADIUS_ATTR_EAP_MESSAGE
) {
572 int flen
= attr
->length
- sizeof(*attr
);
573 os_memcpy(pos
, attr
+ 1, flen
);
585 int radius_msg_verify_msg_auth(struct radius_msg
*msg
, const u8
*secret
,
586 size_t secret_len
, const u8
*req_auth
)
588 u8 auth
[MD5_MAC_LEN
], orig
[MD5_MAC_LEN
];
589 u8 orig_authenticator
[16];
590 struct radius_attr_hdr
*attr
= NULL
, *tmp
;
593 for (i
= 0; i
< msg
->attr_used
; i
++) {
594 tmp
= radius_get_attr_hdr(msg
, i
);
595 if (tmp
->type
== RADIUS_ATTR_MESSAGE_AUTHENTICATOR
) {
597 printf("Multiple Message-Authenticator "
598 "attributes in RADIUS message\n");
606 printf("No Message-Authenticator attribute found\n");
610 os_memcpy(orig
, attr
+ 1, MD5_MAC_LEN
);
611 os_memset(attr
+ 1, 0, MD5_MAC_LEN
);
613 os_memcpy(orig_authenticator
, msg
->hdr
->authenticator
,
614 sizeof(orig_authenticator
));
615 os_memcpy(msg
->hdr
->authenticator
, req_auth
,
616 sizeof(msg
->hdr
->authenticator
));
618 hmac_md5(secret
, secret_len
, msg
->buf
, msg
->buf_used
, auth
);
619 os_memcpy(attr
+ 1, orig
, MD5_MAC_LEN
);
621 os_memcpy(msg
->hdr
->authenticator
, orig_authenticator
,
622 sizeof(orig_authenticator
));
625 if (os_memcmp(orig
, auth
, MD5_MAC_LEN
) != 0) {
626 printf("Invalid Message-Authenticator!\n");
634 int radius_msg_verify(struct radius_msg
*msg
, const u8
*secret
,
635 size_t secret_len
, struct radius_msg
*sent_msg
, int auth
)
639 u8 hash
[MD5_MAC_LEN
];
641 if (sent_msg
== NULL
) {
642 printf("No matching Access-Request message found\n");
647 radius_msg_verify_msg_auth(msg
, secret
, secret_len
,
648 sent_msg
->hdr
->authenticator
)) {
652 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
653 addr
[0] = (u8
*) msg
->hdr
;
655 addr
[1] = sent_msg
->hdr
->authenticator
;
656 len
[1] = MD5_MAC_LEN
;
657 addr
[2] = (u8
*) (msg
->hdr
+ 1);
658 len
[2] = msg
->buf_used
- sizeof(*msg
->hdr
);
661 md5_vector(4, addr
, len
, hash
);
662 if (os_memcmp(hash
, msg
->hdr
->authenticator
, MD5_MAC_LEN
) != 0) {
663 printf("Response Authenticator invalid!\n");
671 int radius_msg_copy_attr(struct radius_msg
*dst
, struct radius_msg
*src
,
674 struct radius_attr_hdr
*attr
;
678 for (i
= 0; i
< src
->attr_used
; i
++) {
679 attr
= radius_get_attr_hdr(src
, i
);
680 if (attr
->type
== type
) {
681 if (!radius_msg_add_attr(dst
, type
, (u8
*) (attr
+ 1),
682 attr
->length
- sizeof(*attr
)))
692 /* Create Request Authenticator. The value should be unique over the lifetime
693 * of the shared secret between authenticator and authentication server.
694 * Use one-way MD5 hash calculated from current timestamp and some data given
696 void radius_msg_make_authenticator(struct radius_msg
*msg
,
697 const u8
*data
, size_t len
)
706 addr
[0] = (u8
*) &tv
;
707 elen
[0] = sizeof(tv
);
712 md5_vector(3, addr
, elen
, msg
->hdr
->authenticator
);
716 /* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
717 * Returns the Attribute payload and sets alen to indicate the length of the
718 * payload if a vendor attribute with subtype is found, otherwise returns NULL.
719 * The returned payload is allocated with os_malloc() and caller must free it
720 * by calling os_free().
722 static u8
*radius_msg_get_vendor_attr(struct radius_msg
*msg
, u32 vendor
,
723 u8 subtype
, size_t *alen
)
731 for (i
= 0; i
< msg
->attr_used
; i
++) {
732 struct radius_attr_hdr
*attr
= radius_get_attr_hdr(msg
, i
);
735 struct radius_attr_vendor
*vhdr
;
737 if (attr
->type
!= RADIUS_ATTR_VENDOR_SPECIFIC
)
740 left
= attr
->length
- sizeof(*attr
);
744 pos
= (u8
*) (attr
+ 1);
746 os_memcpy(&vendor_id
, pos
, 4);
750 if (ntohl(vendor_id
) != vendor
)
753 while (left
>= sizeof(*vhdr
)) {
754 vhdr
= (struct radius_attr_vendor
*) pos
;
755 if (vhdr
->vendor_length
> left
||
756 vhdr
->vendor_length
< sizeof(*vhdr
)) {
760 if (vhdr
->vendor_type
!= subtype
) {
761 pos
+= vhdr
->vendor_length
;
762 left
-= vhdr
->vendor_length
;
766 len
= vhdr
->vendor_length
- sizeof(*vhdr
);
767 data
= os_malloc(len
);
770 os_memcpy(data
, pos
+ sizeof(*vhdr
), len
);
781 static u8
* decrypt_ms_key(const u8
*key
, size_t len
,
782 const u8
*req_authenticator
,
783 const u8
*secret
, size_t secret_len
, size_t *reslen
)
785 u8
*plain
, *ppos
, *res
;
788 u8 hash
[MD5_MAC_LEN
];
793 /* key: 16-bit salt followed by encrypted key info */
801 printf("Invalid ms key len %lu\n", (unsigned long) left
);
806 ppos
= plain
= os_malloc(plen
);
812 /* b(1) = MD5(Secret + Request-Authenticator + Salt)
813 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
816 elen
[0] = secret_len
;
818 addr
[1] = req_authenticator
;
819 elen
[1] = MD5_MAC_LEN
;
821 elen
[2] = 2; /* Salt */
823 addr
[1] = pos
- MD5_MAC_LEN
;
824 elen
[1] = MD5_MAC_LEN
;
826 md5_vector(first
? 3 : 2, addr
, elen
, hash
);
829 for (i
= 0; i
< MD5_MAC_LEN
; i
++)
830 *ppos
++ = *pos
++ ^ hash
[i
];
834 if (plain
[0] == 0 || plain
[0] > plen
- 1) {
835 printf("Failed to decrypt MPPE key\n");
840 res
= os_malloc(plain
[0]);
845 os_memcpy(res
, plain
+ 1, plain
[0]);
853 static void encrypt_ms_key(const u8
*key
, size_t key_len
, u16 salt
,
854 const u8
*req_authenticator
,
855 const u8
*secret
, size_t secret_len
,
856 u8
*ebuf
, size_t *elen
)
858 int i
, len
, first
= 1;
859 u8 hash
[MD5_MAC_LEN
], saltbuf
[2], *pos
;
863 WPA_PUT_BE16(saltbuf
, salt
);
867 len
= (len
& 0xf0) + 16;
869 os_memset(ebuf
, 0, len
);
871 os_memcpy(ebuf
+ 1, key
, key_len
);
877 /* b(1) = MD5(Secret + Request-Authenticator + Salt)
878 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
880 _len
[0] = secret_len
;
882 addr
[1] = req_authenticator
;
883 _len
[1] = MD5_MAC_LEN
;
885 _len
[2] = sizeof(saltbuf
);
887 addr
[1] = pos
- MD5_MAC_LEN
;
888 _len
[1] = MD5_MAC_LEN
;
890 md5_vector(first
? 3 : 2, addr
, _len
, hash
);
893 for (i
= 0; i
< MD5_MAC_LEN
; i
++)
901 struct radius_ms_mppe_keys
*
902 radius_msg_get_ms_keys(struct radius_msg
*msg
, struct radius_msg
*sent_msg
,
903 const u8
*secret
, size_t secret_len
)
907 struct radius_ms_mppe_keys
*keys
;
909 if (msg
== NULL
|| sent_msg
== NULL
)
912 keys
= os_zalloc(sizeof(*keys
));
916 key
= radius_msg_get_vendor_attr(msg
, RADIUS_VENDOR_ID_MICROSOFT
,
917 RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY
,
920 keys
->send
= decrypt_ms_key(key
, keylen
,
921 sent_msg
->hdr
->authenticator
,
927 key
= radius_msg_get_vendor_attr(msg
, RADIUS_VENDOR_ID_MICROSOFT
,
928 RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY
,
931 keys
->recv
= decrypt_ms_key(key
, keylen
,
932 sent_msg
->hdr
->authenticator
,
942 struct radius_ms_mppe_keys
*
943 radius_msg_get_cisco_keys(struct radius_msg
*msg
, struct radius_msg
*sent_msg
,
944 const u8
*secret
, size_t secret_len
)
948 struct radius_ms_mppe_keys
*keys
;
950 if (msg
== NULL
|| sent_msg
== NULL
)
953 keys
= os_zalloc(sizeof(*keys
));
957 key
= radius_msg_get_vendor_attr(msg
, RADIUS_VENDOR_ID_CISCO
,
958 RADIUS_CISCO_AV_PAIR
, &keylen
);
959 if (key
&& keylen
== 51 &&
960 os_memcmp(key
, "leap:session-key=", 17) == 0) {
961 keys
->recv
= decrypt_ms_key(key
+ 17, keylen
- 17,
962 sent_msg
->hdr
->authenticator
,
972 int radius_msg_add_mppe_keys(struct radius_msg
*msg
,
973 const u8
*req_authenticator
,
974 const u8
*secret
, size_t secret_len
,
975 const u8
*send_key
, size_t send_key_len
,
976 const u8
*recv_key
, size_t recv_key_len
)
978 struct radius_attr_hdr
*attr
;
979 u32 vendor_id
= htonl(RADIUS_VENDOR_ID_MICROSOFT
);
981 struct radius_attr_vendor
*vhdr
;
987 hlen
= sizeof(vendor_id
) + sizeof(*vhdr
) + 2;
989 /* MS-MPPE-Send-Key */
990 buf
= os_malloc(hlen
+ send_key_len
+ 16);
995 os_memcpy(pos
, &vendor_id
, sizeof(vendor_id
));
996 pos
+= sizeof(vendor_id
);
997 vhdr
= (struct radius_attr_vendor
*) pos
;
998 vhdr
->vendor_type
= RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY
;
999 pos
= (u8
*) (vhdr
+ 1);
1000 salt
= os_random() | 0x8000;
1001 WPA_PUT_BE16(pos
, salt
);
1003 encrypt_ms_key(send_key
, send_key_len
, salt
, req_authenticator
, secret
,
1004 secret_len
, pos
, &elen
);
1005 vhdr
->vendor_length
= hlen
+ elen
- sizeof(vendor_id
);
1007 attr
= radius_msg_add_attr(msg
, RADIUS_ATTR_VENDOR_SPECIFIC
,
1014 /* MS-MPPE-Recv-Key */
1015 buf
= os_malloc(hlen
+ send_key_len
+ 16);
1020 os_memcpy(pos
, &vendor_id
, sizeof(vendor_id
));
1021 pos
+= sizeof(vendor_id
);
1022 vhdr
= (struct radius_attr_vendor
*) pos
;
1023 vhdr
->vendor_type
= RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY
;
1024 pos
= (u8
*) (vhdr
+ 1);
1026 WPA_PUT_BE16(pos
, salt
);
1028 encrypt_ms_key(recv_key
, recv_key_len
, salt
, req_authenticator
, secret
,
1029 secret_len
, pos
, &elen
);
1030 vhdr
->vendor_length
= hlen
+ elen
- sizeof(vendor_id
);
1032 attr
= radius_msg_add_attr(msg
, RADIUS_ATTR_VENDOR_SPECIFIC
,
1043 /* Add User-Password attribute to a RADIUS message and encrypt it as specified
1044 * in RFC 2865, Chap. 5.2 */
1045 struct radius_attr_hdr
*
1046 radius_msg_add_attr_user_password(struct radius_msg
*msg
,
1047 const u8
*data
, size_t data_len
,
1048 const u8
*secret
, size_t secret_len
)
1052 size_t buf_len
, pos
;
1060 os_memcpy(buf
, data
, data_len
);
1063 padlen
= data_len
% 16;
1065 padlen
= 16 - padlen
;
1066 os_memset(buf
+ data_len
, 0, padlen
);
1071 len
[0] = secret_len
;
1072 addr
[1] = msg
->hdr
->authenticator
;
1074 md5_vector(2, addr
, len
, hash
);
1076 for (i
= 0; i
< 16; i
++)
1080 while (pos
< buf_len
) {
1082 len
[0] = secret_len
;
1083 addr
[1] = &buf
[pos
- 16];
1085 md5_vector(2, addr
, len
, hash
);
1087 for (i
= 0; i
< 16; i
++)
1088 buf
[pos
+ i
] ^= hash
[i
];
1093 return radius_msg_add_attr(msg
, RADIUS_ATTR_USER_PASSWORD
,
1098 int radius_msg_get_attr(struct radius_msg
*msg
, u8 type
, u8
*buf
, size_t len
)
1100 struct radius_attr_hdr
*attr
= NULL
, *tmp
;
1103 for (i
= 0; i
< msg
->attr_used
; i
++) {
1104 tmp
= radius_get_attr_hdr(msg
, i
);
1105 if (tmp
->type
== type
) {
1114 dlen
= attr
->length
- sizeof(*attr
);
1116 os_memcpy(buf
, (attr
+ 1), dlen
> len
? len
: dlen
);
1121 int radius_msg_get_attr_ptr(struct radius_msg
*msg
, u8 type
, u8
**buf
,
1122 size_t *len
, const u8
*start
)
1125 struct radius_attr_hdr
*attr
= NULL
, *tmp
;
1127 for (i
= 0; i
< msg
->attr_used
; i
++) {
1128 tmp
= radius_get_attr_hdr(msg
, i
);
1129 if (tmp
->type
== type
&&
1130 (start
== NULL
|| (u8
*) tmp
> start
)) {
1139 *buf
= (u8
*) (attr
+ 1);
1140 *len
= attr
->length
- sizeof(*attr
);
1145 int radius_msg_count_attr(struct radius_msg
*msg
, u8 type
, int min_len
)
1150 for (count
= 0, i
= 0; i
< msg
->attr_used
; i
++) {
1151 struct radius_attr_hdr
*attr
= radius_get_attr_hdr(msg
, i
);
1152 if (attr
->type
== type
&&
1153 attr
->length
>= sizeof(struct radius_attr_hdr
) + min_len
)
1161 struct radius_tunnel_attrs
{
1163 int type
; /* Tunnel-Type */
1164 int medium_type
; /* Tunnel-Medium-Type */
1170 * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
1171 * @msg: RADIUS message
1172 * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
1174 int radius_msg_get_vlanid(struct radius_msg
*msg
)
1176 struct radius_tunnel_attrs tunnel
[RADIUS_TUNNEL_TAGS
], *tun
;
1178 struct radius_attr_hdr
*attr
= NULL
;
1183 os_memset(&tunnel
, 0, sizeof(tunnel
));
1185 for (i
= 0; i
< msg
->attr_used
; i
++) {
1186 attr
= radius_get_attr_hdr(msg
, i
);
1187 data
= (const u8
*) (attr
+ 1);
1188 dlen
= attr
->length
- sizeof(*attr
);
1189 if (attr
->length
< 3)
1191 if (data
[0] >= RADIUS_TUNNEL_TAGS
)
1194 tun
= &tunnel
[data
[0]];
1196 switch (attr
->type
) {
1197 case RADIUS_ATTR_TUNNEL_TYPE
:
1198 if (attr
->length
!= 6)
1201 tun
->type
= WPA_GET_BE24(data
+ 1);
1203 case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE
:
1204 if (attr
->length
!= 6)
1207 tun
->medium_type
= WPA_GET_BE24(data
+ 1);
1209 case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID
:
1210 if (data
[0] < RADIUS_TUNNEL_TAGS
) {
1214 if (dlen
>= sizeof(buf
))
1216 os_memcpy(buf
, data
, dlen
);
1219 tun
->vlanid
= atoi(buf
);
1224 for (i
= 0; i
< RADIUS_TUNNEL_TAGS
; i
++) {
1226 if (tun
->tag_used
&&
1227 tun
->type
== RADIUS_TUNNEL_TYPE_VLAN
&&
1228 tun
->medium_type
== RADIUS_TUNNEL_MEDIUM_TYPE_802
&&