The introduced SHA1_NOFINAL hasher was not sufficient for EAP-AKA,
[strongswan.git] / src / libstrongswan / chunk.c
1 /*
2 * Copyright (C) 2005-2006 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 *
16 * $Id$
17 */
18
19 #include <stdio.h>
20 #include <sys/stat.h>
21
22 #include "chunk.h"
23
24 #include <debug.h>
25 #include <printf_hook.h>
26 #include <utils/randomizer.h>
27
28 /**
29 * Empty chunk.
30 */
31 chunk_t chunk_empty = { NULL, 0 };
32
33 /**
34 * Described in header.
35 */
36 chunk_t chunk_create(u_char *ptr, size_t len)
37 {
38 chunk_t chunk = {ptr, len};
39 return chunk;
40 }
41
42 /**
43 * Described in header.
44 */
45 chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk)
46 {
47 chunk_t clone = chunk_empty;
48
49 if (chunk.ptr && chunk.len > 0)
50 {
51 clone.ptr = ptr;
52 clone.len = chunk.len;
53 memcpy(clone.ptr, chunk.ptr, chunk.len);
54 }
55
56 return clone;
57 }
58
59 /**
60 * Decribed in header.
61 */
62 size_t chunk_length(const char* mode, ...)
63 {
64 va_list chunks;
65 size_t length = 0;
66
67 va_start(chunks, mode);
68 while (TRUE)
69 {
70 switch (*mode++)
71 {
72 case 'm':
73 case 'c':
74 {
75 chunk_t ch = va_arg(chunks, chunk_t);
76 length += ch.len;
77 continue;
78 }
79 default:
80 break;
81 }
82 break;
83 }
84 va_end(chunks);
85 return length;
86 }
87
88 /**
89 * Decribed in header.
90 */
91 chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...)
92 {
93 va_list chunks;
94 chunk_t construct = chunk_create(ptr, 0);
95
96 va_start(chunks, mode);
97 while (TRUE)
98 {
99 bool free_chunk = FALSE;
100 switch (*mode++)
101 {
102 case 'm':
103 {
104 free_chunk = TRUE;
105 }
106 case 'c':
107 {
108 chunk_t ch = va_arg(chunks, chunk_t);
109 memcpy(ptr, ch.ptr, ch.len);
110 ptr += ch.len;
111 construct.len += ch.len;
112 if (free_chunk)
113 {
114 free(ch.ptr);
115 }
116 continue;
117 }
118 default:
119 break;
120 }
121 break;
122 }
123 va_end(chunks);
124
125 return construct;
126 }
127
128 /**
129 * Decribed in header.
130 */
131 void chunk_split(chunk_t chunk, const char *mode, ...)
132 {
133 va_list chunks;
134 size_t len;
135 chunk_t *ch;
136
137 va_start(chunks, mode);
138 while (TRUE)
139 {
140 if (*mode == '\0')
141 {
142 break;
143 }
144 len = va_arg(chunks, size_t);
145 ch = va_arg(chunks, chunk_t*);
146 /* a null chunk means skip len bytes */
147 if (ch == NULL)
148 {
149 chunk = chunk_skip(chunk, len);
150 continue;
151 }
152 switch (*mode++)
153 {
154 case 'm':
155 {
156 ch->len = min(chunk.len, len);
157 if (ch->len)
158 {
159 ch->ptr = chunk.ptr;
160 }
161 else
162 {
163 ch->ptr = NULL;
164 }
165 chunk = chunk_skip(chunk, ch->len);
166 continue;
167 }
168 case 'a':
169 {
170 ch->len = min(chunk.len, len);
171 if (ch->len)
172 {
173 ch->ptr = malloc(ch->len);
174 memcpy(ch->ptr, chunk.ptr, ch->len);
175 }
176 else
177 {
178 ch->ptr = NULL;
179 }
180 chunk = chunk_skip(chunk, ch->len);
181 continue;
182 }
183 case 'c':
184 {
185 ch->len = min(ch->len, chunk.len);
186 ch->len = min(ch->len, len);
187 if (ch->len)
188 {
189 memcpy(ch->ptr, chunk.ptr, ch->len);
190 }
191 else
192 {
193 ch->ptr = NULL;
194 }
195 chunk = chunk_skip(chunk, ch->len);
196 continue;
197 }
198 default:
199 break;
200 }
201 break;
202 }
203 va_end(chunks);
204 }
205
206 /**
207 * Described in header.
208 */
209 bool chunk_write(chunk_t chunk, const char *path, const char *label, mode_t mask, bool force)
210 {
211 mode_t oldmask;
212 FILE *fd;
213
214 if (!force)
215 {
216 fd = fopen(path, "r");
217 if (fd)
218 {
219 fclose(fd);
220 DBG1(" %s file '%s' already exists", label, path);
221 return FALSE;
222 }
223 }
224
225 /* set umask */
226 oldmask = umask(mask);
227
228 fd = fopen(path, "w");
229
230 if (fd)
231 {
232 fwrite(chunk.ptr, sizeof(u_char), chunk.len, fd);
233 fclose(fd);
234 DBG1(" written %s file '%s' (%u bytes)", label, path, chunk.len);
235 umask(oldmask);
236 return TRUE;
237 }
238 else
239 {
240 DBG1(" could not open %s file '%s' for writing", label, path);
241 umask(oldmask);
242 return FALSE;
243 }
244 }
245
246 /** hex conversion digits */
247 static char hexdig_upper[] = "0123456789ABCDEF";
248 static char hexdig_lower[] = "0123456789abcdef";
249
250 /**
251 * Described in header.
252 */
253 char *chunk_to_hex(chunk_t chunk, bool uppercase)
254 {
255 int i;
256 char *str;
257 char *hexdig = hexdig_lower;
258
259 if (uppercase)
260 {
261 hexdig = hexdig_upper;
262 }
263
264 str = malloc(chunk.len * 2 + 1);
265 str[chunk.len * 2] = '\0';
266
267 for (i = 0; i < chunk.len; i ++)
268 {
269 str[i*2] = hexdig[(chunk.ptr[i] >> 4) & 0xF];
270 str[i*2+1] = hexdig[(chunk.ptr[i] ) & 0xF];
271 }
272 return str;
273 }
274
275 /**
276 * Described in header.
277 */
278 void chunk_free(chunk_t *chunk)
279 {
280 free(chunk->ptr);
281 chunk->ptr = NULL;
282 chunk->len = 0;
283 }
284
285 /**
286 * Described in header.
287 */
288 void chunk_free_randomized(chunk_t *chunk)
289 {
290 if (chunk->ptr)
291 {
292 if (chunk->len > 0)
293 {
294 randomizer_t *randomizer = randomizer_create();
295
296 randomizer->get_pseudo_random_bytes(randomizer,
297 chunk->len, chunk->ptr);
298 randomizer->destroy(randomizer);
299 };
300 free(chunk->ptr);
301 chunk->ptr = NULL;
302 }
303 chunk->len = 0;
304 }
305
306 /**
307 * Described in header.
308 */
309 chunk_t chunk_skip(chunk_t chunk, size_t bytes)
310 {
311 if (chunk.len > bytes)
312 {
313 chunk.ptr += bytes;
314 chunk.len -= bytes;
315 return chunk;
316 }
317 return chunk_empty;
318 }
319
320 /**
321 * Described in header.
322 */
323 int chunk_compare(chunk_t a, chunk_t b)
324 {
325 int compare_len = a.len - b.len;
326 int len = (compare_len < 0)? a.len : b.len;
327
328 if (compare_len != 0 || len == 0)
329 {
330 return compare_len;
331 }
332 return memcmp(a.ptr, b.ptr, len);
333 };
334
335 /**
336 * Described in header.
337 */
338 bool chunk_equals(chunk_t a, chunk_t b)
339 {
340 return a.ptr != NULL && b.ptr != NULL &&
341 a.len == b.len && memeq(a.ptr, b.ptr, a.len);
342 }
343
344 /**
345 * Described in header.
346 */
347 bool chunk_equals_or_null(chunk_t a, chunk_t b)
348 {
349 if (a.ptr == NULL || b.ptr == NULL)
350 return TRUE;
351 return a.len == b.len && memeq(a.ptr, b.ptr, a.len);
352 }
353
354 /**
355 * output handler in printf() for chunks
356 */
357 static int chunk_print(FILE *stream, const struct printf_info *info,
358 const void *const *args)
359 {
360 chunk_t *chunk = *((chunk_t**)(args[0]));
361 bool first = TRUE;
362 chunk_t copy = *chunk;
363 int written = 0;
364 printf_hook_functions_t mem = mem_get_printf_hooks();
365
366 if (!info->alt)
367 {
368 const void *new_args[] = {&chunk->ptr, &chunk->len};
369 return mem.print(stream, info, new_args);
370 }
371
372 while (copy.len > 0)
373 {
374 if (first)
375 {
376 first = FALSE;
377 }
378 else
379 {
380 written += fprintf(stream, ":");
381 }
382 written += fprintf(stream, "%02x", *copy.ptr++);
383 copy.len--;
384 }
385 return written;
386 }
387
388 /**
389 * arginfo handler for printf() mem ranges
390 */
391 static int chunk_arginfo(const struct printf_info *info, size_t n, int *argtypes)
392 {
393 if (n > 0)
394 {
395 argtypes[0] = PA_POINTER;
396 }
397 return 1;
398 }
399
400 /**
401 * return printf hook functions for a chunk
402 */
403 printf_hook_functions_t chunk_get_printf_hooks()
404 {
405 printf_hook_functions_t hooks = {chunk_print, chunk_arginfo};
406
407 return hooks;
408 }
409