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
, u8
*secret
, size_t secret_len
)
299 u8 auth
[MD5_MAC_LEN
];
300 struct radius_attr_hdr
*attr
;
302 os_memset(auth
, 0, MD5_MAC_LEN
);
303 attr
= radius_msg_add_attr(msg
,
304 RADIUS_ATTR_MESSAGE_AUTHENTICATOR
,
307 printf("WARNING: Could not add "
308 "Message-Authenticator\n");
311 msg
->hdr
->length
= htons(msg
->buf_used
);
312 hmac_md5(secret
, secret_len
, msg
->buf
, msg
->buf_used
,
315 msg
->hdr
->length
= htons(msg
->buf_used
);
317 if (msg
->buf_used
> 0xffff) {
318 printf("WARNING: too long RADIUS message (%lu)\n",
319 (unsigned long) msg
->buf_used
);
326 int radius_msg_finish_srv(struct radius_msg
*msg
, const u8
*secret
,
327 size_t secret_len
, const u8
*req_authenticator
)
329 u8 auth
[MD5_MAC_LEN
];
330 struct radius_attr_hdr
*attr
;
334 os_memset(auth
, 0, MD5_MAC_LEN
);
335 attr
= radius_msg_add_attr(msg
, RADIUS_ATTR_MESSAGE_AUTHENTICATOR
,
338 printf("WARNING: Could not add Message-Authenticator\n");
341 msg
->hdr
->length
= htons(msg
->buf_used
);
342 os_memcpy(msg
->hdr
->authenticator
, req_authenticator
,
343 sizeof(msg
->hdr
->authenticator
));
344 hmac_md5(secret
, secret_len
, msg
->buf
, msg
->buf_used
,
347 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
348 addr
[0] = (u8
*) msg
->hdr
;
350 addr
[1] = req_authenticator
;
351 len
[1] = MD5_MAC_LEN
;
352 addr
[2] = (u8
*) (msg
->hdr
+ 1);
353 len
[2] = msg
->buf_used
- sizeof(*msg
->hdr
);
356 md5_vector(4, addr
, len
, msg
->hdr
->authenticator
);
358 if (msg
->buf_used
> 0xffff) {
359 printf("WARNING: too long RADIUS message (%lu)\n",
360 (unsigned long) msg
->buf_used
);
367 void radius_msg_finish_acct(struct radius_msg
*msg
, u8
*secret
,
373 msg
->hdr
->length
= htons(msg
->buf_used
);
374 os_memset(msg
->hdr
->authenticator
, 0, MD5_MAC_LEN
);
376 len
[0] = msg
->buf_used
;
379 md5_vector(2, addr
, len
, msg
->hdr
->authenticator
);
381 if (msg
->buf_used
> 0xffff) {
382 printf("WARNING: too long RADIUS messages (%lu)\n",
383 (unsigned long) msg
->buf_used
);
388 static int radius_msg_add_attr_to_array(struct radius_msg
*msg
,
389 struct radius_attr_hdr
*attr
)
391 if (msg
->attr_used
>= msg
->attr_size
) {
393 int nlen
= msg
->attr_size
* 2;
395 nattr_pos
= os_realloc(msg
->attr_pos
,
396 nlen
* sizeof(*msg
->attr_pos
));
397 if (nattr_pos
== NULL
)
400 msg
->attr_pos
= nattr_pos
;
401 msg
->attr_size
= nlen
;
404 msg
->attr_pos
[msg
->attr_used
++] = (unsigned char *) attr
- msg
->buf
;
410 struct radius_attr_hdr
*radius_msg_add_attr(struct radius_msg
*msg
, u8 type
,
411 const u8
*data
, size_t data_len
)
414 struct radius_attr_hdr
*attr
;
416 if (data_len
> RADIUS_MAX_ATTR_LEN
) {
417 printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
418 (unsigned long) data_len
);
422 buf_needed
= msg
->buf_used
+ sizeof(*attr
) + data_len
;
424 if (msg
->buf_size
< buf_needed
) {
425 /* allocate more space for message buffer */
427 size_t nlen
= msg
->buf_size
;
429 while (nlen
< buf_needed
)
431 nbuf
= os_realloc(msg
->buf
, nlen
);
435 msg
->hdr
= (struct radius_hdr
*) msg
->buf
;
436 os_memset(msg
->buf
+ msg
->buf_size
, 0, nlen
- msg
->buf_size
);
437 msg
->buf_size
= nlen
;
440 attr
= (struct radius_attr_hdr
*) (msg
->buf
+ msg
->buf_used
);
442 attr
->length
= sizeof(*attr
) + data_len
;
444 os_memcpy(attr
+ 1, data
, data_len
);
446 msg
->buf_used
+= sizeof(*attr
) + data_len
;
448 if (radius_msg_add_attr_to_array(msg
, attr
))
455 struct radius_msg
*radius_msg_parse(const u8
*data
, size_t len
)
457 struct radius_msg
*msg
;
458 struct radius_hdr
*hdr
;
459 struct radius_attr_hdr
*attr
;
461 unsigned char *pos
, *end
;
463 if (data
== NULL
|| len
< sizeof(*hdr
))
466 hdr
= (struct radius_hdr
*) data
;
468 msg_len
= ntohs(hdr
->length
);
469 if (msg_len
< sizeof(*hdr
) || msg_len
> len
) {
470 printf("Invalid RADIUS message length\n");
475 printf("Ignored %lu extra bytes after RADIUS message\n",
476 (unsigned long) len
- msg_len
);
479 msg
= os_malloc(sizeof(*msg
));
483 if (radius_msg_initialize(msg
, msg_len
)) {
488 os_memcpy(msg
->buf
, data
, msg_len
);
489 msg
->buf_size
= msg
->buf_used
= msg_len
;
491 /* parse attributes */
492 pos
= (unsigned char *) (msg
->hdr
+ 1);
493 end
= msg
->buf
+ msg
->buf_used
;
495 if ((size_t) (end
- pos
) < sizeof(*attr
))
498 attr
= (struct radius_attr_hdr
*) pos
;
500 if (pos
+ attr
->length
> end
|| attr
->length
< sizeof(*attr
))
503 /* TODO: check that attr->length is suitable for attr->type */
505 if (radius_msg_add_attr_to_array(msg
, attr
))
514 radius_msg_free(msg
);
520 int radius_msg_add_eap(struct radius_msg
*msg
, const u8
*data
, size_t data_len
)
522 const u8
*pos
= data
;
523 size_t left
= data_len
;
527 if (left
> RADIUS_MAX_ATTR_LEN
)
528 len
= RADIUS_MAX_ATTR_LEN
;
532 if (!radius_msg_add_attr(msg
, RADIUS_ATTR_EAP_MESSAGE
,
544 u8
*radius_msg_get_eap(struct radius_msg
*msg
, size_t *eap_len
)
548 struct radius_attr_hdr
*attr
;
554 for (i
= 0; i
< msg
->attr_used
; i
++) {
555 attr
= radius_get_attr_hdr(msg
, i
);
556 if (attr
->type
== RADIUS_ATTR_EAP_MESSAGE
)
557 len
+= attr
->length
- sizeof(struct radius_attr_hdr
);
563 eap
= os_malloc(len
);
568 for (i
= 0; i
< msg
->attr_used
; i
++) {
569 attr
= radius_get_attr_hdr(msg
, i
);
570 if (attr
->type
== RADIUS_ATTR_EAP_MESSAGE
) {
571 int flen
= attr
->length
- sizeof(*attr
);
572 os_memcpy(pos
, attr
+ 1, flen
);
584 int radius_msg_verify_msg_auth(struct radius_msg
*msg
, const u8
*secret
,
585 size_t secret_len
, const u8
*req_auth
)
587 u8 auth
[MD5_MAC_LEN
], orig
[MD5_MAC_LEN
];
588 u8 orig_authenticator
[16];
589 struct radius_attr_hdr
*attr
= NULL
, *tmp
;
592 for (i
= 0; i
< msg
->attr_used
; i
++) {
593 tmp
= radius_get_attr_hdr(msg
, i
);
594 if (tmp
->type
== RADIUS_ATTR_MESSAGE_AUTHENTICATOR
) {
596 printf("Multiple Message-Authenticator "
597 "attributes in RADIUS message\n");
605 printf("No Message-Authenticator attribute found\n");
609 os_memcpy(orig
, attr
+ 1, MD5_MAC_LEN
);
610 os_memset(attr
+ 1, 0, MD5_MAC_LEN
);
612 os_memcpy(orig_authenticator
, msg
->hdr
->authenticator
,
613 sizeof(orig_authenticator
));
614 os_memcpy(msg
->hdr
->authenticator
, req_auth
,
615 sizeof(msg
->hdr
->authenticator
));
617 hmac_md5(secret
, secret_len
, msg
->buf
, msg
->buf_used
, auth
);
618 os_memcpy(attr
+ 1, orig
, MD5_MAC_LEN
);
620 os_memcpy(msg
->hdr
->authenticator
, orig_authenticator
,
621 sizeof(orig_authenticator
));
624 if (os_memcmp(orig
, auth
, MD5_MAC_LEN
) != 0) {
625 printf("Invalid Message-Authenticator!\n");
633 int radius_msg_verify(struct radius_msg
*msg
, const u8
*secret
,
634 size_t secret_len
, struct radius_msg
*sent_msg
, int auth
)
638 u8 hash
[MD5_MAC_LEN
];
640 if (sent_msg
== NULL
) {
641 printf("No matching Access-Request message found\n");
646 radius_msg_verify_msg_auth(msg
, secret
, secret_len
,
647 sent_msg
->hdr
->authenticator
)) {
651 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
652 addr
[0] = (u8
*) msg
->hdr
;
654 addr
[1] = sent_msg
->hdr
->authenticator
;
655 len
[1] = MD5_MAC_LEN
;
656 addr
[2] = (u8
*) (msg
->hdr
+ 1);
657 len
[2] = msg
->buf_used
- sizeof(*msg
->hdr
);
660 md5_vector(4, addr
, len
, hash
);
661 if (os_memcmp(hash
, msg
->hdr
->authenticator
, MD5_MAC_LEN
) != 0) {
662 printf("Response Authenticator invalid!\n");
670 int radius_msg_copy_attr(struct radius_msg
*dst
, struct radius_msg
*src
,
673 struct radius_attr_hdr
*attr
;
677 for (i
= 0; i
< src
->attr_used
; i
++) {
678 attr
= radius_get_attr_hdr(src
, i
);
679 if (attr
->type
== type
) {
680 if (!radius_msg_add_attr(dst
, type
, (u8
*) (attr
+ 1),
681 attr
->length
- sizeof(*attr
)))
691 /* Create Request Authenticator. The value should be unique over the lifetime
692 * of the shared secret between authenticator and authentication server.
693 * Use one-way MD5 hash calculated from current timestamp and some data given
695 void radius_msg_make_authenticator(struct radius_msg
*msg
,
696 const u8
*data
, size_t len
)
705 addr
[0] = (u8
*) &tv
;
706 elen
[0] = sizeof(tv
);
711 md5_vector(3, addr
, elen
, msg
->hdr
->authenticator
);
715 /* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
716 * Returns the Attribute payload and sets alen to indicate the length of the
717 * payload if a vendor attribute with subtype is found, otherwise returns NULL.
718 * The returned payload is allocated with os_malloc() and caller must free it
719 * by calling os_free().
721 static u8
*radius_msg_get_vendor_attr(struct radius_msg
*msg
, u32 vendor
,
722 u8 subtype
, size_t *alen
)
730 for (i
= 0; i
< msg
->attr_used
; i
++) {
731 struct radius_attr_hdr
*attr
= radius_get_attr_hdr(msg
, i
);
734 struct radius_attr_vendor
*vhdr
;
736 if (attr
->type
!= RADIUS_ATTR_VENDOR_SPECIFIC
)
739 left
= attr
->length
- sizeof(*attr
);
743 pos
= (u8
*) (attr
+ 1);
745 os_memcpy(&vendor_id
, pos
, 4);
749 if (ntohl(vendor_id
) != vendor
)
752 while (left
>= sizeof(*vhdr
)) {
753 vhdr
= (struct radius_attr_vendor
*) pos
;
754 if (vhdr
->vendor_length
> left
||
755 vhdr
->vendor_length
< sizeof(*vhdr
)) {
759 if (vhdr
->vendor_type
!= subtype
) {
760 pos
+= vhdr
->vendor_length
;
761 left
-= vhdr
->vendor_length
;
765 len
= vhdr
->vendor_length
- sizeof(*vhdr
);
766 data
= os_malloc(len
);
769 os_memcpy(data
, pos
+ sizeof(*vhdr
), len
);
780 static u8
* decrypt_ms_key(const u8
*key
, size_t len
,
781 const u8
*req_authenticator
,
782 const u8
*secret
, size_t secret_len
, size_t *reslen
)
784 u8
*plain
, *ppos
, *res
;
787 u8 hash
[MD5_MAC_LEN
];
792 /* key: 16-bit salt followed by encrypted key info */
800 printf("Invalid ms key len %lu\n", (unsigned long) left
);
805 ppos
= plain
= os_malloc(plen
);
811 /* b(1) = MD5(Secret + Request-Authenticator + Salt)
812 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
815 elen
[0] = secret_len
;
817 addr
[1] = req_authenticator
;
818 elen
[1] = MD5_MAC_LEN
;
820 elen
[2] = 2; /* Salt */
822 addr
[1] = pos
- MD5_MAC_LEN
;
823 elen
[1] = MD5_MAC_LEN
;
825 md5_vector(first
? 3 : 2, addr
, elen
, hash
);
828 for (i
= 0; i
< MD5_MAC_LEN
; i
++)
829 *ppos
++ = *pos
++ ^ hash
[i
];
833 if (plain
[0] == 0 || plain
[0] > plen
- 1) {
834 printf("Failed to decrypt MPPE key\n");
839 res
= os_malloc(plain
[0]);
844 os_memcpy(res
, plain
+ 1, plain
[0]);
852 static void encrypt_ms_key(const u8
*key
, size_t key_len
, u16 salt
,
853 const u8
*req_authenticator
,
854 const u8
*secret
, size_t secret_len
,
855 u8
*ebuf
, size_t *elen
)
857 int i
, len
, first
= 1;
858 u8 hash
[MD5_MAC_LEN
], saltbuf
[2], *pos
;
862 WPA_PUT_BE16(saltbuf
, salt
);
866 len
= (len
& 0xf0) + 16;
868 os_memset(ebuf
, 0, len
);
870 os_memcpy(ebuf
+ 1, key
, key_len
);
876 /* b(1) = MD5(Secret + Request-Authenticator + Salt)
877 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
879 _len
[0] = secret_len
;
881 addr
[1] = req_authenticator
;
882 _len
[1] = MD5_MAC_LEN
;
884 _len
[2] = sizeof(saltbuf
);
886 addr
[1] = pos
- MD5_MAC_LEN
;
887 _len
[1] = MD5_MAC_LEN
;
889 md5_vector(first
? 3 : 2, addr
, _len
, hash
);
892 for (i
= 0; i
< MD5_MAC_LEN
; i
++)
900 struct radius_ms_mppe_keys
*
901 radius_msg_get_ms_keys(struct radius_msg
*msg
, struct radius_msg
*sent_msg
,
902 u8
*secret
, size_t secret_len
)
906 struct radius_ms_mppe_keys
*keys
;
908 if (msg
== NULL
|| sent_msg
== NULL
)
911 keys
= os_zalloc(sizeof(*keys
));
915 key
= radius_msg_get_vendor_attr(msg
, RADIUS_VENDOR_ID_MICROSOFT
,
916 RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY
,
919 keys
->send
= decrypt_ms_key(key
, keylen
,
920 sent_msg
->hdr
->authenticator
,
926 key
= radius_msg_get_vendor_attr(msg
, RADIUS_VENDOR_ID_MICROSOFT
,
927 RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY
,
930 keys
->recv
= decrypt_ms_key(key
, keylen
,
931 sent_msg
->hdr
->authenticator
,
941 struct radius_ms_mppe_keys
*
942 radius_msg_get_cisco_keys(struct radius_msg
*msg
, struct radius_msg
*sent_msg
,
943 u8
*secret
, size_t secret_len
)
947 struct radius_ms_mppe_keys
*keys
;
949 if (msg
== NULL
|| sent_msg
== NULL
)
952 keys
= os_zalloc(sizeof(*keys
));
956 key
= radius_msg_get_vendor_attr(msg
, RADIUS_VENDOR_ID_CISCO
,
957 RADIUS_CISCO_AV_PAIR
, &keylen
);
958 if (key
&& keylen
== 51 &&
959 os_memcmp(key
, "leap:session-key=", 17) == 0) {
960 keys
->recv
= decrypt_ms_key(key
+ 17, keylen
- 17,
961 sent_msg
->hdr
->authenticator
,
971 int radius_msg_add_mppe_keys(struct radius_msg
*msg
,
972 const u8
*req_authenticator
,
973 const u8
*secret
, size_t secret_len
,
974 const u8
*send_key
, size_t send_key_len
,
975 const u8
*recv_key
, size_t recv_key_len
)
977 struct radius_attr_hdr
*attr
;
978 u32 vendor_id
= htonl(RADIUS_VENDOR_ID_MICROSOFT
);
980 struct radius_attr_vendor
*vhdr
;
986 hlen
= sizeof(vendor_id
) + sizeof(*vhdr
) + 2;
988 /* MS-MPPE-Send-Key */
989 buf
= os_malloc(hlen
+ send_key_len
+ 16);
994 os_memcpy(pos
, &vendor_id
, sizeof(vendor_id
));
995 pos
+= sizeof(vendor_id
);
996 vhdr
= (struct radius_attr_vendor
*) pos
;
997 vhdr
->vendor_type
= RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY
;
998 pos
= (u8
*) (vhdr
+ 1);
999 salt
= os_random() | 0x8000;
1000 WPA_PUT_BE16(pos
, salt
);
1002 encrypt_ms_key(send_key
, send_key_len
, salt
, req_authenticator
, secret
,
1003 secret_len
, pos
, &elen
);
1004 vhdr
->vendor_length
= hlen
+ elen
- sizeof(vendor_id
);
1006 attr
= radius_msg_add_attr(msg
, RADIUS_ATTR_VENDOR_SPECIFIC
,
1013 /* MS-MPPE-Recv-Key */
1014 buf
= os_malloc(hlen
+ send_key_len
+ 16);
1019 os_memcpy(pos
, &vendor_id
, sizeof(vendor_id
));
1020 pos
+= sizeof(vendor_id
);
1021 vhdr
= (struct radius_attr_vendor
*) pos
;
1022 vhdr
->vendor_type
= RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY
;
1023 pos
= (u8
*) (vhdr
+ 1);
1025 WPA_PUT_BE16(pos
, salt
);
1027 encrypt_ms_key(recv_key
, recv_key_len
, salt
, req_authenticator
, secret
,
1028 secret_len
, pos
, &elen
);
1029 vhdr
->vendor_length
= hlen
+ elen
- sizeof(vendor_id
);
1031 attr
= radius_msg_add_attr(msg
, RADIUS_ATTR_VENDOR_SPECIFIC
,
1042 /* Add User-Password attribute to a RADIUS message and encrypt it as specified
1043 * in RFC 2865, Chap. 5.2 */
1044 struct radius_attr_hdr
*
1045 radius_msg_add_attr_user_password(struct radius_msg
*msg
,
1046 u8
*data
, size_t data_len
,
1047 u8
*secret
, size_t secret_len
)
1051 size_t buf_len
, pos
;
1059 os_memcpy(buf
, data
, data_len
);
1062 padlen
= data_len
% 16;
1064 padlen
= 16 - padlen
;
1065 os_memset(buf
+ data_len
, 0, padlen
);
1070 len
[0] = secret_len
;
1071 addr
[1] = msg
->hdr
->authenticator
;
1073 md5_vector(2, addr
, len
, hash
);
1075 for (i
= 0; i
< 16; i
++)
1079 while (pos
< buf_len
) {
1081 len
[0] = secret_len
;
1082 addr
[1] = &buf
[pos
- 16];
1084 md5_vector(2, addr
, len
, hash
);
1086 for (i
= 0; i
< 16; i
++)
1087 buf
[pos
+ i
] ^= hash
[i
];
1092 return radius_msg_add_attr(msg
, RADIUS_ATTR_USER_PASSWORD
,
1097 int radius_msg_get_attr(struct radius_msg
*msg
, u8 type
, u8
*buf
, size_t len
)
1099 struct radius_attr_hdr
*attr
= NULL
, *tmp
;
1102 for (i
= 0; i
< msg
->attr_used
; i
++) {
1103 tmp
= radius_get_attr_hdr(msg
, i
);
1104 if (tmp
->type
== type
) {
1113 dlen
= attr
->length
- sizeof(*attr
);
1115 os_memcpy(buf
, (attr
+ 1), dlen
> len
? len
: dlen
);
1120 int radius_msg_get_attr_ptr(struct radius_msg
*msg
, u8 type
, u8
**buf
,
1121 size_t *len
, const u8
*start
)
1124 struct radius_attr_hdr
*attr
= NULL
, *tmp
;
1126 for (i
= 0; i
< msg
->attr_used
; i
++) {
1127 tmp
= radius_get_attr_hdr(msg
, i
);
1128 if (tmp
->type
== type
&&
1129 (start
== NULL
|| (u8
*) tmp
> start
)) {
1138 *buf
= (u8
*) (attr
+ 1);
1139 *len
= attr
->length
- sizeof(*attr
);
1144 int radius_msg_count_attr(struct radius_msg
*msg
, u8 type
, int min_len
)
1149 for (count
= 0, i
= 0; i
< msg
->attr_used
; i
++) {
1150 struct radius_attr_hdr
*attr
= radius_get_attr_hdr(msg
, i
);
1151 if (attr
->type
== type
&&
1152 attr
->length
>= sizeof(struct radius_attr_hdr
) + min_len
)
1160 struct radius_tunnel_attrs
{
1162 int type
; /* Tunnel-Type */
1163 int medium_type
; /* Tunnel-Medium-Type */
1169 * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
1170 * @msg: RADIUS message
1171 * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
1173 int radius_msg_get_vlanid(struct radius_msg
*msg
)
1175 struct radius_tunnel_attrs tunnel
[RADIUS_TUNNEL_TAGS
], *tun
;
1177 struct radius_attr_hdr
*attr
= NULL
;
1182 os_memset(&tunnel
, 0, sizeof(tunnel
));
1184 for (i
= 0; i
< msg
->attr_used
; i
++) {
1185 attr
= radius_get_attr_hdr(msg
, i
);
1186 data
= (const u8
*) (attr
+ 1);
1187 dlen
= attr
->length
- sizeof(*attr
);
1188 if (attr
->length
< 3)
1190 if (data
[0] >= RADIUS_TUNNEL_TAGS
)
1193 tun
= &tunnel
[data
[0]];
1195 switch (attr
->type
) {
1196 case RADIUS_ATTR_TUNNEL_TYPE
:
1197 if (attr
->length
!= 6)
1200 tun
->type
= WPA_GET_BE24(data
+ 1);
1202 case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE
:
1203 if (attr
->length
!= 6)
1206 tun
->medium_type
= WPA_GET_BE24(data
+ 1);
1208 case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID
:
1209 if (data
[0] < RADIUS_TUNNEL_TAGS
) {
1213 if (dlen
>= sizeof(buf
))
1215 os_memcpy(buf
, data
, dlen
);
1218 tun
->vlanid
= atoi(buf
);
1223 for (i
= 0; i
< RADIUS_TUNNEL_TAGS
; i
++) {
1225 if (tun
->tag_used
&&
1226 tun
->type
== RADIUS_TUNNEL_TYPE_VLAN
&&
1227 tun
->medium_type
== RADIUS_TUNNEL_MEDIUM_TYPE_802
&&