hostapd vendor branch: Update version from 0.6.10 => 2.1
[dragonfly.git] / contrib / hostapd / src / eap_peer / eap_md5.c
1 /*
2  * EAP peer method: EAP-MD5 (RFC 3748 and RFC 1994)
3  * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8
9 #include "includes.h"
10
11 #include "common.h"
12 #include "eap_i.h"
13 #include "eap_common/chap.h"
14
15
16 static void * eap_md5_init(struct eap_sm *sm)
17 {
18         /* No need for private data. However, must return non-NULL to indicate
19          * success. */
20         return (void *) 1;
21 }
22
23
24 static void eap_md5_deinit(struct eap_sm *sm, void *priv)
25 {
26 }
27
28
29 static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
30                                        struct eap_method_ret *ret,
31                                        const struct wpabuf *reqData)
32 {
33         struct wpabuf *resp;
34         const u8 *pos, *challenge, *password;
35         u8 *rpos, id;
36         size_t len, challenge_len, password_len;
37
38         password = eap_get_config_password(sm, &password_len);
39         if (password == NULL) {
40                 wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
41                 eap_sm_request_password(sm);
42                 ret->ignore = TRUE;
43                 return NULL;
44         }
45
46         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, reqData, &len);
47         if (pos == NULL || len == 0) {
48                 wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame (pos=%p len=%lu)",
49                            pos, (unsigned long) len);
50                 ret->ignore = TRUE;
51                 return NULL;
52         }
53
54         /*
55          * CHAP Challenge:
56          * Value-Size (1 octet) | Value(Challenge) | Name(optional)
57          */
58         challenge_len = *pos++;
59         if (challenge_len == 0 || challenge_len > len - 1) {
60                 wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge "
61                            "(challenge_len=%lu len=%lu)",
62                            (unsigned long) challenge_len, (unsigned long) len);
63                 ret->ignore = TRUE;
64                 return NULL;
65         }
66         ret->ignore = FALSE;
67         challenge = pos;
68         wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge",
69                     challenge, challenge_len);
70
71         wpa_printf(MSG_DEBUG, "EAP-MD5: Generating Challenge Response");
72         ret->methodState = METHOD_DONE;
73         ret->decision = DECISION_COND_SUCC;
74         ret->allowNotifications = TRUE;
75
76         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHAP_MD5_LEN,
77                              EAP_CODE_RESPONSE, eap_get_id(reqData));
78         if (resp == NULL)
79                 return NULL;
80
81         /*
82          * CHAP Response:
83          * Value-Size (1 octet) | Value(Response) | Name(optional)
84          */
85         wpabuf_put_u8(resp, CHAP_MD5_LEN);
86
87         id = eap_get_id(resp);
88         rpos = wpabuf_put(resp, CHAP_MD5_LEN);
89         if (chap_md5(id, password, password_len, challenge, challenge_len,
90                      rpos)) {
91                 wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed");
92                 ret->ignore = TRUE;
93                 wpabuf_free(resp);
94                 return NULL;
95         }
96         wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, CHAP_MD5_LEN);
97
98         return resp;
99 }
100
101
102 int eap_peer_md5_register(void)
103 {
104         struct eap_method *eap;
105         int ret;
106
107         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
108                                     EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5");
109         if (eap == NULL)
110                 return -1;
111
112         eap->init = eap_md5_init;
113         eap->deinit = eap_md5_deinit;
114         eap->process = eap_md5_process;
115
116         ret = eap_peer_method_register(eap);
117         if (ret)
118                 eap_peer_method_free(eap);
119         return ret;
120 }