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