OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / freeswan / lib / 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  * RCSID $Id: ttodata.c,v 1.4 2002/03/12 17:04:58 henry Exp $
16  */
17 #include "internal.h"
18 #include "freeswan.h"
19
20 /* converters and misc */
21 static int unhex(const char *, char *, size_t);
22 static int unb64(const char *, char *, size_t);
23 static int untext(const char *, char *, size_t);
24 static const char *badch(const char *, int, char *, size_t);
25
26 /* internal error codes for converters */
27 #define SHORT   (-2)            /* internal buffer too short */
28 #define BADPAD  (-3)            /* bad base64 padding */
29 #define BADCH0  (-4)            /* invalid character 0 */
30 #define BADCH1  (-5)            /* invalid character 1 */
31 #define BADCH2  (-6)            /* invalid character 2 */
32 #define BADCH3  (-7)            /* invalid character 3 */
33 #define BADOFF(code) (BADCH0-(code))
34
35 /*
36  - ttodatav - convert text to data, with verbose error reports
37  * If some of this looks slightly odd, it's because it has changed
38  * repeatedly (from the original atodata()) without a major rewrite.
39  */
40 const char *                    /* NULL on success, else literal or errp */
41 ttodatav(src, srclen, base, dst, dstlen, lenp, errp, errlen)
42 const char *src;
43 size_t srclen;                  /* 0 means apply strlen() */
44 int base;                       /* 0 means figure it out */
45 char *dst;                      /* need not be valid if dstlen is 0 */
46 size_t dstlen;
47 size_t *lenp;                   /* where to record length (NULL is nowhere) */
48 char *errp;                     /* error buffer */
49 size_t errlen;
50 {
51         size_t ingroup;         /* number of input bytes converted at once */
52         char buf[4];            /* output from conversion */
53         int nbytes;             /* size of output */
54         int (*decode)(const char *, char *, size_t);
55         char *stop;
56         int ndone;
57         int i;
58         int underscoreok;
59
60         if (srclen == 0)
61                 srclen = strlen(src);
62         if (dstlen == 0)
63                 dst = buf;      /* point it somewhere valid */
64         stop = dst + dstlen;
65
66         if (base == 0) {
67                 if (srclen < 2)
68                         return "input too short to be valid";
69                 if (*src++ != '0')
70                         return "input does not begin with format prefix";
71                 switch (*src++) {
72                 case 'x':
73                 case 'X':
74                         base = 16;
75                         break;
76                 case 's':
77                 case 'S':
78                         base = 64;
79                         break;
80                 case 't':
81                 case 'T':
82                         base = 256;
83                         break;
84                 default:
85                         return "unknown format prefix";
86                         break;
87                 }
88                 srclen -= 2;
89         }
90         switch (base) {
91         case 16:
92                 ingroup = 2;
93                 decode = unhex;
94                 underscoreok = 1;
95                 break;
96         case 64:
97                 ingroup = 4;
98                 decode = unb64;
99                 underscoreok = 0;
100                 break;
101         case 256:
102                 ingroup = 1;
103                 decode = untext;
104                 underscoreok = 0;
105                 break;
106         default:
107                 return "unknown base";
108                 break;
109         }
110
111         /* proceed */
112         ndone = 0;
113         while (srclen >= ingroup) {
114                 nbytes = (*decode)(src, buf, sizeof(buf));
115                 switch (nbytes) {
116                 case BADCH0:
117                 case BADCH1:
118                 case BADCH2:
119                 case BADCH3:
120                         return badch(src, nbytes, errp, errlen);
121                         break;
122                 case SHORT:
123                         return "internal buffer too short (\"can't happen\")";
124                         break;
125                 case BADPAD:
126                         return "bad (non-zero) padding at end of base64 input";
127                         break;
128                 }
129                 if (nbytes <= 0)
130                         return "unknown internal error";
131                 for (i = 0; i < nbytes; i++) {
132                         if (dst < stop)
133                                 *dst++ = buf[i];
134                         ndone++;
135                 }
136                 src += ingroup;
137                 srclen -= ingroup;
138                 if (underscoreok && srclen > 1 && *src == '_') {
139                         /* srclen > 1 means not last character */
140                         src++;
141                         srclen--;
142                 }
143         }
144         if (srclen != 0)
145                 return "input ends in mid-byte, perhaps truncated";
146         if (ndone == 0)
147                 return "no data bytes specified by input";
148         if (lenp != NULL)
149                 *lenp = ndone;
150         return NULL;
151 }
152
153 /*
154  - ttodata - convert text to data
155  */
156 const char *                    /* NULL on success, else literal */
157 ttodata(src, srclen, base, dst, dstlen, lenp)
158 const char *src;
159 size_t srclen;                  /* 0 means apply strlen() */
160 int base;                       /* 0 means figure it out */
161 char *dst;                      /* need not be valid if dstlen is 0 */
162 size_t dstlen;
163 size_t *lenp;                   /* where to record length (NULL is nowhere) */
164 {
165         return ttodatav(src, srclen, base, dst, dstlen, lenp, (char *)NULL,
166                                                                 (size_t)0);
167 }
168
169 /*
170  - atodata - convert ASCII to data
171  * backward-compatibility interface
172  */
173 size_t                          /* 0 for failure, true length for success */
174 atodata(src, srclen, dst, dstlen)
175 const char *src;
176 size_t srclen;
177 char *dst;
178 size_t dstlen;
179 {
180         size_t len;
181         const char *err;
182
183         err = ttodata(src, srclen, 0, dst, dstlen, &len);
184         if (err != NULL)
185                 return 0;
186         return len;
187 }
188
189 /*
190  - atobytes - convert ASCII to data bytes
191  * another backward-compatibility interface
192  */
193 const char *
194 atobytes(src, srclen, dst, dstlen, lenp)
195 const char *src;
196 size_t srclen;
197 char *dst;
198 size_t dstlen;
199 size_t *lenp;
200 {
201         return ttodata(src, srclen, 0, dst, dstlen, lenp);
202 }
203
204 /*
205  - unhex - convert two ASCII hex digits to byte
206  */
207 static int              /* number of result bytes, or error code */
208 unhex(src, dst, dstlen)
209 const char *src;        /* known to be full length */
210 char *dst;
211 size_t dstlen;          /* not large enough is a failure */
212 {
213         char *p;
214         unsigned byte;
215         static char hex[] = "0123456789abcdef";
216
217         if (dstlen < 1)
218                 return SHORT;
219
220         p = strchr(hex, *src);
221         if (p == NULL)
222                 p = strchr(hex, tolower(*src));
223         if (p == NULL)
224                 return BADCH0;
225         byte = (p - hex) << 4;
226         src++;
227
228         p = strchr(hex, *src);
229         if (p == NULL)
230                 p = strchr(hex, tolower(*src));
231         if (p == NULL)
232                 return BADCH1;
233         byte |= (p - hex);
234
235         *dst = byte;
236         return 1;
237 }
238
239 /*
240  - unb64 - convert four ASCII base64 digits to three bytes
241  * Note that a base64 digit group is padded out with '=' if it represents
242  * less than three bytes:  one byte is dd==, two is ddd=, three is dddd.
243  */
244 static int              /* number of result bytes, or error code */
245 unb64(src, dst, dstlen)
246 const char *src;        /* known to be full length */
247 char *dst;
248 size_t dstlen;
249 {
250         char *p;
251         unsigned byte1;
252         unsigned byte2;
253         static char base64[] =
254         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
255
256         if (dstlen < 3)
257                 return SHORT;
258
259         p = strchr(base64, *src++);
260         if (p == NULL)
261                 return BADCH0;
262         byte1 = (p - base64) << 2;      /* first six bits */
263
264         p = strchr(base64, *src++);
265         if (p == NULL)
266                 return BADCH1;
267         byte2 = p - base64;             /* next six:  two plus four */
268         *dst++ = byte1 | (byte2 >> 4);
269         byte1 = (byte2 & 0xf) << 4;
270
271         p = strchr(base64, *src++);
272         if (p == NULL) {
273                 if (*(src-1) == '=' && *src == '=') {
274                         if (byte1 != 0)         /* bad padding */
275                                 return BADPAD;
276                         return 1;
277                 }
278                 return BADCH2;
279         }
280         byte2 = p - base64;             /* next six:  four plus two */
281         *dst++ = byte1 | (byte2 >> 2);
282         byte1 = (byte2 & 0x3) << 6;
283
284         p = strchr(base64, *src++);
285         if (p == NULL) {
286                 if (*(src-1) == '=') {
287                         if (byte1 != 0)         /* bad padding */
288                                 return BADPAD;
289                         return 2;
290                 }
291                 return BADCH3;
292         }
293         byte2 = p - base64;             /* last six */
294         *dst++ = byte1 | byte2;
295         return 3;
296 }
297
298 /*
299  - untext - convert one ASCII character to byte
300  */
301 static int              /* number of result bytes, or error code */
302 untext(src, dst, dstlen)
303 const char *src;        /* known to be full length */
304 char *dst;
305 size_t dstlen;          /* not large enough is a failure */
306 {
307         if (dstlen < 1)
308                 return SHORT;
309
310         *dst = *src;
311         return 1;
312 }
313
314 /*
315  - badch - produce a nice complaint about an unknown character
316  *
317  * If the compiler complains that the array bigenough[] has a negative
318  * size, that means the TTODATAV_BUF constant has been set too small.
319  */
320 static const char *             /* literal or errp */
321 badch(src, errcode, errp, errlen)
322 const char *src;
323 int errcode;
324 char *errp;                     /* might be NULL */
325 size_t errlen;
326 {
327         static const char pre[] = "unknown character (`";
328         static const char suf[] = "') in input";
329         char buf[5];
330 #       define  REQD    (sizeof(pre) - 1 + sizeof(buf) - 1 + sizeof(suf))
331         struct sizecheck {
332                 char bigenough[TTODATAV_BUF - REQD];    /* see above */
333         };
334         char ch;
335
336         if (errp == NULL || errlen < REQD)
337                 return "unknown character in input";
338         strcpy(errp, pre);
339         ch = *(src + BADOFF(errcode));
340         if (isprint(ch)) {
341                 buf[0] = ch;
342                 buf[1] = '\0';
343         } else {
344                 buf[0] = '\\';
345                 buf[1] = ((ch & 0700) >> 6) + '0';
346                 buf[2] = ((ch & 0070) >> 3) + '0';
347                 buf[3] = ((ch & 0007) >> 0) + '0';
348                 buf[4] = '\0';
349         }
350         strcat(errp, buf);
351         strcat(errp, suf);
352         return (const char *)errp;
353 }
354
355
356
357 #ifdef TTODATA_MAIN
358
359 #include <stdio.h>
360
361 void regress();
362 void hexout();
363
364 /*
365  - main - convert first argument to hex, or run regression
366  */
367 int
368 main(argc, argv)
369 int argc;
370 char *argv[];
371 {
372         char buf[1024];
373         char buf2[1024];
374         char err[512];
375         size_t n;
376         size_t i;
377         char *p = buf;
378         char *p2 = buf2;
379         char *pgm = argv[0];
380         const char *oops;
381
382         if (argc < 2) {
383                 fprintf(stderr, "Usage: %s {0x<hex>|0s<base64>|-r}\n", pgm);
384                 exit(2);
385         }
386
387         if (strcmp(argv[1], "-r") == 0) {
388                 regress(pgm);   /* should not return */
389                 fprintf(stderr, "%s: regress() returned?!?\n", pgm);
390                 exit(1);
391         }
392
393         oops = ttodatav(argv[1], 0, 0, buf, sizeof(buf), &n, err, sizeof(err));
394         if (oops != NULL) {
395                 fprintf(stderr, "%s: ttodata error `%s' in `%s'\n", pgm,
396                                                                 oops, argv[1]);
397                 exit(1);
398         }
399
400         if (n > sizeof(buf)) {
401                 p = (char *)malloc((size_t)n);
402                 if (p == NULL) {
403                         fprintf(stderr,
404                                 "%s: unable to malloc %d bytes for result\n",
405                                 pgm, n);
406                         exit(1);
407                 }
408                 oops = ttodata(argv[1], 0, 0, p, n, &n);
409                 if (oops != NULL) {
410                         fprintf(stderr, "%s: error `%s' in ttodata retry?!?\n",
411                                                                 pgm, oops);
412                         exit(1);
413                 }
414         }
415
416         hexout(p, n, stdout);
417         printf("\n");
418
419         i = datatot(buf, n, 'h', buf2, sizeof(buf2));
420         if (i == 0) {
421                 fprintf(stderr, "%s: datatot reports error in `%s'\n", pgm,
422                                                                 argv[1]);
423                 exit(1);
424         }
425
426         if (i > sizeof(buf2)) {
427                 p2 = (char *)malloc((size_t)i);
428                 if (p == NULL) {
429                         fprintf(stderr,
430                                 "%s: unable to malloc %d bytes for result\n",
431                                 pgm, i);
432                         exit(1);
433                 }
434                 i = datatot(buf, n, 'h', p2, i);
435                 if (i == 0) {
436                         fprintf(stderr, "%s: error in datatoa retry?!?\n", pgm);
437                         exit(1);
438                 }
439         }
440
441         printf("%s\n", p2);
442
443         exit(0);
444 }
445
446 /*
447  - hexout - output an arbitrary-length string in hex
448  */
449 void
450 hexout(s, len, f)
451 const char *s;
452 size_t len;
453 FILE *f;
454 {
455         size_t i;
456
457         fprintf(f, "0x");
458         for (i = 0; i < len; i++)
459                 fprintf(f, "%02x", (unsigned char)s[i]);
460 }
461
462 struct artab {
463         int base;
464         char *ascii;            /* NULL for end */
465         char *data;             /* NULL for error expected */
466 } atodatatab[] = {
467         0, "",                  NULL,
468         0, "0",                 NULL,
469         0, "0x",                NULL,
470         0, "0xa",               NULL,
471         0, "0xab",              "\xab",
472         0, "0xabc",             NULL,
473         0, "0xabcd",            "\xab\xcd",
474         0, "0x0123456789",      "\x01\x23\x45\x67\x89",
475         0, "0x01x",             NULL,
476         0, "0xabcdef",          "\xab\xcd\xef",
477         0, "0xABCDEF",          "\xab\xcd\xef",
478         0, "0XaBc0eEd81f",      "\xab\xc0\xee\xd8\x1f",
479         0, "0XaBc0_eEd8",       "\xab\xc0\xee\xd8",
480         0, "0XaBc0_",           NULL,
481         0, "0X_aBc0",           NULL,
482         0, "0Xa_Bc0",           NULL,
483         16, "aBc0_eEd8",        "\xab\xc0\xee\xd8",
484         0, "0s",                NULL,
485         0, "0sA",               NULL,
486         0, "0sBA",              NULL,
487         0, "0sCBA",             NULL,
488         0, "0sDCBA",            "\x0c\x20\x40",
489         0, "0SDCBA",            "\x0c\x20\x40",
490         0, "0sDA==",            "\x0c",
491         0, "0sDC==",            NULL,
492         0, "0sDCA=",            "\x0c\x20",
493         0, "0sDCB=",            NULL,
494         0, "0sDCAZ",            "\x0c\x20\x19",
495         0, "0sDCAa",            "\x0c\x20\x1a",
496         0, "0sDCAz",            "\x0c\x20\x33",
497         0, "0sDCA0",            "\x0c\x20\x34",
498         0, "0sDCA9",            "\x0c\x20\x3d",
499         0, "0sDCA+",            "\x0c\x20\x3e",
500         0, "0sDCA/",            "\x0c\x20\x3f",
501         0, "0sAbraCadabra+",    "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe",
502         64, "AbraCadabra+",     "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe",
503         0, "0t",                NULL,
504         0, "0tabc_xyz",         "abc_xyz",
505         256, "abc_xyz",         "abc_xyz",
506         0, NULL,                NULL,
507 };
508
509 struct drtab {
510         char *data;     /* input; NULL for end */
511         char format;
512         int buflen;     /* -1 means big buffer */
513         int outlen;     /* -1 means strlen(ascii)+1 */
514         char *ascii;    /* NULL for error expected */
515 } datatoatab[] = {
516         "",                     'x',    -1,     -1,     NULL,
517         "",                     'X',    -1,     -1,     NULL,
518         "",                     'n',    -1,     -1,     NULL,
519         "0",                    'x',    -1,     -1,     "0x30",
520         "0",                    'x',    0,      5,      "---",
521         "0",                    'x',    1,      5,      "",
522         "0",                    'x',    2,      5,      "0",
523         "0",                    'x',    3,      5,      "0x",
524         "0",                    'x',    4,      5,      "0x3",
525         "0",                    'x',    5,      5,      "0x30",
526         "0",                    'x',    6,      5,      "0x30",
527         "\xab\xcd",             'x',    -1,     -1,     "0xabcd",
528         "\x01\x23\x45\x67\x89", 'x',    -1,     -1,     "0x0123456789",
529         "\xab\xcd\xef",         'x',    -1,     -1,     "0xabcdef",
530         "\xab\xc0\xee\xd8\x1f", 'x',    -1,     -1,     "0xabc0eed81f",
531         "\x01\x02",             'h',    -1,     -1,     "0x0102",
532         "\x01\x02\x03\x04\x05\x06",     'h',    -1, -1, "0x01020304_0506",
533         "\xab\xc0\xee\xd8\x1f", 16,     -1,     -1,     "abc0eed81f",
534         "\x0c\x20\x40",         's',    -1,     -1,     "0sDCBA",
535         "\x0c\x20\x40",         's',    0,      7,      "---",
536         "\x0c\x20\x40",         's',    1,      7,      "",
537         "\x0c\x20\x40",         's',    2,      7,      "0",
538         "\x0c\x20\x40",         's',    3,      7,      "0s",
539         "\x0c\x20\x40",         's',    4,      7,      "0sD",
540         "\x0c\x20\x40",         's',    5,      7,      "0sDC",
541         "\x0c\x20\x40",         's',    6,      7,      "0sDCB",
542         "\x0c\x20\x40",         's',    7,      7,      "0sDCBA",
543         "\x0c\x20\x40",         's',    8,      7,      "0sDCBA",
544         "\x0c",                 's',    -1,     -1,     "0sDA==",
545         "\x0c\x20",             's',    -1,     -1,     "0sDCA=",
546         "\x0c\x20\x19",         's',    -1,     -1,     "0sDCAZ",
547         "\x0c\x20\x1a",         's',    -1,     -1,     "0sDCAa",
548         "\x0c\x20\x33",         's',    -1,     -1,     "0sDCAz",
549         "\x0c\x20\x34",         's',    -1,     -1,     "0sDCA0",
550         "\x0c\x20\x3d",         's',    -1,     -1,     "0sDCA9",       
551         "\x0c\x20\x3e",         's',    -1,     -1,     "0sDCA+",
552         "\x0c\x20\x3f",         's',    -1,     -1,     "0sDCA/",       
553         "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 's', -1, -1, "0sAbraCadabra+",
554         "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 64, -1, -1, "AbraCadabra+",
555         NULL,                   'x',    -1,     -1,     NULL,
556 };
557
558 /*
559  - regress - regression-test ttodata() and datatot()
560  */
561 void                    /* should not return at all, in fact */
562 regress(pgm)
563 char *pgm;
564 {
565         struct artab *r;
566         struct drtab *dr;
567         char buf[100];
568         size_t n;
569         int status = 0;
570         size_t should;
571         const char *oops;
572
573         for (r = atodatatab; r->ascii != NULL; r++) {
574                 oops = ttodata(r->ascii, 0, r->base, buf, sizeof(buf), &n);
575                 if (oops != NULL && r->data == NULL)
576                         {}                      /* error expected */
577                 else if (oops != NULL) {
578                         printf("`%s' gave error `%s', expecting %d `", r->ascii,
579                                                         oops, strlen(r->data));
580                         hexout(r->data, strlen(r->data), stdout);
581                         printf("'\n");
582                         status = 1;
583                 } else if (r->data == NULL) {
584                         printf("`%s' gave %d `", r->ascii, n);
585                         hexout(buf, n, stdout);
586                         printf("', expecting error\n");
587                         status = 1;
588                 } else if (n != strlen(r->data)) {
589                         printf("length wrong in `%s': got %d `", r->ascii, n);
590                         hexout(buf, n, stdout);
591                         printf("', expecting %d `", strlen(r->data));
592                         hexout(r->data, strlen(r->data), stdout);
593                         printf("'\n");
594                         status = 1;
595                 } else if (memcmp(buf, r->data, n) != 0) {
596                         printf("`%s' gave %d `", r->ascii, n);
597                         hexout(buf, n, stdout);
598                         printf("', expecting %d `", strlen(r->data));
599                         hexout(r->data, strlen(r->data), stdout);
600                         printf("'\n");
601                         status = 1;
602                 }
603                 fflush(stdout);
604         }
605         for (dr = datatoatab; dr->data != NULL; dr++) {
606                 strcpy(buf, "---");
607                 n = datatot(dr->data, strlen(dr->data), dr->format, buf,
608                                 (dr->buflen == -1) ? sizeof(buf) : dr->buflen);
609                 should = (dr->ascii == NULL) ? 0 : strlen(dr->ascii) + 1;
610                 if (dr->outlen != -1)
611                         should = dr->outlen;
612                 if (n == 0 && dr->ascii == NULL)
613                         {}                      /* error expected */
614                 else if (n == 0) {
615                         printf("`");
616                         hexout(dr->data, strlen(dr->data), stdout);
617                         printf("' %c gave error, expecting %d `%s'\n",
618                                 dr->format, should, dr->ascii);
619                         status = 1;
620                 } else if (dr->ascii == NULL) {
621                         printf("`");
622                         hexout(dr->data, strlen(dr->data), stdout);
623                         printf("' %c gave %d `%.*s', expecting error\n",
624                                 dr->format, n, n, buf);
625                         status = 1;
626                 } else if (n != should) {
627                         printf("length wrong in `");
628                         hexout(dr->data, strlen(dr->data), stdout);
629                         printf("': got %d `%s'", n, buf);
630                         printf(", expecting %d `%s'\n", should, dr->ascii);
631                         status = 1;
632                 } else if (strcmp(buf, dr->ascii) != 0) {
633                         printf("`");
634                         hexout(dr->data, strlen(dr->data), stdout);
635                         printf("' gave %d `%s'", n, buf);
636                         printf(", expecting %d `%s'\n", should, dr->ascii);
637                         status = 1;
638                 }
639                 fflush(stdout);
640         }
641         exit(status);
642 }
643
644 #endif /* TTODATA_MAIN */