The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
eap_md5.c
Go to the documentation of this file.
1 /*
2  * eap_md5.c EAP MD5 functionality.
3  *
4  * Version: $Id: 243a8ed880e5053f43c252c378f17ec303a95287 $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * @copyright 2000,2001,2006 The FreeRADIUS server project
21  * @copyright 2001 hereUare Communications, Inc. (raghud@hereuare.com)
22  */
23 
24 /*
25  *
26  * MD5 Packet Format in EAP Type-Data
27  * --- ------ ------ -- --- ---------
28  * 0 1 2 3
29  * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
30  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31  * | Value-Size | Value ...
32  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33  * | Name ...
34  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35  *
36  */
37 RCSID("$Id: 243a8ed880e5053f43c252c378f17ec303a95287 $")
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <freeradius-devel/eap/base.h>
42 
43 #include "eap_md5.h"
44 #include <freeradius-devel/util/md5.h>
45 
46 /*
47  * We expect only RESPONSE for which SUCCESS or FAILURE is sent back
48  */
50 {
52  MD5_PACKET *packet;
53  unsigned short name_len;
54 
55  /*
56  * We need a response, of type EAP-MD5, with at least
57  * one byte of type data (EAP-MD5) following the 4-byte
58  * EAP-Packet header.
59  */
60  if (!eap_round ||
61  !eap_round->response ||
62  (eap_round->response->code != FR_MD5_RESPONSE) ||
63  eap_round->response->type.num != FR_EAP_METHOD_MD5 ||
64  !eap_round->response->type.data ||
65  (eap_round->response->length <= MD5_HEADER_LEN) ||
66  (eap_round->response->type.data[0] == 0)) {
67  REDEBUG("corrupted data");
68  return NULL;
69  }
70 
71  packet = talloc_zero(eap_round, MD5_PACKET);
72  if (!packet) return NULL;
73 
74  /*
75  * Code & id for MD5 & EAP are same
76  *
77  * but md5_length = length of the EAP-MD5 data, which
78  * doesn't include the EAP header, or the octet saying
79  * EAP-MD5.
80  */
81  packet->code = eap_round->response->code;
82  packet->id = eap_round->response->id;
83  packet->length = eap_round->response->length - (MD5_HEADER_LEN + 1);
84 
85  /*
86  * Sanity check the EAP-MD5 packet sent to us
87  * by the client.
88  */
89  data = (md5_packet_t *)eap_round->response->type.data;
90 
91  /*
92  * Already checked the size above.
93  */
94  packet->value_size = data->value_size;
95 
96  /*
97  * Allocate room for the data, and copy over the data.
98  */
99  packet->value = talloc_array(packet, uint8_t, packet->value_size);
100  if (!packet->value) {
101  talloc_free(packet);
102  return NULL;
103  }
104  memcpy(packet->value, data->value_name, packet->value_size);
105 
106  /*
107  * Name is optional and is present after Value, but we
108  * need to check for it, as eap_md5_compose()
109  */
110  name_len = packet->length - (packet->value_size + 1);
111  if (name_len) {
112  packet->name = talloc_array(packet, char, name_len + 1);
113  if (!packet->name) {
114  talloc_free(packet);
115  return NULL;
116  }
117  memcpy(packet->name, data->value_name + packet->value_size,
118  name_len);
119  packet->name[name_len] = 0;
120  }
121 
122  return packet;
123 }
124 
125 
126 /*
127  * verify = MD5(id+password+challenge_sent)
128  */
129 int eap_md5_verify(request_t *request, MD5_PACKET *packet, fr_pair_t* password,
130  uint8_t *challenge)
131 {
132  char *ptr;
133  char string[1 + FR_MAX_STRING_LEN*2];
134  uint8_t digest[16];
135  unsigned short len;
136 
137  /*
138  * Sanity check it.
139  */
140  if (packet->value_size != 16) {
141  REDEBUG("Expected 16 bytes of response to challenge, got %d", packet->value_size);
142  return 0;
143  }
144 
145  len = 0;
146  ptr = string;
147 
148  /*
149  * This is really rad_chap_pwencode()...
150  */
151  *ptr++ = packet->id;
152  len++;
153  memcpy(ptr, password->vp_strvalue, password->vp_length);
154  ptr += password->vp_length;
155  len += password->vp_length;
156 
157  /*
158  * The challenge size is hard-coded.
159  */
160  memcpy(ptr, challenge, MD5_CHALLENGE_LEN);
161  len += MD5_CHALLENGE_LEN;
162 
163  fr_md5_calc(digest, (uint8_t *)string, len);
164 
165  /*
166  * The length of the response is always 16 for MD5.
167  */
168  if (fr_digest_cmp(digest, packet->value, 16) != 0) {
169  return 0;
170  }
171 
172  return 1;
173 }
174 
175 /*
176  * Compose the portions of the reply packet specific to the
177  * EAP-MD5 protocol, in the EAP reply typedata
178  */
179 int eap_md5_compose(eap_round_t *eap_round, MD5_PACKET *reply)
180 {
181  uint8_t *ptr;
182  unsigned short name_len;
183 
184  /*
185  * We really only send Challenge (EAP-Identity),
186  * and EAP-Success, and EAP-Failure.
187  */
188  if (reply->code < 3) {
189  eap_round->request->type.num = FR_EAP_METHOD_MD5;
190 
191  fr_assert(reply->length > 0);
192 
193  eap_round->request->type.data = talloc_array(eap_round->request,
194  uint8_t,
195  reply->length);
196  if (!eap_round->request->type.data) {
197  talloc_free(reply);
198  return 0;
199  }
200  ptr = eap_round->request->type.data;
201  *ptr++ = (uint8_t)(reply->value_size & 0xFF);
202  memcpy(ptr, reply->value, reply->value_size);
203 
204  /* Just the Challenge length */
205  eap_round->request->type.length = reply->value_size + 1;
206 
207  /*
208  * Return the name, if necessary.
209  *
210  * Don't see why this is *ever* necessary...
211  */
212  name_len = reply->length - (reply->value_size + 1);
213  if (name_len && reply->name) {
214  ptr += reply->value_size;
215  memcpy(ptr, reply->name, name_len);
216  /* Challenge length + Name length */
217  eap_round->request->type.length += name_len;
218  }
219  } else {
220  eap_round->request->type.length = 0;
221  /* TODO: In future we might add message here wrt rfc1994 */
222  }
223  eap_round->request->code = reply->code;
224  talloc_free(reply);
225 
226  return 1;
227 }
#define RCSID(id)
Definition: build.h:444
eap_type_data_t type
Definition: compose.h:39
size_t length
Definition: compose.h:38
eap_packet_t * response
Packet we received from the peer.
Definition: compose.h:49
eap_code_t code
Definition: compose.h:36
uint8_t id
Definition: compose.h:37
eap_packet_t * request
Packet we will send to the peer.
Definition: compose.h:50
Contains a pair of request and response packets.
Definition: compose.h:48
eap_type_t num
Definition: types.h:110
size_t length
Definition: types.h:111
uint8_t * data
Definition: types.h:112
@ FR_EAP_METHOD_MD5
Definition: types.h:49
MD5_PACKET * eap_md5_extract(request_t *request, eap_round_t *eap_round)
Definition: eap_md5.c:49
int eap_md5_verify(request_t *request, MD5_PACKET *packet, fr_pair_t *password, uint8_t *challenge)
Definition: eap_md5.c:129
int eap_md5_compose(eap_round_t *eap_round, MD5_PACKET *reply)
Definition: eap_md5.c:179
#define MD5_HEADER_LEN
Definition: eap_md5.h:12
#define FR_MD5_RESPONSE
Definition: eap_md5.h:7
unsigned char id
Definition: eap_md5.h:38
#define MD5_CHALLENGE_LEN
Definition: eap_md5.h:13
unsigned short length
Definition: eap_md5.h:39
unsigned char code
Definition: eap_md5.h:37
unsigned char * value
Definition: eap_md5.h:41
char * name
Definition: eap_md5.h:42
unsigned char value_size
Definition: eap_md5.h:40
talloc_free(reap)
void fr_md5_calc(uint8_t out[static MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
Perform a single digest operation on a single input buffer.
Definition: merged_model.c:251
unsigned char uint8_t
Definition: merged_model.c:30
int fr_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length)
Do a comparison of two authentication digests by comparing the FULL data.
Definition: misc.c:463
#define REDEBUG(fmt,...)
Definition: radclient.h:52
fr_assert(0)
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
static fr_slen_t data
Definition: value.h:1259
#define FR_MAX_STRING_LEN
Definition: value.h:30