All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
eap_md5.c
Go to the documentation of this file.
1 /*
2  * eap_md5.c EAP MD5 functionality.
3  *
4  * Version: $Id: 79af590918024558d0fd3814c02fae534c68a517 $
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 
38 RCSID("$Id: 79af590918024558d0fd3814c02fae534c68a517 $")
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include "eap.h"
43 
44 #include "eap_md5.h"
45 #include <freeradius-devel/md5.h>
46 
47 /*
48  * We expect only RESPONSE for which SUCCESS or FAILURE is sent back
49  */
51 {
53  MD5_PACKET *packet;
54  unsigned short name_len;
55 
56  /*
57  * We need a response, of type EAP-MD5, with at least
58  * one byte of type data (EAP-MD5) following the 4-byte
59  * EAP-Packet header.
60  */
61  if (!eap_round ||
62  !eap_round->response ||
63  (eap_round->response->code != PW_MD5_RESPONSE) ||
64  eap_round->response->type.num != PW_EAP_MD5 ||
65  !eap_round->response->type.data ||
66  (eap_round->response->length <= MD5_HEADER_LEN) ||
67  (eap_round->response->type.data[0] <= 0)) {
68  ERROR("rlm_eap_md5: corrupted data");
69  return NULL;
70  }
71 
72  packet = talloc_zero(eap_round, MD5_PACKET);
73  if (!packet) return NULL;
74 
75  /*
76  * Code & id for MD5 & EAP are same
77  *
78  * but md5_length = length of the EAP-MD5 data, which
79  * doesn't include the EAP header, or the octet saying
80  * EAP-MD5.
81  */
82  packet->code = eap_round->response->code;
83  packet->id = eap_round->response->id;
84  packet->length = eap_round->response->length - (MD5_HEADER_LEN + 1);
85 
86  /*
87  * Sanity check the EAP-MD5 packet sent to us
88  * by the client.
89  */
90  data = (md5_packet_t *)eap_round->response->type.data;
91 
92  /*
93  * Already checked the size above.
94  */
95  packet->value_size = data->value_size;
96 
97  /*
98  * Allocate room for the data, and copy over the data.
99  */
100  packet->value = talloc_array(packet, uint8_t, packet->value_size);
101  if (!packet->value) {
102  talloc_free(packet);
103  return NULL;
104  }
105  memcpy(packet->value, data->value_name, packet->value_size);
106 
107  /*
108  * Name is optional and is present after Value, but we
109  * need to check for it, as eapmd5_compose()
110  */
111  name_len = packet->length - (packet->value_size + 1);
112  if (name_len) {
113  packet->name = talloc_array(packet, char, name_len + 1);
114  if (!packet->name) {
115  talloc_free(packet);
116  return NULL;
117  }
118  memcpy(packet->name, data->value_name + packet->value_size,
119  name_len);
120  packet->name[name_len] = 0;
121  }
122 
123  return packet;
124 }
125 
126 
127 /*
128  * verify = MD5(id+password+challenge_sent)
129  */
130 int eapmd5_verify(MD5_PACKET *packet, VALUE_PAIR* password,
131  uint8_t *challenge)
132 {
133  char *ptr;
134  char string[1 + MAX_STRING_LEN*2];
135  uint8_t digest[16];
136  unsigned short len;
137 
138  /*
139  * Sanity check it.
140  */
141  if (packet->value_size != 16) {
142  ERROR("rlm_eap_md5: Expected 16 bytes of response to challenge, got %d", packet->value_size);
143  return 0;
144  }
145 
146  len = 0;
147  ptr = string;
148 
149  /*
150  * This is really rad_chap_pwencode()...
151  */
152  *ptr++ = packet->id;
153  len++;
154  memcpy(ptr, password->vp_strvalue, password->vp_length);
155  ptr += password->vp_length;
156  len += password->vp_length;
157 
158  /*
159  * The challenge size is hard-coded.
160  */
161  memcpy(ptr, challenge, MD5_CHALLENGE_LEN);
162  len += MD5_CHALLENGE_LEN;
163 
164  fr_md5_calc(digest, (uint8_t *)string, len);
165 
166  /*
167  * The length of the response is always 16 for MD5.
168  */
169  if (fr_radius_digest_cmp(digest, packet->value, 16) != 0) {
170  return 0;
171  }
172 
173  return 1;
174 }
175 
176 /*
177  * Compose the portions of the reply packet specific to the
178  * EAP-MD5 protocol, in the EAP reply typedata
179  */
181 {
182  uint8_t *ptr;
183  unsigned short name_len;
184 
185  /*
186  * We really only send Challenge (EAP-Identity),
187  * and EAP-Success, and EAP-Failure.
188  */
189  if (reply->code < 3) {
190  eap_round->request->type.num = PW_EAP_MD5;
191 
192  rad_assert(reply->length > 0);
193 
194  eap_round->request->type.data = talloc_array(eap_round->request,
195  uint8_t,
196  reply->length);
197  if (!eap_round->request->type.data) {
198  talloc_free(reply);
199  return 0;
200  }
201  ptr = eap_round->request->type.data;
202  *ptr++ = (uint8_t)(reply->value_size & 0xFF);
203  memcpy(ptr, reply->value, reply->value_size);
204 
205  /* Just the Challenge length */
206  eap_round->request->type.length = reply->value_size + 1;
207 
208  /*
209  * Return the name, if necessary.
210  *
211  * Don't see why this is *ever* necessary...
212  */
213  name_len = reply->length - (reply->value_size + 1);
214  if (name_len && reply->name) {
215  ptr += reply->value_size;
216  memcpy(ptr, reply->name, name_len);
217  /* Challenge length + Name length */
218  eap_round->request->type.length += name_len;
219  }
220  } else {
221  eap_round->request->type.length = 0;
222  /* TODO: In future we might add message here wrt rfc1994 */
223  }
224  eap_round->request->code = reply->code;
225  talloc_free(reply);
226 
227  return 1;
228 }
void fr_md5_calc(uint8_t *out, uint8_t const *in, size_t inlen)
Calculate the MD5 hash of the contents of a buffer.
Definition: md5.c:28
size_t length
Definition: eap_types.h:135
int eapmd5_verify(MD5_PACKET *packet, VALUE_PAIR *password, uint8_t *challenge)
Definition: eap_md5.c:130
unsigned char id
Definition: eap_md5.h:40
unsigned char code
Definition: eap_md5.h:39
eap_packet_t * request
Packet we will send to the peer.
Definition: eap.h:45
MD5_PACKET * eapmd5_extract(eap_round_t *eap_round)
Definition: eap_md5.c:50
#define PW_MD5_RESPONSE
Definition: eap_md5.h:9
eap_type_data_t type
Definition: eap_types.h:136
#define rad_assert(expr)
Definition: rad_assert.h:38
eap_type_t num
Definition: eap_types.h:122
uint8_t id
Definition: eap_types.h:134
uint8_t value_name[1]
Definition: eap_md5.h:35
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
size_t length
Definition: eap_types.h:123
unsigned short length
Definition: eap_md5.h:41
Contains a pair of request and response packets.
Definition: eap.h:43
uint8_t data[]
Definition: eap_pwd.h:625
char * name
Definition: eap_md5.h:44
uint8_t value_size
Definition: eap_md5.h:34
int fr_radius_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length)
Do a comparison of two authentication digests by comparing the FULL digest.
Definition: radius.c:578
#define MD5_CHALLENGE_LEN
Definition: eap_md5.h:15
int eapmd5_compose(eap_round_t *eap_round, MD5_PACKET *reply)
Definition: eap_md5.c:180
unsigned char value_size
Definition: eap_md5.h:42
unsigned char * value
Definition: eap_md5.h:43
eap_packet_t * response
Packet we received from the peer.
Definition: eap.h:44
#define MAX_STRING_LEN
Definition: libradius.h:120
#define RCSID(id)
Definition: build.h:135
#define MD5_HEADER_LEN
Definition: eap_md5.h:14
#define ERROR(fmt,...)
Definition: log.h:145
eap_code_t code
Definition: eap_types.h:133
uint8_t * data
Definition: eap_types.h:124