2 * hostapd / RADIUS message processing
3 * Copyright (c) 2002-2005, 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 struct radius_msg
*radius_msg_new(u8 code
, u8 identifier
)
25 struct radius_msg
*msg
;
27 msg
= os_malloc(sizeof(*msg
));
31 if (radius_msg_initialize(msg
, RADIUS_DEFAULT_MSG_SIZE
)) {
36 radius_msg_set_hdr(msg
, code
, identifier
);
42 int radius_msg_initialize(struct radius_msg
*msg
, size_t init_len
)
44 if (msg
== NULL
|| init_len
< sizeof(struct radius_hdr
))
47 os_memset(msg
, 0, sizeof(*msg
));
48 msg
->buf
= wpa_zalloc(init_len
);
52 msg
->buf_size
= init_len
;
53 msg
->hdr
= (struct radius_hdr
*) msg
->buf
;
54 msg
->buf_used
= sizeof(*msg
->hdr
);
57 os_malloc(RADIUS_DEFAULT_ATTR_COUNT
* sizeof(*msg
->attrs
));
58 if (msg
->attrs
== NULL
) {
65 msg
->attr_size
= RADIUS_DEFAULT_ATTR_COUNT
;
72 void radius_msg_set_hdr(struct radius_msg
*msg
, u8 code
, u8 identifier
)
74 msg
->hdr
->code
= code
;
75 msg
->hdr
->identifier
= identifier
;
79 void radius_msg_free(struct radius_msg
*msg
)
81 if (msg
->buf
!= NULL
) {
86 msg
->buf_size
= msg
->buf_used
= 0;
88 if (msg
->attrs
!= NULL
) {
92 msg
->attr_size
= msg
->attr_used
= 0;
96 static const char *radius_code_string(u8 code
)
99 case RADIUS_CODE_ACCESS_REQUEST
: return "Access-Request";
100 case RADIUS_CODE_ACCESS_ACCEPT
: return "Access-Accept";
101 case RADIUS_CODE_ACCESS_REJECT
: return "Access-Reject";
102 case RADIUS_CODE_ACCOUNTING_REQUEST
: return "Accounting-Request";
103 case RADIUS_CODE_ACCOUNTING_RESPONSE
: return "Accounting-Response";
104 case RADIUS_CODE_ACCESS_CHALLENGE
: return "Access-Challenge";
105 case RADIUS_CODE_STATUS_SERVER
: return "Status-Server";
106 case RADIUS_CODE_STATUS_CLIENT
: return "Status-Client";
107 case RADIUS_CODE_RESERVED
: return "Reserved";
108 default: return "?Unknown?";
113 struct radius_attr_type
{
117 RADIUS_ATTR_UNDIST
, RADIUS_ATTR_TEXT
, RADIUS_ATTR_IP
,
118 RADIUS_ATTR_HEXDUMP
, RADIUS_ATTR_INT32
, RADIUS_ATTR_IPV6
122 static struct radius_attr_type radius_attrs
[] =
124 { RADIUS_ATTR_USER_NAME
, "User-Name", RADIUS_ATTR_TEXT
},
125 { RADIUS_ATTR_USER_PASSWORD
, "User-Password", RADIUS_ATTR_UNDIST
},
126 { RADIUS_ATTR_NAS_IP_ADDRESS
, "NAS-IP-Address", RADIUS_ATTR_IP
},
127 { RADIUS_ATTR_NAS_PORT
, "NAS-Port", RADIUS_ATTR_INT32
},
128 { RADIUS_ATTR_FRAMED_MTU
, "Framed-MTU", RADIUS_ATTR_INT32
},
129 { RADIUS_ATTR_STATE
, "State", RADIUS_ATTR_UNDIST
},
130 { RADIUS_ATTR_CLASS
, "Class", RADIUS_ATTR_UNDIST
},
131 { RADIUS_ATTR_VENDOR_SPECIFIC
, "Vendor-Specific", RADIUS_ATTR_UNDIST
},
132 { RADIUS_ATTR_SESSION_TIMEOUT
, "Session-Timeout", RADIUS_ATTR_INT32
},
133 { RADIUS_ATTR_IDLE_TIMEOUT
, "Idle-Timeout", RADIUS_ATTR_INT32
},
134 { RADIUS_ATTR_TERMINATION_ACTION
, "Termination-Action",
136 { RADIUS_ATTR_CALLED_STATION_ID
, "Called-Station-Id",
138 { RADIUS_ATTR_CALLING_STATION_ID
, "Calling-Station-Id",
140 { RADIUS_ATTR_NAS_IDENTIFIER
, "NAS-Identifier", RADIUS_ATTR_TEXT
},
141 { RADIUS_ATTR_ACCT_STATUS_TYPE
, "Acct-Status-Type",
143 { RADIUS_ATTR_ACCT_DELAY_TIME
, "Acct-Delay-Time", RADIUS_ATTR_INT32
},
144 { RADIUS_ATTR_ACCT_INPUT_OCTETS
, "Acct-Input-Octets",
146 { RADIUS_ATTR_ACCT_OUTPUT_OCTETS
, "Acct-Output-Octets",
148 { RADIUS_ATTR_ACCT_SESSION_ID
, "Acct-Session-Id", RADIUS_ATTR_TEXT
},
149 { RADIUS_ATTR_ACCT_AUTHENTIC
, "Acct-Authentic", RADIUS_ATTR_INT32
},
150 { RADIUS_ATTR_ACCT_SESSION_TIME
, "Acct-Session-Time",
152 { RADIUS_ATTR_ACCT_INPUT_PACKETS
, "Acct-Input-Packets",
154 { RADIUS_ATTR_ACCT_OUTPUT_PACKETS
, "Acct-Output-Packets",
156 { RADIUS_ATTR_ACCT_TERMINATE_CAUSE
, "Acct-Terminate-Cause",
158 { RADIUS_ATTR_ACCT_MULTI_SESSION_ID
, "Acct-Multi-Session-Id",
160 { RADIUS_ATTR_ACCT_LINK_COUNT
, "Acct-Link-Count", RADIUS_ATTR_INT32
},
161 { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS
, "Acct-Input-Gigawords",
163 { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS
, "Acct-Output-Gigawords",
165 { RADIUS_ATTR_EVENT_TIMESTAMP
, "Event-Timestamp",
167 { RADIUS_ATTR_NAS_PORT_TYPE
, "NAS-Port-Type", RADIUS_ATTR_INT32
},
168 { RADIUS_ATTR_TUNNEL_TYPE
, "Tunnel-Type", RADIUS_ATTR_HEXDUMP
},
169 { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE
, "Tunnel-Medium-Type",
170 RADIUS_ATTR_HEXDUMP
},
171 { RADIUS_ATTR_CONNECT_INFO
, "Connect-Info", RADIUS_ATTR_TEXT
},
172 { RADIUS_ATTR_EAP_MESSAGE
, "EAP-Message", RADIUS_ATTR_UNDIST
},
173 { RADIUS_ATTR_MESSAGE_AUTHENTICATOR
, "Message-Authenticator",
174 RADIUS_ATTR_UNDIST
},
175 { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID
, "Tunnel-Private-Group-Id",
176 RADIUS_ATTR_HEXDUMP
},
177 { RADIUS_ATTR_ACCT_INTERIM_INTERVAL
, "Acct-Interim-Interval",
179 { RADIUS_ATTR_NAS_IPV6_ADDRESS
, "NAS-IPv6-Address", RADIUS_ATTR_IPV6
},
181 #define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
184 static struct radius_attr_type
*radius_get_attr_type(u8 type
)
188 for (i
= 0; i
< RADIUS_ATTRS
; i
++) {
189 if (type
== radius_attrs
[i
].type
)
190 return &radius_attrs
[i
];
197 static void print_char(char c
)
199 if (c
>= 32 && c
< 127)
206 static void radius_msg_dump_attr(struct radius_attr_hdr
*hdr
)
208 struct radius_attr_type
*attr
;
212 attr
= radius_get_attr_type(hdr
->type
);
214 printf(" Attribute %d (%s) length=%d\n",
215 hdr
->type
, attr
? attr
->name
: "?Unknown?", hdr
->length
);
220 len
= hdr
->length
- sizeof(struct radius_attr_hdr
);
221 pos
= (unsigned char *) (hdr
+ 1);
223 switch (attr
->data_type
) {
224 case RADIUS_ATTR_TEXT
:
226 for (i
= 0; i
< len
; i
++)
233 struct in_addr
*addr
= (struct in_addr
*) pos
;
234 printf(" Value: %s\n", inet_ntoa(*addr
));
236 printf(" Invalid IP address length %d\n", len
);
240 case RADIUS_ATTR_IPV6
:
244 struct in6_addr
*addr
= (struct in6_addr
*) pos
;
245 atxt
= inet_ntop(AF_INET6
, addr
, buf
, sizeof(buf
));
246 printf(" Value: %s\n", atxt
? atxt
: "?");
248 printf(" Invalid IPv6 address length %d\n", len
);
250 #endif /* CONFIG_IPV6 */
252 case RADIUS_ATTR_HEXDUMP
:
253 case RADIUS_ATTR_UNDIST
:
255 for (i
= 0; i
< len
; i
++)
256 printf(" %02x", pos
[i
]);
260 case RADIUS_ATTR_INT32
:
262 printf(" Value: %u\n", WPA_GET_BE32(pos
));
264 printf(" Invalid INT32 length %d\n", len
);
273 void radius_msg_dump(struct radius_msg
*msg
)
277 printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
278 msg
->hdr
->code
, radius_code_string(msg
->hdr
->code
),
279 msg
->hdr
->identifier
, ntohs(msg
->hdr
->length
));
281 for (i
= 0; i
< msg
->attr_used
; i
++) {
282 radius_msg_dump_attr(msg
->attrs
[i
]);
287 int radius_msg_finish(struct radius_msg
*msg
, u8
*secret
, size_t secret_len
)
290 u8 auth
[MD5_MAC_LEN
];
291 struct radius_attr_hdr
*attr
;
293 os_memset(auth
, 0, MD5_MAC_LEN
);
294 attr
= radius_msg_add_attr(msg
,
295 RADIUS_ATTR_MESSAGE_AUTHENTICATOR
,
298 printf("WARNING: Could not add "
299 "Message-Authenticator\n");
302 msg
->hdr
->length
= htons(msg
->buf_used
);
303 hmac_md5(secret
, secret_len
, msg
->buf
, msg
->buf_used
,
306 msg
->hdr
->length
= htons(msg
->buf_used
);
308 if (msg
->buf_used
> 0xffff) {
309 printf("WARNING: too long RADIUS message (%lu)\n",
310 (unsigned long) msg
->buf_used
);
317 int radius_msg_finish_srv(struct radius_msg
*msg
, const u8
*secret
,
318 size_t secret_len
, const u8
*req_authenticator
)
320 u8 auth
[MD5_MAC_LEN
];
321 struct radius_attr_hdr
*attr
;
325 os_memset(auth
, 0, MD5_MAC_LEN
);
326 attr
= radius_msg_add_attr(msg
, RADIUS_ATTR_MESSAGE_AUTHENTICATOR
,
329 printf("WARNING: Could not add Message-Authenticator\n");
332 msg
->hdr
->length
= htons(msg
->buf_used
);
333 os_memcpy(msg
->hdr
->authenticator
, req_authenticator
,
334 sizeof(msg
->hdr
->authenticator
));
335 hmac_md5(secret
, secret_len
, msg
->buf
, msg
->buf_used
,
338 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
339 addr
[0] = (u8
*) msg
->hdr
;
341 addr
[1] = req_authenticator
;
342 len
[1] = MD5_MAC_LEN
;
343 addr
[2] = (u8
*) (msg
->hdr
+ 1);
344 len
[2] = msg
->buf_used
- sizeof(*msg
->hdr
);
347 md5_vector(4, addr
, len
, msg
->hdr
->authenticator
);
349 if (msg
->buf_used
> 0xffff) {
350 printf("WARNING: too long RADIUS message (%lu)\n",
351 (unsigned long) msg
->buf_used
);
358 void radius_msg_finish_acct(struct radius_msg
*msg
, u8
*secret
,
364 msg
->hdr
->length
= htons(msg
->buf_used
);
365 os_memset(msg
->hdr
->authenticator
, 0, MD5_MAC_LEN
);
367 len
[0] = msg
->buf_used
;
370 md5_vector(2, addr
, len
, msg
->hdr
->authenticator
);
372 if (msg
->buf_used
> 0xffff) {
373 printf("WARNING: too long RADIUS messages (%lu)\n",
374 (unsigned long) msg
->buf_used
);
379 static int radius_msg_add_attr_to_array(struct radius_msg
*msg
,
380 struct radius_attr_hdr
*attr
)
382 if (msg
->attr_used
>= msg
->attr_size
) {
383 struct radius_attr_hdr
**nattrs
;
384 int nlen
= msg
->attr_size
* 2;
386 nattrs
= os_realloc(msg
->attrs
, nlen
* sizeof(*msg
->attrs
));
391 msg
->attr_size
= nlen
;
394 msg
->attrs
[msg
->attr_used
++] = attr
;
400 struct radius_attr_hdr
*radius_msg_add_attr(struct radius_msg
*msg
, u8 type
,
401 const u8
*data
, size_t data_len
)
404 struct radius_attr_hdr
*attr
;
406 if (data_len
> RADIUS_MAX_ATTR_LEN
) {
407 printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
408 (unsigned long) data_len
);
412 buf_needed
= msg
->buf_used
+ sizeof(*attr
) + data_len
;
414 if (msg
->buf_size
< buf_needed
) {
415 /* allocate more space for message buffer */
417 size_t i
, nlen
= msg
->buf_size
;
420 while (nlen
< buf_needed
)
422 nbuf
= os_realloc(msg
->buf
, nlen
);
425 diff
= nbuf
- msg
->buf
;
427 msg
->hdr
= (struct radius_hdr
*) msg
->buf
;
428 /* adjust attr pointers to match with the new buffer */
429 for (i
= 0; i
< msg
->attr_used
; i
++)
430 msg
->attrs
[i
] = (struct radius_attr_hdr
*)
431 (((u8
*) msg
->attrs
[i
]) + diff
);
432 os_memset(msg
->buf
+ msg
->buf_size
, 0, nlen
- msg
->buf_size
);
433 msg
->buf_size
= nlen
;
436 attr
= (struct radius_attr_hdr
*) (msg
->buf
+ msg
->buf_used
);
438 attr
->length
= sizeof(*attr
) + data_len
;
440 os_memcpy(attr
+ 1, data
, data_len
);
442 msg
->buf_used
+= sizeof(*attr
) + data_len
;
444 if (radius_msg_add_attr_to_array(msg
, attr
))
451 struct radius_msg
*radius_msg_parse(const u8
*data
, size_t len
)
453 struct radius_msg
*msg
;
454 struct radius_hdr
*hdr
;
455 struct radius_attr_hdr
*attr
;
457 unsigned char *pos
, *end
;
459 if (data
== NULL
|| len
< sizeof(*hdr
))
462 hdr
= (struct radius_hdr
*) data
;
464 msg_len
= ntohs(hdr
->length
);
465 if (msg_len
< sizeof(*hdr
) || msg_len
> len
) {
466 printf("Invalid RADIUS message length\n");
471 printf("Ignored %lu extra bytes after RADIUS message\n",
472 (unsigned long) len
- msg_len
);
475 msg
= os_malloc(sizeof(*msg
));
479 if (radius_msg_initialize(msg
, msg_len
)) {
484 os_memcpy(msg
->buf
, data
, msg_len
);
485 msg
->buf_size
= msg
->buf_used
= msg_len
;
487 /* parse attributes */
488 pos
= (unsigned char *) (msg
->hdr
+ 1);
489 end
= msg
->buf
+ msg
->buf_used
;
491 if ((size_t) (end
- pos
) < sizeof(*attr
))
494 attr
= (struct radius_attr_hdr
*) pos
;
496 if (pos
+ attr
->length
> end
|| attr
->length
< sizeof(*attr
))
499 /* TODO: check that attr->length is suitable for attr->type */
501 if (radius_msg_add_attr_to_array(msg
, attr
))
510 radius_msg_free(msg
);
516 int radius_msg_add_eap(struct radius_msg
*msg
, const u8
*data
, size_t data_len
)
518 const u8
*pos
= data
;
519 size_t left
= data_len
;
523 if (left
> RADIUS_MAX_ATTR_LEN
)
524 len
= RADIUS_MAX_ATTR_LEN
;
528 if (!radius_msg_add_attr(msg
, RADIUS_ATTR_EAP_MESSAGE
,
540 u8
*radius_msg_get_eap(struct radius_msg
*msg
, size_t *eap_len
)
549 for (i
= 0; i
< msg
->attr_used
; i
++) {
550 if (msg
->attrs
[i
]->type
== RADIUS_ATTR_EAP_MESSAGE
)
551 len
+= msg
->attrs
[i
]->length
-
552 sizeof(struct radius_attr_hdr
);
558 eap
= os_malloc(len
);
563 for (i
= 0; i
< msg
->attr_used
; i
++) {
564 if (msg
->attrs
[i
]->type
== RADIUS_ATTR_EAP_MESSAGE
) {
565 struct radius_attr_hdr
*attr
= msg
->attrs
[i
];
566 int flen
= attr
->length
- sizeof(*attr
);
567 os_memcpy(pos
, attr
+ 1, flen
);
579 int radius_msg_verify_msg_auth(struct radius_msg
*msg
, const u8
*secret
,
580 size_t secret_len
, const u8
*req_auth
)
582 u8 auth
[MD5_MAC_LEN
], orig
[MD5_MAC_LEN
];
583 u8 orig_authenticator
[16];
584 struct radius_attr_hdr
*attr
= NULL
;
587 for (i
= 0; i
< msg
->attr_used
; i
++) {
588 if (msg
->attrs
[i
]->type
== RADIUS_ATTR_MESSAGE_AUTHENTICATOR
) {
590 printf("Multiple Message-Authenticator "
591 "attributes in RADIUS message\n");
594 attr
= msg
->attrs
[i
];
599 printf("No Message-Authenticator attribute found\n");
603 os_memcpy(orig
, attr
+ 1, MD5_MAC_LEN
);
604 os_memset(attr
+ 1, 0, MD5_MAC_LEN
);
606 os_memcpy(orig_authenticator
, msg
->hdr
->authenticator
,
607 sizeof(orig_authenticator
));
608 os_memcpy(msg
->hdr
->authenticator
, req_auth
,
609 sizeof(msg
->hdr
->authenticator
));
611 hmac_md5(secret
, secret_len
, msg
->buf
, msg
->buf_used
, auth
);
612 os_memcpy(attr
+ 1, orig
, MD5_MAC_LEN
);
614 os_memcpy(msg
->hdr
->authenticator
, orig_authenticator
,
615 sizeof(orig_authenticator
));
618 if (os_memcmp(orig
, auth
, MD5_MAC_LEN
) != 0) {
619 printf("Invalid Message-Authenticator!\n");
627 int radius_msg_verify(struct radius_msg
*msg
, const u8
*secret
,
628 size_t secret_len
, struct radius_msg
*sent_msg
, int auth
)
632 u8 hash
[MD5_MAC_LEN
];
634 if (sent_msg
== NULL
) {
635 printf("No matching Access-Request message found\n");
640 radius_msg_verify_msg_auth(msg
, secret
, secret_len
,
641 sent_msg
->hdr
->authenticator
)) {
645 /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
646 addr
[0] = (u8
*) msg
->hdr
;
648 addr
[1] = sent_msg
->hdr
->authenticator
;
649 len
[1] = MD5_MAC_LEN
;
650 addr
[2] = (u8
*) (msg
->hdr
+ 1);
651 len
[2] = msg
->buf_used
- sizeof(*msg
->hdr
);
654 md5_vector(4, addr
, len
, hash
);
655 if (os_memcmp(hash
, msg
->hdr
->authenticator
, MD5_MAC_LEN
) != 0) {
656 printf("Response Authenticator invalid!\n");
664 int radius_msg_copy_attr(struct radius_msg
*dst
, struct radius_msg
*src
,
667 struct radius_attr_hdr
*attr
= NULL
;
670 for (i
= 0; i
< src
->attr_used
; i
++) {
671 if (src
->attrs
[i
]->type
== type
) {
672 attr
= src
->attrs
[i
];
680 if (!radius_msg_add_attr(dst
, type
, (u8
*) (attr
+ 1),
681 attr
->length
- sizeof(*attr
)))
688 /* Create Request Authenticator. The value should be unique over the lifetime
689 * of the shared secret between authenticator and authentication server.
690 * Use one-way MD5 hash calculated from current timestamp and some data given
692 void radius_msg_make_authenticator(struct radius_msg
*msg
,
693 const u8
*data
, size_t len
)
702 addr
[0] = (u8
*) &tv
;
703 elen
[0] = sizeof(tv
);
708 md5_vector(3, addr
, elen
, msg
->hdr
->authenticator
);
712 /* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
713 * Returns the Attribute payload and sets alen to indicate the length of the
714 * payload if a vendor attribute with subtype is found, otherwise returns NULL.
715 * The returned payload is allocated with os_malloc() and caller must free it
716 * by calling os_free().
718 static u8
*radius_msg_get_vendor_attr(struct radius_msg
*msg
, u32 vendor
,
719 u8 subtype
, size_t *alen
)
727 for (i
= 0; i
< msg
->attr_used
; i
++) {
728 struct radius_attr_hdr
*attr
= msg
->attrs
[i
];
731 struct radius_attr_vendor
*vhdr
;
733 if (attr
->type
!= RADIUS_ATTR_VENDOR_SPECIFIC
)
736 left
= attr
->length
- sizeof(*attr
);
740 pos
= (u8
*) (attr
+ 1);
742 os_memcpy(&vendor_id
, pos
, 4);
746 if (ntohl(vendor_id
) != vendor
)
749 while (left
>= sizeof(*vhdr
)) {
750 vhdr
= (struct radius_attr_vendor
*) pos
;
751 if (vhdr
->vendor_length
> left
||
752 vhdr
->vendor_length
< sizeof(*vhdr
)) {
756 if (vhdr
->vendor_type
!= subtype
) {
757 pos
+= vhdr
->vendor_length
;
758 left
-= vhdr
->vendor_length
;
762 len
= vhdr
->vendor_length
- sizeof(*vhdr
);
763 data
= os_malloc(len
);
766 os_memcpy(data
, pos
+ sizeof(*vhdr
), len
);
777 static u8
* decrypt_ms_key(const u8
*key
, size_t len
,
778 const u8
*req_authenticator
,
779 const u8
*secret
, size_t secret_len
, size_t *reslen
)
781 u8
*plain
, *ppos
, *res
;
784 u8 hash
[MD5_MAC_LEN
];
789 /* key: 16-bit salt followed by encrypted key info */
797 printf("Invalid ms key len %lu\n", (unsigned long) left
);
802 ppos
= plain
= os_malloc(plen
);
807 /* b(1) = MD5(Secret + Request-Authenticator + Salt)
808 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
811 elen
[0] = secret_len
;
813 addr
[1] = req_authenticator
;
814 elen
[1] = MD5_MAC_LEN
;
816 elen
[2] = 2; /* Salt */
818 addr
[1] = pos
- MD5_MAC_LEN
;
819 elen
[1] = MD5_MAC_LEN
;
821 md5_vector(first
? 3 : 2, addr
, elen
, hash
);
824 for (i
= 0; i
< MD5_MAC_LEN
; i
++)
825 *ppos
++ = *pos
++ ^ hash
[i
];
829 if (plain
[0] > plen
- 1) {
830 printf("Failed to decrypt MPPE key\n");
835 res
= os_malloc(plain
[0]);
840 os_memcpy(res
, plain
+ 1, plain
[0]);
848 static void encrypt_ms_key(const u8
*key
, size_t key_len
, u16 salt
,
849 const u8
*req_authenticator
,
850 const u8
*secret
, size_t secret_len
,
851 u8
*ebuf
, size_t *elen
)
853 int i
, len
, first
= 1;
854 u8 hash
[MD5_MAC_LEN
], saltbuf
[2], *pos
;
858 saltbuf
[0] = salt
>> 8;
863 len
= (len
& 0xf0) + 16;
865 os_memset(ebuf
, 0, len
);
867 os_memcpy(ebuf
+ 1, key
, key_len
);
873 /* b(1) = MD5(Secret + Request-Authenticator + Salt)
874 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
876 _len
[0] = secret_len
;
878 addr
[1] = req_authenticator
;
879 _len
[1] = MD5_MAC_LEN
;
881 _len
[2] = sizeof(saltbuf
);
883 addr
[1] = pos
- MD5_MAC_LEN
;
884 _len
[1] = MD5_MAC_LEN
;
886 md5_vector(first
? 3 : 2, addr
, _len
, hash
);
889 for (i
= 0; i
< MD5_MAC_LEN
; i
++)
897 struct radius_ms_mppe_keys
*
898 radius_msg_get_ms_keys(struct radius_msg
*msg
, struct radius_msg
*sent_msg
,
899 u8
*secret
, size_t secret_len
)
903 struct radius_ms_mppe_keys
*keys
;
905 if (msg
== NULL
|| sent_msg
== NULL
)
908 keys
= wpa_zalloc(sizeof(*keys
));
912 key
= radius_msg_get_vendor_attr(msg
, RADIUS_VENDOR_ID_MICROSOFT
,
913 RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY
,
916 keys
->send
= decrypt_ms_key(key
, keylen
,
917 sent_msg
->hdr
->authenticator
,
923 key
= radius_msg_get_vendor_attr(msg
, RADIUS_VENDOR_ID_MICROSOFT
,
924 RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY
,
927 keys
->recv
= decrypt_ms_key(key
, keylen
,
928 sent_msg
->hdr
->authenticator
,
938 struct radius_ms_mppe_keys
*
939 radius_msg_get_cisco_keys(struct radius_msg
*msg
, struct radius_msg
*sent_msg
,
940 u8
*secret
, size_t secret_len
)
944 struct radius_ms_mppe_keys
*keys
;
946 if (msg
== NULL
|| sent_msg
== NULL
)
949 keys
= wpa_zalloc(sizeof(*keys
));
953 key
= radius_msg_get_vendor_attr(msg
, RADIUS_VENDOR_ID_CISCO
,
954 RADIUS_CISCO_AV_PAIR
, &keylen
);
955 if (key
&& keylen
== 51 &&
956 os_memcmp(key
, "leap:session-key=", 17) == 0) {
957 keys
->recv
= decrypt_ms_key(key
+ 17, keylen
- 17,
958 sent_msg
->hdr
->authenticator
,
968 int radius_msg_add_mppe_keys(struct radius_msg
*msg
,
969 const u8
*req_authenticator
,
970 const u8
*secret
, size_t secret_len
,
971 const u8
*send_key
, size_t send_key_len
,
972 const u8
*recv_key
, size_t recv_key_len
)
974 struct radius_attr_hdr
*attr
;
975 u32 vendor_id
= htonl(RADIUS_VENDOR_ID_MICROSOFT
);
977 struct radius_attr_vendor
*vhdr
;
983 hlen
= sizeof(vendor_id
) + sizeof(*vhdr
) + 2;
985 /* MS-MPPE-Send-Key */
986 buf
= os_malloc(hlen
+ send_key_len
+ 16);
991 os_memcpy(pos
, &vendor_id
, sizeof(vendor_id
));
992 pos
+= sizeof(vendor_id
);
993 vhdr
= (struct radius_attr_vendor
*) pos
;
994 vhdr
->vendor_type
= RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY
;
995 pos
= (u8
*) (vhdr
+ 1);
996 salt
= os_random() | 0x8000;
999 encrypt_ms_key(send_key
, send_key_len
, salt
, req_authenticator
, secret
,
1000 secret_len
, pos
, &elen
);
1001 vhdr
->vendor_length
= hlen
+ elen
- sizeof(vendor_id
);
1003 attr
= radius_msg_add_attr(msg
, RADIUS_ATTR_VENDOR_SPECIFIC
,
1010 /* MS-MPPE-Recv-Key */
1011 buf
= os_malloc(hlen
+ send_key_len
+ 16);
1016 os_memcpy(pos
, &vendor_id
, sizeof(vendor_id
));
1017 pos
+= sizeof(vendor_id
);
1018 vhdr
= (struct radius_attr_vendor
*) pos
;
1019 vhdr
->vendor_type
= RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY
;
1020 pos
= (u8
*) (vhdr
+ 1);
1024 encrypt_ms_key(recv_key
, recv_key_len
, salt
, req_authenticator
, secret
,
1025 secret_len
, pos
, &elen
);
1026 vhdr
->vendor_length
= hlen
+ elen
- sizeof(vendor_id
);
1028 attr
= radius_msg_add_attr(msg
, RADIUS_ATTR_VENDOR_SPECIFIC
,
1039 /* Add User-Password attribute to a RADIUS message and encrypt it as specified
1040 * in RFC 2865, Chap. 5.2 */
1041 struct radius_attr_hdr
*
1042 radius_msg_add_attr_user_password(struct radius_msg
*msg
,
1043 u8
*data
, size_t data_len
,
1044 u8
*secret
, size_t secret_len
)
1048 size_t buf_len
, pos
;
1056 os_memcpy(buf
, data
, data_len
);
1059 padlen
= data_len
% 16;
1061 padlen
= 16 - padlen
;
1062 os_memset(buf
+ data_len
, 0, padlen
);
1067 len
[0] = secret_len
;
1068 addr
[1] = msg
->hdr
->authenticator
;
1070 md5_vector(2, addr
, len
, hash
);
1072 for (i
= 0; i
< 16; i
++)
1076 while (pos
< buf_len
) {
1078 len
[0] = secret_len
;
1079 addr
[1] = &buf
[pos
- 16];
1081 md5_vector(2, addr
, len
, hash
);
1083 for (i
= 0; i
< 16; i
++)
1084 buf
[pos
+ i
] ^= hash
[i
];
1089 return radius_msg_add_attr(msg
, RADIUS_ATTR_USER_PASSWORD
,
1094 int radius_msg_get_attr(struct radius_msg
*msg
, u8 type
, u8
*buf
, size_t len
)
1096 struct radius_attr_hdr
*attr
= NULL
;
1099 for (i
= 0; i
< msg
->attr_used
; i
++) {
1100 if (msg
->attrs
[i
]->type
== type
) {
1101 attr
= msg
->attrs
[i
];
1109 dlen
= attr
->length
- sizeof(*attr
);
1111 os_memcpy(buf
, (attr
+ 1), dlen
> len
? len
: dlen
);
1116 int radius_msg_get_attr_ptr(struct radius_msg
*msg
, u8 type
, u8
**buf
,
1117 size_t *len
, const u8
*start
)
1120 struct radius_attr_hdr
*attr
= NULL
;
1122 for (i
= 0; i
< msg
->attr_used
; i
++) {
1123 if (msg
->attrs
[i
]->type
== type
&&
1124 (start
== NULL
|| (u8
*) msg
->attrs
[i
] > start
)) {
1125 attr
= msg
->attrs
[i
];
1133 *buf
= (u8
*) (attr
+ 1);
1134 *len
= attr
->length
- sizeof(*attr
);
1139 int radius_msg_count_attr(struct radius_msg
*msg
, u8 type
, int min_len
)
1144 for (count
= 0, i
= 0; i
< msg
->attr_used
; i
++) {
1145 if (msg
->attrs
[i
]->type
== type
&&
1146 msg
->attrs
[i
]->length
>=
1147 sizeof(struct radius_attr_hdr
) + min_len
)
1155 struct radius_tunnel_attrs
{
1157 int type
; /* Tunnel-Type */
1158 int medium_type
; /* Tunnel-Medium-Type */
1164 * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
1165 * @msg: RADIUS message
1166 * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
1168 int radius_msg_get_vlanid(struct radius_msg
*msg
)
1170 struct radius_tunnel_attrs tunnel
[RADIUS_TUNNEL_TAGS
], *tun
;
1172 struct radius_attr_hdr
*attr
= NULL
;
1177 os_memset(&tunnel
, 0, sizeof(tunnel
));
1179 for (i
= 0; i
< msg
->attr_used
; i
++) {
1180 attr
= msg
->attrs
[i
];
1181 data
= (const u8
*) (attr
+ 1);
1182 dlen
= attr
->length
- sizeof(*attr
);
1183 if (attr
->length
< 3)
1185 if (data
[0] >= RADIUS_TUNNEL_TAGS
)
1188 tun
= &tunnel
[data
[0]];
1190 switch (attr
->type
) {
1191 case RADIUS_ATTR_TUNNEL_TYPE
:
1192 if (attr
->length
!= 6)
1195 tun
->type
= (data
[1] << 16) | (data
[2] << 8) | data
[3];
1197 case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE
:
1198 if (attr
->length
!= 6)
1202 (data
[1] << 16) | (data
[2] << 8) | data
[3];
1204 case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID
:
1205 if (data
[0] < RADIUS_TUNNEL_TAGS
) {
1209 if (dlen
>= sizeof(buf
))
1211 os_memcpy(buf
, data
, dlen
);
1214 tun
->vlanid
= atoi(buf
);
1219 for (i
= 0; i
< RADIUS_TUNNEL_TAGS
; i
++) {
1221 if (tun
->tag_used
&&
1222 tun
->type
== RADIUS_TUNNEL_TYPE_VLAN
&&
1223 tun
->medium_type
== RADIUS_TUNNEL_MEDIUM_TYPE_802
&&