removed unused gmp.h to build libstrongswan without libgmp
[strongswan.git] / src / libstrongswan / asn1 / ttodata.c
1 /*
2 * convert from text form of arbitrary data (e.g., keys) to binary
3 * Copyright (C) 2000 Henry Spencer.
4 *
5 * This library is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Library General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
9 *
10 * This library 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 Library General Public
13 * License for more details.
14 *
15 * $Id$
16 */
17
18 #include "ttodata.h"
19
20 #include <string.h>
21 #include <ctype.h>
22
23 /* converters and misc */
24 static int unhex(const char *, char *, size_t);
25 static int unb64(const char *, char *, size_t);
26 static int untext(const char *, char *, size_t);
27 static const char *badch(const char *, int, char *, size_t);
28
29 /* internal error codes for converters */
30 #define SHORT (-2) /* internal buffer too short */
31 #define BADPAD (-3) /* bad base64 padding */
32 #define BADCH0 (-4) /* invalid character 0 */
33 #define BADCH1 (-5) /* invalid character 1 */
34 #define BADCH2 (-6) /* invalid character 2 */
35 #define BADCH3 (-7) /* invalid character 3 */
36 #define BADOFF(code) (BADCH0-(code))
37
38 /**
39 * convert text to data, with verbose error reports
40 *
41 * If some of this looks slightly odd, it's because it has changed
42 * repeatedly (from the original atodata()) without a major rewrite.
43 *
44 * @param src
45 * @param srclen 0 means apply strlen()
46 * @param base 0 means figure it out
47 * @param dst need not be valid if dstlen is 0
48 * @param dstlen
49 * @param lenp where to record length (NULL is nowhere)
50 * @param errp error buffer
51 * @param flags
52 * @return NULL on success, else literal or errp
53 */
54 const char *ttodatav(const char *src, size_t srclen, int base, char *dst, size_t dstlen, size_t *lenp, char *errp, size_t errlen, unsigned int flags)
55 {
56 size_t ingroup; /* number of input bytes converted at once */
57 char buf[4]; /* output from conversion */
58 int nbytes; /* size of output */
59 int (*decode)(const char *, char *, size_t);
60 char *stop;
61 int ndone;
62 int i;
63 int underscoreok;
64 int skipSpace = 0;
65
66 if (srclen == 0)
67 {
68 srclen = strlen(src);
69 }
70 if (dstlen == 0)
71 {
72 dst = buf; /* point it somewhere valid */
73 }
74 stop = dst + dstlen;
75
76 if (base == 0)
77 {
78 if (srclen < 2)
79 {
80 return "input too short to be valid";
81 }
82 if (*src++ != '0')
83 {
84 return "input does not begin with format prefix";
85 }
86 switch (*src++)
87 {
88 case 'x':
89 case 'X':
90 base = 16;
91 break;
92 case 's':
93 case 'S':
94 base = 64;
95 break;
96 case 't':
97 case 'T':
98 base = 256;
99 break;
100 default:
101 return "unknown format prefix";
102 }
103 srclen -= 2;
104 }
105 switch (base)
106 {
107 case 16:
108 decode = unhex;
109 underscoreok = 1;
110 ingroup = 2;
111 break;
112 case 64:
113 decode = unb64;
114 underscoreok = 0;
115 ingroup = 4;
116 if(flags & TTODATAV_IGNORESPACE)
117 {
118 skipSpace = 1;
119 }
120 break;
121 case 256:
122 decode = untext;
123 ingroup = 1;
124 underscoreok = 0;
125 break;
126 default:
127 return "unknown base";
128 }
129
130 /* proceed */
131 ndone = 0;
132 while (srclen > 0)
133 {
134 char stage[4]; /* staging area for group */
135 size_t sl = 0;
136
137 /* Grab ingroup characters into stage,
138 * squeezing out blanks if we are supposed to ignore them.
139 */
140 for (sl = 0; sl < ingroup; src++, srclen--)
141 {
142 if (srclen == 0)
143 {
144 return "input ends in mid-byte, perhaps truncated";
145 }
146 else if (!(skipSpace && (*src == ' ' || *src == '\t')))
147 {
148 stage[sl++] = *src;
149 }
150 }
151
152 nbytes = (*decode)(stage, buf, sizeof(buf));
153 switch (nbytes)
154 {
155 case BADCH0:
156 case BADCH1:
157 case BADCH2:
158 case BADCH3:
159 return badch(stage, nbytes, errp, errlen);
160 case SHORT:
161 return "internal buffer too short (\"can't happen\")";
162 case BADPAD:
163 return "bad (non-zero) padding at end of base64 input";
164 }
165 if (nbytes <= 0)
166 {
167 return "unknown internal error";
168 }
169 for (i = 0; i < nbytes; i++)
170 {
171 if (dst < stop)
172 {
173 *dst++ = buf[i];
174 }
175 ndone++;
176 }
177 while (srclen >= 1 && skipSpace && (*src == ' ' || *src == '\t'))
178 {
179 src++;
180 srclen--;
181 }
182 if (underscoreok && srclen > 1 && (*src == '_' || *src == ':'))
183 {
184 /* srclen > 1 means not last character */
185 src++;
186 srclen--;
187 }
188 }
189
190 if (ndone == 0)
191 {
192 return "no data bytes specified by input";
193 }
194 if (lenp != NULL)
195 {
196 *lenp = ndone;
197 }
198 return NULL;
199 }
200
201 /**
202 * ttodata - convert text to data
203 *
204 * @param src
205 * @param srclen 0 means apply strlen()
206 * @param base 0 means figure it out
207 * @param dst need not be valid if dstlen is 0
208 * @param dstlen
209 * @param lenp where to record length (NULL is nowhere)
210 * @return NULL on success, else literal
211 */
212 const char *ttodata(const char *src, size_t srclen, int base, char *dst, size_t dstlen, size_t *lenp)
213 {
214 return ttodatav(src, srclen, base, dst, dstlen, lenp, (char *)NULL,
215 (size_t)0, TTODATAV_SPACECOUNTS);
216 }
217
218 /**
219 * atodata - convert ASCII to data
220 *
221 * backward-compatibility interface
222 *
223 * @param src
224 * @param srclen
225 * @param dst
226 * @param dstlen
227 * @return 0 for failure, true length for success
228 */
229 size_t atodata(const char *src, size_t srclen, char *dst, size_t dstlen)
230 {
231 size_t len;
232 const char *err;
233
234 err = ttodata(src, srclen, 0, dst, dstlen, &len);
235 return (err)? 0:len;
236 }
237
238 /**
239 * atobytes - convert ASCII to data bytes
240 *
241 * another backward-compatibility interface
242 */
243 const char *atobytes(const char *src, size_t srclen, char *dst, size_t dstlen, size_t *lenp)
244 {
245 return ttodata(src, srclen, 0, dst, dstlen, lenp);
246 }
247
248 /**
249 * unhex - convert two ASCII hex digits to byte
250 *
251 * @param src known to be full length
252 * @param dstnumber of result bytes, or error code
253 * @param dstlen not large enough is a failure
254 * @return
255 */
256 static int unhex(const char *src, char *dst, size_t dstlen)
257 {
258 char *p;
259 unsigned byte;
260 static char hex[] = "0123456789abcdef";
261
262 if (dstlen < 1)
263 {
264 return SHORT;
265 }
266
267 p = strchr(hex, *src);
268 if (p == NULL)
269 {
270 p = strchr(hex, tolower(*src));
271 }
272 if (p == NULL)
273 {
274 return BADCH0;
275 }
276 byte = (p - hex) << 4;
277 src++;
278
279 p = strchr(hex, *src);
280 if (p == NULL)
281 {
282 p = strchr(hex, tolower(*src));
283 }
284 if (p == NULL)
285 {
286 return BADCH1;
287 }
288 byte |= (p - hex);
289
290 *dst = byte;
291 return 1;
292 }
293
294 /**
295 * unb64 - convert four ASCII base64 digits to three bytes
296 *
297 * Note that a base64 digit group is padded out with '=' if it represents
298 * less than three bytes: one byte is dd==, two is ddd=, three is dddd.
299 *
300 * @param src known to be full length
301 * @param dst
302 * @param dstlen
303 * @return number of result bytes, or error code
304 */
305 static int unb64(const char *src, char *dst, size_t dstlen)
306 {
307 char *p;
308 unsigned byte1;
309 unsigned byte2;
310 static char base64[] =
311 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
312
313 if (dstlen < 3)
314 {
315 return SHORT;
316 }
317 p = strchr(base64, *src++);
318
319 if (p == NULL)
320 {
321 return BADCH0;
322 }
323 byte1 = (p - base64) << 2; /* first six bits */
324
325 p = strchr(base64, *src++);
326 if (p == NULL)
327 {
328 return BADCH1;
329 }
330
331 byte2 = p - base64; /* next six: two plus four */
332 *dst++ = byte1 | (byte2 >> 4);
333 byte1 = (byte2 & 0xf) << 4;
334
335 p = strchr(base64, *src++);
336 if (p == NULL)
337 {
338 if (*(src-1) == '=' && *src == '=')
339 {
340 if (byte1 != 0) /* bad padding */
341 {
342 return BADPAD;
343 }
344 return 1;
345 }
346 return BADCH2;
347 }
348
349 byte2 = p - base64; /* next six: four plus two */
350 *dst++ = byte1 | (byte2 >> 2);
351 byte1 = (byte2 & 0x3) << 6;
352
353 p = strchr(base64, *src++);
354 if (p == NULL)
355 {
356 if (*(src-1) == '=')
357 {
358 if (byte1 != 0) /* bad padding */
359 {
360 return BADPAD;
361 }
362 return 2;
363 }
364 return BADCH3;
365 }
366 byte2 = p - base64; /* last six */
367 *dst++ = byte1 | byte2;
368
369 return 3;
370 }
371
372 /**
373 * untext - convert one ASCII character to byte
374 *
375 * @param src known to be full length
376 * @param dst
377 * @param dstlen not large enough is a failure
378 * @return number of result bytes, or error code
379 */
380 static int untext(const char *src, char *dst, size_t dstlen)
381 {
382 if (dstlen < 1)
383 {
384 return SHORT;
385 }
386 *dst = *src;
387 return 1;
388 }
389
390 /**
391 * badch - produce a nice complaint about an unknown character
392 *
393 * If the compiler complains that the array bigenough[] has a negative
394 * size, that means the TTODATAV_BUF constant has been set too small.
395 *
396 * @param src
397 * @param errcode
398 * @param errp might be NULL
399 * @param errlen
400 * @return literal or errp
401 */
402 static const char *badch(const char *src, int errcode, char *errp, size_t errlen)
403 {
404 static const char pre[] = "unknown character (`";
405 static const char suf[] = "') in input";
406 char buf[5];
407 # define REQD (sizeof(pre) - 1 + sizeof(buf) - 1 + sizeof(suf))
408 struct sizecheck {
409 char bigenough[TTODATAV_BUF - REQD]; /* see above */
410 };
411 char ch;
412
413 if (errp == NULL || errlen < REQD)
414 {
415 return "unknown character in input";
416 }
417 strcpy(errp, pre);
418 ch = *(src + BADOFF(errcode));
419 if (isprint(ch))
420 {
421 buf[0] = ch;
422 buf[1] = '\0';
423 }
424 else
425 {
426 buf[0] = '\\';
427 buf[1] = ((ch & 0700) >> 6) + '0';
428 buf[2] = ((ch & 0070) >> 3) + '0';
429 buf[3] = ((ch & 0007) >> 0) + '0';
430 buf[4] = '\0';
431 }
432 strcat(errp, buf);
433 strcat(errp, suf);
434 return (const char *)errp;
435 }