trimming additial / in some cases
[strongswan.git] / src / charon / plugins / eap_sim / eap_sim_file.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include <string.h>
19 #include <stdio.h>
20 #include <errno.h>
21
22 #include <daemon.h>
23
24 #define IMSI_LEN 64
25 #define RAND_LEN 16
26 #define SRES_LEN 4
27 #define KC_LEN 8
28
29 typedef struct triplet_t triplet_t;
30
31 struct triplet_t {
32 unsigned char imsi[IMSI_LEN];
33 unsigned char rand[RAND_LEN];
34 unsigned char sres[SRES_LEN];
35 unsigned char kc[KC_LEN];
36 };
37
38 static triplet_t *triplets = NULL;
39 static int triplet_count = 0;
40
41 #define TRIPLET_FILE IPSEC_CONFDIR "/ipsec.d/triplets.dat"
42
43 /**
44 * convert a single HEX char to its integer value
45 */
46 static int hexchr(char chr)
47 {
48 switch (chr)
49 {
50 case '0'...'9':
51 return chr - '0';
52 case 'A'...'F':
53 return 10 + chr - 'A';
54 case 'a'...'f':
55 return 10 + chr - 'a';
56 }
57 return 0;
58 }
59
60 /**
61 * convert a HEX string into a char array bin, limited by array length len
62 */
63 static void hex2bin(char *hex, unsigned char *bin, size_t len)
64 {
65 char *pos;
66 int i, even = 1;
67
68 pos = hex - 1;
69 /* find the end, as we convert bottom up */
70 while (TRUE)
71 {
72 switch (*(pos+1))
73 {
74 case '0'...'9':
75 case 'A'...'F':
76 case 'a'...'f':
77 pos++;
78 continue;
79 }
80 break;
81 }
82 /* convert two hex chars into a single bin byte */
83 for (i = 0; pos >= hex && i < len; pos--)
84 {
85 if (even)
86 {
87 bin[len - 1 - i] = hexchr(*pos);
88 }
89 else
90 {
91 bin[len - 1 - i] |= 16 * hexchr(*pos);
92 i++;
93 }
94 even = !even;
95 }
96 }
97
98 /**
99 * free up allocated triplets
100 */
101 static void __attribute__ ((destructor)) free_triplets()
102 {
103 free(triplets);
104 }
105
106 /**
107 * read the triplets from the file, using freeradius triplet file syntax:
108 * http://www.freeradius.org/radiusd/doc/rlm_sim_triplets
109 */
110 static void __attribute__ ((constructor)) read_triplets()
111 {
112 char line[512], *data[4], *pos;
113 FILE *file;
114 int i, nr = 0;
115 triplet_t *triplet;
116
117 file = fopen(TRIPLET_FILE, "r");
118 if (file == NULL)
119 {
120 DBG1(DBG_CFG, "opening triplet file %s failed: %s",
121 TRIPLET_FILE, strerror(errno));
122 return;
123 }
124
125 if (triplets)
126 {
127 free(triplets);
128 triplets = NULL;
129 triplet_count = 0;
130 }
131
132 /* read line by line */
133 while (fgets(line, sizeof(line), file))
134 {
135 nr++;
136 /* skip comments, empty lines */
137 switch (line[0])
138 {
139 case '\n':
140 case '\r':
141 case '#':
142 case '\0':
143 continue;
144 default:
145 break;
146 }
147 /* read comma separated values */
148 pos = line;
149 for (i = 0; i < 4; i++)
150 {
151 data[i] = pos;
152 pos = strchr(pos, ',');
153 if (pos)
154 {
155 *pos = '\0';
156 pos++;
157 }
158 else if (i != 3)
159 {
160 DBG1(DBG_CFG, "error in triplet file, line %d", nr);
161 fclose(file);
162 return;
163 }
164 }
165 /* allocate new triplet */
166 triplet_count++;
167 triplets = realloc(triplets, triplet_count * sizeof(triplet_t));
168 triplet = &triplets[triplet_count - 1];
169 memset(triplet, 0, sizeof(triplet_t));
170
171 /* convert/copy triplet data */
172 for (i = 0; i < IMSI_LEN - 1; i++)
173 {
174 switch (data[0][i])
175 {
176 case '\n':
177 case '\r':
178 case '\0':
179 break;
180 default:
181 triplet->imsi[i] = data[0][i];
182 continue;
183 }
184 break;
185 }
186 hex2bin(data[1], triplet->rand, RAND_LEN);
187 hex2bin(data[2], triplet->sres, SRES_LEN);
188 hex2bin(data[3], triplet->kc, KC_LEN);
189
190 DBG4(DBG_CFG, "triplet: imsi %b\nrand %b\nsres %b\nkc %b",
191 triplet->imsi, IMSI_LEN, triplet->rand, RAND_LEN,
192 triplet->sres, SRES_LEN, triplet->kc, KC_LEN);
193 }
194 fclose(file);
195 DBG2(DBG_CFG, "read %d triplets from %s", triplet_count, TRIPLET_FILE);
196 }
197
198 /**
199 * Run the sim algorithm, see eap_sim.h
200 */
201 int sim_run_alg(const unsigned char *rand, int rand_length,
202 unsigned char *sres, int *sres_length,
203 unsigned char *kc, int *kc_length)
204 {
205 int current;
206
207 if (rand_length != RAND_LEN ||
208 *sres_length < SRES_LEN ||
209 *kc_length < KC_LEN)
210 {
211 return 1;
212 }
213
214 for (current = 0; current < triplet_count; current++)
215 {
216 if (memcmp(triplets[current].rand, rand, RAND_LEN) == 0)
217 {
218 memcpy(sres, triplets[current].sres, SRES_LEN);
219 memcpy(kc, triplets[current].kc, KC_LEN);
220 *sres_length = SRES_LEN;
221 *kc_length = KC_LEN;
222 return 0;
223 }
224 }
225 return 2;
226 }
227
228 /**
229 * Get a single triplet, see_eap_sim.h
230 */
231 int sim_get_triplet(char *imsi,
232 unsigned char *rand, int *rand_length,
233 unsigned char *sres, int *sres_length,
234 unsigned char *kc, int *kc_length)
235 {
236 int current;
237 triplet_t *triplet;
238 static int skip = -1;
239
240 DBG2(DBG_CFG, "getting triplet for %s", imsi);
241
242 if (*rand_length < RAND_LEN ||
243 *sres_length < SRES_LEN ||
244 *kc_length < KC_LEN)
245 {
246 return 1;
247 }
248 if (triplet_count == 0)
249 {
250 return 2;
251 }
252 for (current = 0; current < triplet_count; current++)
253 {
254 triplet = &triplets[current];
255
256 if (streq(imsi, triplet->imsi))
257 {
258 /* skip triplet if already used */
259 if (skip >= current)
260 {
261 continue;
262 }
263 *rand_length = RAND_LEN;
264 *sres_length = SRES_LEN;
265 *kc_length = KC_LEN;
266 memcpy(rand, triplet->rand, RAND_LEN);
267 memcpy(sres, triplet->sres, SRES_LEN);
268 memcpy(kc, triplet->kc, KC_LEN);
269 /* remember used triplet */
270 skip = current;
271 return 0;
272 }
273 }
274 if (skip > -1)
275 {
276 /* no triplet left, reuse triplets */
277 skip = -1;
278 return sim_get_triplet(imsi, rand, rand_length,
279 sres, sres_length, kc, kc_length);
280 }
281 return 2;
282 }
283