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