summaryrefslogtreecommitdiffabout
path: root/pwmanager/libcrypt/crypt/sexp.c
Unidiff
Diffstat (limited to 'pwmanager/libcrypt/crypt/sexp.c') (more/less context) (show whitespace changes)
-rw-r--r--pwmanager/libcrypt/crypt/sexp.c1804
1 files changed, 1804 insertions, 0 deletions
diff --git a/pwmanager/libcrypt/crypt/sexp.c b/pwmanager/libcrypt/crypt/sexp.c
new file mode 100644
index 0000000..c19dc33
--- a/dev/null
+++ b/pwmanager/libcrypt/crypt/sexp.c
@@ -0,0 +1,1804 @@
1/* sexp.c - S-Expression handling
2 * Copyright (C) 1999, 2000, 2001, 2002, 2003,
3 * 2004 Free Software Foundation, Inc.
4 *
5 * This file is part of Libgcrypt.
6 *
7 * Libgcrypt is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser general Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * Libgcrypt is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20 */
21
22
23#include <config.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <stdarg.h>
28#include <ctype.h>
29#include <assert.h>
30
31#define GCRYPT_NO_MPI_MACROS 1
32#include "g10lib.h"
33#include "memory.h"
34
35typedef struct gcry_sexp *NODE;
36typedef unsigned short DATALEN;
37
38struct gcry_sexp
39{
40 byte d[1];
41};
42
43#define ST_STOP 0
44#define ST_DATA 1 /* datalen follows */
45#define ST_HINT 2 /* datalen follows */
46#define ST_OPEN 3
47#define ST_CLOSE 4
48
49/* the atoi macros assume that the buffer has only valid digits */
50#define atoi_1(p) (*(p) - '0' )
51#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
52 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
53#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
54
55#define TOKEN_SPECIALS "-./_:*+="
56
57static gcry_error_t
58sexp_sscan (gcry_sexp_t *retsexp, size_t *erroff,
59 const char *buffer, size_t length, int argflag,
60 va_list arg_ptr, void **arg_list);
61
62#if 0
63static void
64dump_mpi( gcry_mpi_t a )
65{
66 char buffer[1000];
67 size_t n = 1000;
68
69 if( !a )
70 fputs("[no MPI]", stderr );
71 else if( gcry_mpi_print( GCRYMPI_FMT_HEX, buffer, &n, a ) )
72 fputs("[MPI too large to print]", stderr );
73 else
74 fputs( buffer, stderr );
75}
76#endif
77
78static void
79dump_string (const byte *p, size_t n, int delim )
80{
81 for (; n; n--, p++ )
82 {
83 if ((*p & 0x80) || iscntrl( *p ) || *p == delim )
84 {
85 if( *p == '\n' )
86 log_printf ("\\n");
87 else if( *p == '\r' )
88 log_printf ("\\r");
89 else if( *p == '\f' )
90 log_printf ("\\f");
91 else if( *p == '\v' )
92 log_printf ("\\v");
93 else if( *p == '\b' )
94 log_printf ("\\b");
95 else if( !*p )
96 log_printf ("\\0");
97 else
98 log_printf ("\\x%02x", *p );
99 }
100 else
101 log_printf ("%c", *p);
102 }
103}
104
105
106void
107gcry_sexp_dump (const gcry_sexp_t a)
108{
109 const byte *p;
110 int indent = 0;
111 int type;
112
113 if (!a)
114 {
115 log_printf ( "[nil]\n");
116 return;
117 }
118
119 p = a->d;
120 while ( (type = *p) != ST_STOP )
121 {
122 p++;
123 switch ( type )
124 {
125 case ST_OPEN:
126 log_printf ("%*s[open]\n", 2*indent, "");
127 indent++;
128 break;
129 case ST_CLOSE:
130 if( indent )
131 indent--;
132 log_printf ("%*s[close]\n", 2*indent, "");
133 break;
134 case ST_DATA: {
135 DATALEN n;
136 memcpy ( &n, p, sizeof n );
137 p += sizeof n;
138 log_printf ("%*s[data=\"", 2*indent, "" );
139 dump_string (p, n, '\"' );
140 log_printf ("\"]\n");
141 p += n;
142 }
143 break;
144 default:
145 log_printf ("%*s[unknown tag %d]\n", 2*indent, "", type);
146 break;
147 }
148 }
149}
150
151/****************
152 * Pass list through except when it is an empty list - in that case
153 * return NULL and release the passed list.
154 */
155static gcry_sexp_t
156normalize ( gcry_sexp_t list )
157{
158 char *p;
159 if ( !list )
160 return NULL;
161 p = list->d;
162 if ( *p == ST_STOP ) {
163 /* this is "" */
164 gcry_sexp_release ( list );
165 return NULL;
166 }
167 if( *p == ST_OPEN && p[1] == ST_CLOSE ) {
168 /* this is "()" */
169 gcry_sexp_release ( list );
170 return NULL;
171 }
172
173 return list;
174}
175
176/* Create a new S-expression object by reading LENGTH bytes from
177 BUFFER, assuming it is canonilized encoded or autodetected encoding
178 when AUTODETECT is set to 1. With FREEFNC not NULL, ownership of
179 the buffer is transferred to tyhe newle created object. FREEFNC
180 should be the freefnc used to release BUFFER; there is no guarantee
181 at which point this function is called; most likey you want to use
182 free() or gcry_free().
183
184 Passing LENGTH and AUTODETECT as 0 is allowed to indicate that
185 BUFFER points to a valid canonical encoded S-expression. A LENGTH
186 of 0 and AUTODETECT 1 indicates that buffer points to a
187 null-terminated string.
188
189 This function returns 0 and and the pointer to the new object in
190 RETSEXP or an error code in which case RETSEXP is set to NULL. */
191gcry_error_t
192gcry_sexp_create (gcry_sexp_t *retsexp, void *buffer, size_t length,
193 int autodetect, void (*freefnc)(void*) )
194{
195 gcry_error_t errcode;
196 gcry_sexp_t se;
197 volatile va_list dummy_arg_ptr;
198
199 if (!retsexp)
200 return gcry_error (GPG_ERR_INV_ARG);
201 *retsexp = NULL;
202 if (autodetect < 0 || autodetect > 1 || !buffer)
203 return gcry_error (GPG_ERR_INV_ARG);
204
205 if (!length && !autodetect)
206 { /* What a brave caller to assume that there is really a canonical
207 encoded S-expression in buffer */
208 length = gcry_sexp_canon_len (buffer, 0, NULL, &errcode);
209 if (!length)
210 return errcode;
211 }
212 else if (!length && autodetect)
213 { /* buffer is a string */
214 length = strlen ((char *)buffer);
215 }
216
217 errcode = sexp_sscan (&se, NULL, buffer, length, 0, dummy_arg_ptr, NULL);
218 if (errcode)
219 return errcode;
220
221 *retsexp = se;
222 if (freefnc)
223 {
224 /* For now we release the buffer immediately. As soon as we
225 have changed the internal represenation of S-expression to
226 the canoncial format - which has the advantage of faster
227 parsing - we will use this function as a closure in our
228 GCRYSEXP object and use the BUFFER directly */
229 freefnc (buffer);
230 }
231 return gcry_error (GPG_ERR_NO_ERROR);
232}
233
234/* Same as gcry_sexp_create but don't transfer ownership */
235gcry_error_t
236gcry_sexp_new (gcry_sexp_t *retsexp, const void *buffer, size_t length,
237 int autodetect)
238{
239 return gcry_sexp_create (retsexp, (void *)buffer, length, autodetect, NULL);
240}
241
242
243/****************
244 * Release resource of the given SEXP object.
245 */
246void
247gcry_sexp_release( gcry_sexp_t sexp )
248{
249 if (sexp)
250 {
251 if (gcry_is_secure (sexp))
252 {
253 /* Extra paranoid wiping. */
254 const byte *p = sexp->d;
255 int type;
256
257 while ( (type = *p) != ST_STOP )
258 {
259 p++;
260 switch ( type )
261 {
262 case ST_OPEN:
263 break;
264 case ST_CLOSE:
265 break;
266 case ST_DATA:
267 {
268 DATALEN n;
269 memcpy ( &n, p, sizeof n );
270 p += sizeof n;
271 p += n;
272 }
273 break;
274 default:
275 break;
276 }
277 }
278 wipememory (sexp->d, p - sexp->d);
279 }
280 gcry_free ( sexp );
281 }
282}
283
284
285/****************
286 * Make a pair from lists a and b, don't use a or b later on.
287 * Special behaviour: If one is a single element list we put the
288 * element straight into the new pair.
289 */
290gcry_sexp_t
291gcry_sexp_cons( const gcry_sexp_t a, const gcry_sexp_t b )
292{
293 /* NYI: Implementation should be quite easy with our new data
294 representation */
295 BUG ();
296 return NULL;
297}
298
299
300/****************
301 * Make a list from all items in the array the end of the array is marked
302 * with a NULL.
303 */
304gcry_sexp_t
305gcry_sexp_alist( const gcry_sexp_t *array )
306{
307 /* NYI: Implementation should be quite easy with our new data
308 representation. */
309 BUG ();
310 return NULL;
311}
312
313/****************
314 * Make a list from all items, the end of list is indicated by a NULL
315 */
316gcry_sexp_t
317gcry_sexp_vlist( const gcry_sexp_t a, ... )
318{
319 /* NYI: Implementation should be quite easy with our new data
320 representation. */
321 BUG ();
322 return NULL;
323}
324
325
326/****************
327 * Append n to the list a
328 * Returns: a new ist (which maybe a)
329 */
330gcry_sexp_t
331gcry_sexp_append( const gcry_sexp_t a, const gcry_sexp_t n )
332{
333 /* NYI: Implementation should be quite easy with our new data
334 representation. */
335 BUG ();
336 return NULL;
337}
338
339gcry_sexp_t
340gcry_sexp_prepend( const gcry_sexp_t a, const gcry_sexp_t n )
341{
342 /* NYI: Implementation should be quite easy with our new data
343 representation. */
344 BUG ();
345 return NULL;
346}
347
348
349
350/****************
351 * Locate token in a list. The token must be the car of a sublist.
352 * Returns: A new list with this sublist or NULL if not found.
353 */
354gcry_sexp_t
355gcry_sexp_find_token( const gcry_sexp_t list, const char *tok, size_t toklen )
356{
357 const byte *p;
358 DATALEN n;
359
360 if ( !list )
361 return NULL;
362
363 if( !toklen )
364 toklen = strlen(tok);
365 p = list->d;
366 while ( *p != ST_STOP ) {
367 if ( *p == ST_OPEN && p[1] == ST_DATA ) {
368 const byte *head = p;
369
370 p += 2;
371 memcpy ( &n, p, sizeof n ); p += sizeof n;
372 if ( n == toklen && !memcmp( p, tok, toklen ) ) { /* found it */
373 gcry_sexp_t newlist;
374 byte *d;
375 int level = 1;
376
377 /* look for the end of the list */
378 for ( p += n; level; p++ ) {
379 if ( *p == ST_DATA ) {
380 memcpy ( &n, ++p, sizeof n );
381 p += sizeof n + n;
382 p--; /* compensate for later increment */
383 }
384 else if ( *p == ST_OPEN ) {
385 level++;
386 }
387 else if ( *p == ST_CLOSE ) {
388 level--;
389 }
390 else if ( *p == ST_STOP ) {
391 BUG ();
392 }
393 } while ( level );
394 n = p - head;
395
396 newlist = gcry_xmalloc ( sizeof *newlist + n );
397 d = newlist->d;
398 memcpy ( d, head, n ); d += n;
399 *d++ = ST_STOP;
400 return normalize ( newlist );
401 }
402 p += n;
403 }
404 else if ( *p == ST_DATA ) {
405 memcpy ( &n, ++p, sizeof n ); p += sizeof n;
406 p += n;
407 }
408 else
409 p++;
410 }
411 return NULL;
412}
413
414/****************
415 * Return the length of the given list
416 */
417int
418gcry_sexp_length( const gcry_sexp_t list )
419{
420 const byte *p;
421 DATALEN n;
422 int type;
423 int length = 0;
424 int level = 0;
425
426 if ( !list )
427 return 0;
428
429 p = list->d;
430 while ( (type=*p) != ST_STOP ) {
431 p++;
432 if ( type == ST_DATA ) {
433 memcpy ( &n, p, sizeof n );
434 p += sizeof n + n;
435 if ( level == 1 )
436 length++;
437 }
438 else if ( type == ST_OPEN ) {
439 if ( level == 1 )
440 length++;
441 level++;
442 }
443 else if ( type == ST_CLOSE ) {
444 level--;
445 }
446 }
447 return length;
448}
449
450
451
452/****************
453 * Extract the CAR of the given list
454 */
455gcry_sexp_t
456gcry_sexp_nth( const gcry_sexp_t list, int number )
457{
458 const byte *p;
459 DATALEN n;
460 gcry_sexp_t newlist;
461 byte *d;
462 int level = 0;
463
464 if ( !list || list->d[0] != ST_OPEN )
465 return NULL;
466 p = list->d;
467
468 while ( number > 0 ) {
469 p++;
470 if ( *p == ST_DATA ) {
471 memcpy ( &n, ++p, sizeof n );
472 p += sizeof n + n;
473 p--;
474 if ( !level )
475 number--;
476 }
477 else if ( *p == ST_OPEN ) {
478 level++;
479 }
480 else if ( *p == ST_CLOSE ) {
481 level--;
482 if ( !level )
483 number--;
484 }
485 else if ( *p == ST_STOP ) {
486 return NULL;
487 }
488 }
489 p++;
490
491 if ( *p == ST_DATA ) {
492 memcpy ( &n, p, sizeof n ); p += sizeof n;
493 newlist = gcry_xmalloc ( sizeof *newlist + n + 1 );
494 d = newlist->d;
495 memcpy ( d, p, n ); d += n;
496 *d++ = ST_STOP;
497 }
498 else if ( *p == ST_OPEN ) {
499 const byte *head = p;
500
501 level = 1;
502 do {
503 p++;
504 if ( *p == ST_DATA ) {
505 memcpy ( &n, ++p, sizeof n );
506 p += sizeof n + n;
507 p--;
508 }
509 else if ( *p == ST_OPEN ) {
510 level++;
511 }
512 else if ( *p == ST_CLOSE ) {
513 level--;
514 }
515 else if ( *p == ST_STOP ) {
516 BUG ();
517 }
518 } while ( level );
519 n = p + 1 - head;
520
521 newlist = gcry_xmalloc ( sizeof *newlist + n );
522 d = newlist->d;
523 memcpy ( d, head, n ); d += n;
524 *d++ = ST_STOP;
525 }
526 else
527 newlist = NULL;
528
529 return normalize (newlist);
530}
531
532gcry_sexp_t
533gcry_sexp_car( const gcry_sexp_t list )
534{
535 return gcry_sexp_nth ( list, 0 );
536}
537
538/****************
539 * Get data from the car. The returned value is valid as long as the list
540 * is not modified.
541 */
542const char *
543gcry_sexp_nth_data( const gcry_sexp_t list, int number, size_t *datalen )
544{
545 const byte *p;
546 DATALEN n;
547 int level = 0;
548
549 *datalen = 0;
550 if ( !list ) {
551 return NULL;
552 }
553 p = list->d;
554 if ( *p == ST_OPEN )
555 p++; /* yep, a list */
556 else if (number )
557 return NULL; /* not a list but an n > 0 element requested */
558
559 /* skip n elements */
560 while ( number > 0 ) {
561 if ( *p == ST_DATA ) {
562 memcpy ( &n, ++p, sizeof n );
563 p += sizeof n + n;
564 p--;
565 if ( !level )
566 number--;
567 }
568 else if ( *p == ST_OPEN ) {
569 level++;
570 }
571 else if ( *p == ST_CLOSE ) {
572 level--;
573 if ( !level )
574 number--;
575 }
576 else if ( *p == ST_STOP ) {
577 return NULL;
578 }
579 p++;
580 }
581
582
583 if ( *p == ST_DATA ) {
584 memcpy ( &n, ++p, sizeof n );
585 *datalen = n;
586 return p + sizeof n;
587 }
588
589 return NULL;
590}
591
592/****************
593 * Get a MPI from the car
594 */
595gcry_mpi_t
596gcry_sexp_nth_mpi( gcry_sexp_t list, int number, int mpifmt )
597{
598 const byte *p;
599 DATALEN n;
600 int level = 0;
601
602 if ( !list )
603 return NULL;
604 if ( !mpifmt )
605 mpifmt = GCRYMPI_FMT_STD;
606
607 p = list->d;
608 if ( *p == ST_OPEN )
609 p++; /* yep, a list */
610 else if (number )
611 return NULL; /* not a list but an n > 0 element requested */
612
613 /* skip n elements */
614 while ( number > 0 ) {
615 if ( *p == ST_DATA ) {
616 memcpy ( &n, ++p, sizeof n );
617 p += sizeof n + n;
618 p--;
619 if ( !level )
620 number--;
621 }
622 else if ( *p == ST_OPEN ) {
623 level++;
624 }
625 else if ( *p == ST_CLOSE ) {
626 level--;
627 if ( !level )
628 number--;
629 }
630 else if ( *p == ST_STOP ) {
631 return NULL;
632 }
633 p++;
634 }
635
636 if ( *p == ST_DATA ) {
637 gcry_mpi_t a;
638 size_t nbytes;
639
640 memcpy ( &n, ++p, sizeof n );
641 p += sizeof n;
642 nbytes = n;
643 if( !gcry_mpi_scan( &a, mpifmt, p, n, &nbytes ) )
644 return a;
645 }
646
647 return NULL;
648}
649
650
651/****************
652 * Get the CDR
653 */
654gcry_sexp_t
655gcry_sexp_cdr( const gcry_sexp_t list )
656{
657 const byte *p;
658 const byte *head;
659 DATALEN n;
660 gcry_sexp_t newlist;
661 byte *d;
662 int level = 0;
663 int skip = 1;
664
665 if ( !list || list->d[0] != ST_OPEN )
666 return NULL;
667 p = list->d;
668
669 while ( skip > 0 ) {
670 p++;
671 if ( *p == ST_DATA ) {
672 memcpy ( &n, ++p, sizeof n );
673 p += sizeof n + n;
674 p--;
675 if ( !level )
676 skip--;
677 }
678 else if ( *p == ST_OPEN ) {
679 level++;
680 }
681 else if ( *p == ST_CLOSE ) {
682 level--;
683 if ( !level )
684 skip--;
685 }
686 else if ( *p == ST_STOP ) {
687 return NULL;
688 }
689 }
690 p++;
691
692 head = p;
693 level = 0;
694 do {
695 if ( *p == ST_DATA ) {
696 memcpy ( &n, ++p, sizeof n );
697 p += sizeof n + n;
698 p--;
699 }
700 else if ( *p == ST_OPEN ) {
701 level++;
702 }
703 else if ( *p == ST_CLOSE ) {
704 level--;
705 }
706 else if ( *p == ST_STOP ) {
707 return NULL;
708 }
709 p++;
710 } while ( level );
711 n = p - head;
712
713 newlist = gcry_xmalloc ( sizeof *newlist + n + 2 );
714 d = newlist->d;
715 *d++ = ST_OPEN;
716 memcpy ( d, head, n ); d += n;
717 *d++ = ST_CLOSE;
718 *d++ = ST_STOP;
719
720 return normalize (newlist);
721}
722
723gcry_sexp_t
724gcry_sexp_cadr ( const gcry_sexp_t list )
725{
726 gcry_sexp_t a, b;
727
728 a = gcry_sexp_cdr ( list );
729 b = gcry_sexp_car ( a );
730 gcry_sexp_release ( a );
731 return b;
732}
733
734
735
736static int
737hextobyte( const byte *s )
738{
739 int c=0;
740
741 if( *s >= '0' && *s <= '9' )
742 c = 16 * (*s - '0');
743 else if( *s >= 'A' && *s <= 'F' )
744 c = 16 * (10 + *s - 'A');
745 else if( *s >= 'a' && *s <= 'f' ) {
746 c = 16 * (10 + *s - 'a');
747 }
748 s++;
749 if( *s >= '0' && *s <= '9' )
750 c += *s - '0';
751 else if( *s >= 'A' && *s <= 'F' )
752 c += 10 + *s - 'A';
753 else if( *s >= 'a' && *s <= 'f' ) {
754 c += 10 + *s - 'a';
755 }
756 return c;
757}
758
759struct make_space_ctx {
760 gcry_sexp_t sexp;
761 size_t allocated;
762 byte *pos;
763};
764
765static void
766make_space ( struct make_space_ctx *c, size_t n )
767{
768 size_t used = c->pos - c->sexp->d;
769
770 if ( used + n + sizeof(DATALEN) + 1 >= c->allocated ) {
771 gcry_sexp_t newsexp;
772 byte *newhead;
773
774 c->allocated += 2*(n+sizeof(DATALEN)+1);
775 newsexp = gcry_xrealloc ( c->sexp, sizeof *newsexp + c->allocated - 1 );
776 newhead = newsexp->d;
777 c->pos = newhead + used;
778 c->sexp = newsexp;
779 }
780}
781
782
783/* Unquote STRING of LENGTH and store it into BUF. The surrounding
784 quotes are must already be removed from STRING. We assume that the
785 quoted string is syntacillay correct. */
786static size_t
787unquote_string (const unsigned char *string, size_t length, unsigned char *buf)
788{
789 int esc = 0;
790 const unsigned char *s = string;
791 unsigned char *d = buf;
792 size_t n = length;
793
794 for (; n; n--, s++)
795 {
796 if (esc)
797 {
798 switch (*s)
799 {
800 case 'b': *d++ = '\b'; break;
801 case 't': *d++ = '\t'; break;
802 case 'v': *d++ = '\v'; break;
803 case 'n': *d++ = '\n'; break;
804 case 'f': *d++ = '\f'; break;
805 case 'r': *d++ = '\r'; break;
806 case '"': *d++ = '\"'; break;
807 case '\'': *d++ = '\''; break;
808 case '\\': *d++ = '\\'; break;
809
810 case '\r': /* ignore CR[,LF] */
811 if (n>1 && s[1] == '\n')
812 {
813 s++; n--;
814 }
815 esc = 0;
816 break;
817
818 case '\n': /* ignore LF[,CR] */
819 if (n>1 && s[1] == '\r')
820 {
821 s++; n--;
822 }
823 break;
824
825 case 'x': /* hex value */
826 if (n>2 && hexdigitp (s+1) && hexdigitp (s+2))
827 {
828 s++; n--;
829 *d++ = xtoi_2 (s);
830 s++; n--;
831 }
832 break;
833
834 default:
835 if (n>2 && octdigitp (s) && octdigitp (s+1) && octdigitp (s+2))
836 {
837 *d++ = (atoi_1 (s)*64) + (atoi_1 (s+1)*8) + atoi_1 (s+2);
838 s += 2;
839 n -= 2;
840 }
841 break;
842 }
843 esc = 0;
844 }
845 else if( *s == '\\' )
846 esc = 1;
847 else
848 *d++ = *s;
849 }
850
851 return d - buf;
852}
853
854/****************
855 * Scan the provided buffer and return the S expression in our internal
856 * format. Returns a newly allocated expression. If erroff is not NULL and
857 * a parsing error has occured, the offset into buffer will be returned.
858 * If ARGFLAG is true, the function supports some printf like
859 * expressions.
860 * These are:
861 *%m - MPI
862 *%s - string (no autoswitch to secure allocation)
863 *%d - integer stored as string (no autoswitch to secure allocation)
864 * %b - memory buffer; this takes _two_ arguments: an integer with the
865 * length of the buffer and a pointer to the buffer.
866 * all other format elements are currently not defined and return an error.
867 * this includes the "%%" sequence becauce the percent sign is not an
868 * allowed character.
869 * FIXME: We should find a way to store the secure-MPIs not in the string
870 * but as reference to somewhere - this can help us to save huge amounts
871 * of secure memory. The problem is, that if only one element is secure, all
872 * other elements are automagicaly copied to secure memory too, so the most
873 * common operation gcry_sexp_cdr_mpi() will always return a secure MPI
874 * regardless whether it is needed or not.
875 */
876static gcry_error_t
877sexp_sscan (gcry_sexp_t *retsexp, size_t *erroff,
878 const char *buffer, size_t length, int argflag,
879 va_list arg_ptr, void **arg_list)
880{
881 gcry_err_code_t err = GPG_ERR_NO_ERROR;
882 static const char tokenchars[] =
883 "abcdefghijklmnopqrstuvwxyz"
884 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
885 "0123456789-./_:*+=";
886 const char *p;
887 size_t n;
888 const char *digptr = NULL;
889 const char *quoted = NULL;
890 const char *tokenp = NULL;
891 const char *hexfmt = NULL;
892 const char *base64 = NULL;
893 const char *disphint = NULL;
894 const char *percent = NULL;
895 int hexcount = 0;
896 int quoted_esc = 0;
897 int datalen = 0;
898 size_t dummy_erroff;
899 struct make_space_ctx c;
900 int arg_counter = 0;
901 int level = 0;
902
903 /* FIXME: invent better error codes (?). */
904
905 if (! erroff)
906 erroff = &dummy_erroff;
907
908 /* Depending on wether ARG_LIST is non-zero or not, this macro gives
909 us the next argument, either from the variable argument list as
910 specified by ARG_PTR or from the argument array ARG_LIST. */
911#define ARG_NEXT(storage, type) \
912 do \
913 { \
914 if (! arg_list) \
915 storage = va_arg (arg_ptr, type); \
916 else \
917 storage = *((type *) (arg_list[arg_counter++])); \
918 } \
919 while (0)
920
921#define MAKE_SPACE(n) do { make_space ( &c, (n) ); } while (0)
922 #define STORE_LEN(p,n) do { \
923 DATALEN ashort = (n); \
924 memcpy ( (p), &ashort, sizeof(ashort) ); \
925 (p) += sizeof (ashort); \
926 } while (0)
927
928 /* We assume that the internal representation takes less memory
929 * than the provided one. However, we add space for one extra datalen
930 * so that the code which does the ST_CLOSE can use MAKE_SPACE */
931 c.allocated = length + sizeof(DATALEN);
932 if (buffer && length && gcry_is_secure (buffer))
933 c.sexp = gcry_xmalloc_secure (sizeof *c.sexp + c.allocated - 1);
934 else
935 c.sexp = gcry_xmalloc (sizeof *c.sexp + c.allocated - 1);
936 c.pos = c.sexp->d;
937
938 for (p = buffer, n = length; n; p++, n--)
939 {
940 if (tokenp && (! hexfmt))
941 {
942 if (strchr (tokenchars, *p))
943 continue;
944 else
945 {
946 datalen = p - tokenp;
947 MAKE_SPACE (datalen);
948 *c.pos++ = ST_DATA;
949 STORE_LEN (c.pos, datalen);
950 memcpy (c.pos, tokenp, datalen);
951 c.pos += datalen;
952 tokenp = NULL;
953 }
954 }
955
956 if (quoted)
957 {
958 if (quoted_esc)
959 {
960 switch (*p)
961 {
962 case 'b': case 't': case 'v': case 'n': case 'f':
963 case 'r': case '"': case '\'': case '\\':
964 quoted_esc = 0;
965 break;
966
967 case '0': case '1': case '2': case '3': case '4':
968 case '5': case '6': case '7':
969 if (! ((n > 2)
970 && (p[1] >= '0') && (p[1] <= '7')
971 && (p[2] >= '0') && (p[2] <= '7')))
972 {
973 *erroff = p - buffer;
974 /* Invalid octal value. */
975 err = GPG_ERR_SEXP_BAD_QUOTATION;
976 //return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION);
977 }
978 p += 2;
979 n -= 2;
980 quoted_esc = 0;
981 break;
982
983 case 'x':
984 if (! ((n > 2) && isxdigit(p[1]) && isxdigit(p[2])))
985 {
986 *erroff = p - buffer;
987 /* Invalid hex value. */
988 err = GPG_ERR_SEXP_BAD_QUOTATION;
989 //return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION);
990 }
991 p += 2;
992 n -= 2;
993 quoted_esc = 0;
994 break;
995
996 case '\r':
997 /* ignore CR[,LF] */
998 if (n && (p[1] == '\n'))
999 {
1000 p++;
1001 n--;
1002 }
1003 quoted_esc = 0;
1004 break;
1005
1006 case '\n':
1007 /* ignore LF[,CR] */
1008 if (n && (p[1] == '\r'))
1009 {
1010 p++;
1011 n--;
1012 }
1013 quoted_esc = 0;
1014 break;
1015
1016 default:
1017 *erroff = p - buffer;
1018 /* Invalid quoted string escape. */
1019 err = GPG_ERR_SEXP_BAD_QUOTATION;
1020 }
1021 }
1022 else if (*p == '\\')
1023 quoted_esc = 1;
1024 else if (*p == '\"')
1025 {
1026 /* Keep it easy - we know that the unquoted string will
1027 never be larger. */
1028 char *save;
1029 size_t len;
1030
1031 quoted++; /* Skip leading quote. */
1032 MAKE_SPACE (p - quoted);
1033 *c.pos++ = ST_DATA;
1034 save = c.pos;
1035 STORE_LEN (c.pos, 0); /* Will be fixed up later. */
1036 len = unquote_string (quoted, p - quoted, c.pos);
1037 c.pos += len;
1038 STORE_LEN (save, len);
1039 quoted = NULL;
1040 }
1041 }
1042 else if (hexfmt)
1043 {
1044 if (isxdigit (*p))
1045 hexcount++;
1046 else if (*p == '#')
1047 {
1048 if ((hexcount & 1))
1049 {
1050 *erroff = p - buffer;
1051 err = GPG_ERR_SEXP_ODD_HEX_NUMBERS;
1052 }
1053
1054 datalen = hexcount / 2;
1055 MAKE_SPACE (datalen);
1056 *c.pos++ = ST_DATA;
1057 STORE_LEN (c.pos, datalen);
1058 for (hexfmt++; hexfmt < p; hexfmt++)
1059 {
1060 if (isspace (*hexfmt))
1061 continue;
1062 *c.pos++ = hextobyte (hexfmt);
1063 hexfmt++;
1064 }
1065 hexfmt = NULL;
1066 }
1067 else if (! isspace (*p))
1068 {
1069 *erroff = p - buffer;
1070 err = GPG_ERR_SEXP_BAD_HEX_CHAR;
1071 }
1072 }
1073 else if (base64)
1074 {
1075 if (*p == '|')
1076 base64 = NULL;
1077 }
1078 else if (digptr)
1079 {
1080 if (isdigit (*p))
1081 ;
1082 else if (*p == ':')
1083 {
1084 datalen = atoi (digptr); /* FIXME: check for overflow. */
1085 digptr = NULL;
1086 if (datalen > n - 1)
1087 {
1088 *erroff = p - buffer;
1089 /* Buffer too short. */
1090 err = GPG_ERR_SEXP_STRING_TOO_LONG;
1091 }
1092 /* Make a new list entry. */
1093 MAKE_SPACE (datalen);
1094 *c.pos++ = ST_DATA;
1095 STORE_LEN (c.pos, datalen);
1096 memcpy (c.pos, p + 1, datalen);
1097 c.pos += datalen;
1098 n -= datalen;
1099 p += datalen;
1100 }
1101 else if (*p == '\"')
1102 {
1103 digptr = NULL; /* We ignore the optional length. */
1104 quoted = p;
1105 quoted_esc = 0;
1106 }
1107 else if (*p == '#')
1108 {
1109 digptr = NULL; /* We ignore the optional length. */
1110 hexfmt = p;
1111 hexcount = 0;
1112 }
1113 else if (*p == '|')
1114 {
1115 digptr = NULL; /* We ignore the optional length. */
1116 base64 = p;
1117 }
1118 else
1119 {
1120 *erroff = p - buffer;
1121 err = GPG_ERR_SEXP_INV_LEN_SPEC;
1122 }
1123 }
1124 else if (percent)
1125 {
1126 if (*p == 'm')
1127 {
1128 /* Insert an MPI. */
1129 gcry_mpi_t m;
1130 size_t nm = 0;
1131
1132 ARG_NEXT (m, gcry_mpi_t);
1133
1134 if (gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &nm, m))
1135 BUG ();
1136
1137 MAKE_SPACE (nm);
1138 if ((! gcry_is_secure (c.sexp->d))
1139 && gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE))
1140 {
1141 /* We have to switch to secure allocation. */
1142 gcry_sexp_t newsexp;
1143 byte *newhead;
1144
1145 newsexp = gcry_xmalloc_secure (sizeof *newsexp
1146 + c.allocated - 1);
1147 newhead = newsexp->d;
1148 memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d));
1149 c.pos = newhead + (c.pos - c.sexp->d);
1150 gcry_free (c.sexp);
1151 c.sexp = newsexp;
1152 }
1153
1154 *c.pos++ = ST_DATA;
1155 STORE_LEN (c.pos, nm);
1156 if (gcry_mpi_print (GCRYMPI_FMT_STD, c.pos, nm, &nm, m))
1157 BUG ();
1158 c.pos += nm;
1159 }
1160 else if (*p == 's')
1161 {
1162 /* Insert an string. */
1163 const char *astr;
1164 size_t alen;
1165
1166 ARG_NEXT (astr, const char *);
1167 alen = strlen (astr);
1168
1169 MAKE_SPACE (alen);
1170 *c.pos++ = ST_DATA;
1171 STORE_LEN (c.pos, alen);
1172 memcpy (c.pos, astr, alen);
1173 c.pos += alen;
1174 }
1175 else if (*p == 'b')
1176 {
1177 /* Insert a memory buffer. */
1178 const char *astr;
1179 int alen;
1180
1181 ARG_NEXT (alen, int);
1182 ARG_NEXT (astr, const char *);
1183
1184 MAKE_SPACE (alen);
1185 if (alen
1186 && !gcry_is_secure (c.sexp->d)
1187 && gcry_is_secure (astr))
1188 {
1189 /* We have to switch to secure allocation. */
1190 gcry_sexp_t newsexp;
1191 byte *newhead;
1192
1193 newsexp = gcry_xmalloc_secure (sizeof *newsexp
1194 + c.allocated - 1);
1195 newhead = newsexp->d;
1196 memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d));
1197 c.pos = newhead + (c.pos - c.sexp->d);
1198 gcry_free (c.sexp);
1199 c.sexp = newsexp;
1200 }
1201
1202 *c.pos++ = ST_DATA;
1203 STORE_LEN (c.pos, alen);
1204 memcpy (c.pos, astr, alen);
1205 c.pos += alen;
1206 }
1207 else if (*p == 'd')
1208 {
1209 /* Insert an integer as string. */
1210 int aint;
1211 size_t alen;
1212 char buf[20];
1213
1214 ARG_NEXT (aint, int);
1215 sprintf (buf, "%d", aint);
1216 alen = strlen (buf);
1217 MAKE_SPACE (alen);
1218 *c.pos++ = ST_DATA;
1219 STORE_LEN (c.pos, alen);
1220 memcpy (c.pos, buf, alen);
1221 c.pos += alen;
1222 }
1223 else
1224 {
1225 *erroff = p - buffer;
1226 /* Invalid format specifier. */
1227 err = GPG_ERR_SEXP_INV_LEN_SPEC;
1228 }
1229 percent = NULL;
1230 }
1231 else if (*p == '(')
1232 {
1233 if (disphint)
1234 {
1235 *erroff = p - buffer;
1236 /* Open display hint. */
1237 err = GPG_ERR_SEXP_UNMATCHED_DH;
1238 }
1239 MAKE_SPACE (0);
1240 *c.pos++ = ST_OPEN;
1241 level++;
1242 }
1243 else if (*p == ')')
1244 {
1245 /* Walk up. */
1246 if (disphint)
1247 {
1248 *erroff = p - buffer;
1249 /* Open display hint. */
1250 err = GPG_ERR_SEXP_UNMATCHED_DH;
1251 }
1252 MAKE_SPACE (0);
1253 *c.pos++ = ST_CLOSE;
1254 level--;
1255 }
1256 else if (*p == '\"')
1257 {
1258 quoted = p;
1259 quoted_esc = 0;
1260 }
1261 else if (*p == '#')
1262 {
1263 hexfmt = p;
1264 hexcount = 0;
1265 }
1266 else if (*p == '|')
1267 base64 = p;
1268 else if (*p == '[')
1269 {
1270 if (disphint)
1271 {
1272 *erroff = p - buffer;
1273 /* Open display hint. */
1274 err = GPG_ERR_SEXP_NESTED_DH;
1275 }
1276 disphint = p;
1277 }
1278 else if (*p == ']')
1279 {
1280 if (! disphint)
1281 {
1282 *erroff = p - buffer;
1283 /* Open display hint. */
1284 err = GPG_ERR_SEXP_UNMATCHED_DH;
1285 }
1286 disphint = NULL;
1287 }
1288 else if (isdigit (*p))
1289 {
1290 if (*p == '0')
1291 {
1292 /* A length may not begin with zero. */
1293 *erroff = p - buffer;
1294 err = GPG_ERR_SEXP_ZERO_PREFIX;
1295 }
1296 digptr = p;
1297 }
1298 else if (strchr (tokenchars, *p))
1299 tokenp = p;
1300 else if (isspace (*p))
1301 ;
1302 else if (*p == '{')
1303 {
1304 /* fixme: handle rescanning: we can do this by saving our
1305 current state and start over at p+1 -- Hmmm. At this
1306 point here we are in a well defined state, so we don't
1307 need to save it. Great. */
1308 *erroff = p - buffer;
1309 err = GPG_ERR_SEXP_UNEXPECTED_PUNC;
1310 }
1311 else if (strchr ("&\\", *p))
1312 {
1313 /* Reserved punctuation. */
1314 *erroff = p - buffer;
1315 err = GPG_ERR_SEXP_UNEXPECTED_PUNC;
1316 }
1317 else if (argflag && (*p == '%'))
1318 percent = p;
1319 else
1320 {
1321 /* Bad or unavailable. */
1322 *erroff = p - buffer;
1323 err = GPG_ERR_SEXP_BAD_CHARACTER;
1324 }
1325 }
1326 MAKE_SPACE (0);
1327 *c.pos++ = ST_STOP;
1328
1329 if (level)
1330 err = GPG_ERR_SEXP_UNMATCHED_PAREN;
1331
1332 if (err)
1333 {
1334 /* Error -> deallocate. */
1335 if (c.sexp)
1336 {
1337 /* Extra paranoid wipe on error. */
1338 if (gcry_is_secure (c.sexp))
1339 wipememory (c.sexp, sizeof (struct gcry_sexp) + c.allocated - 1);
1340 gcry_free (c.sexp);
1341 }
1342 /* This might be expected by existing code... */
1343 *retsexp = NULL;
1344 }
1345 else
1346 *retsexp = normalize (c.sexp);
1347
1348 return gcry_error (err);
1349#undef MAKE_SPACE
1350#undef STORE_LEN
1351}
1352
1353gcry_error_t
1354gcry_sexp_build (gcry_sexp_t *retsexp, size_t *erroff, const char *format, ...)
1355{
1356 gcry_error_t rc;
1357 va_list arg_ptr;
1358
1359 va_start (arg_ptr, format);
1360 rc = sexp_sscan (retsexp, erroff, format, strlen(format), 1,
1361 arg_ptr, NULL);
1362 va_end (arg_ptr);
1363
1364 return rc;
1365}
1366
1367/* Like gcry_sexp_build, but uses an array instead of variable
1368 function arguments. */
1369gcry_error_t
1370gcry_sexp_build_array (gcry_sexp_t *retsexp, size_t *erroff,
1371 const char *format, void **arg_list)
1372{
1373 /* We don't need the va_list because it is controlled by the
1374 following flag, however we have to pass it but can't initialize
1375 it as there is no portable way to do so. volatile is needed to
1376 suppress the compiler warning */
1377 volatile va_list dummy_arg_ptr;
1378
1379 gcry_error_t rc;
1380
1381 rc = sexp_sscan (retsexp, erroff, format, strlen(format), 1,
1382 dummy_arg_ptr, arg_list);
1383
1384 return rc;
1385}
1386
1387gcry_error_t
1388gcry_sexp_sscan (gcry_sexp_t *retsexp, size_t *erroff,
1389 const char *buffer, size_t length)
1390{
1391 /* We don't need the va_list because it is controlled by the
1392 following flag, however we have to pass it but can't initialize
1393 it as there is no portable way to do so. volatile is needed to
1394 suppress the compiler warning */
1395 volatile va_list dummy_arg_ptr;
1396
1397 return sexp_sscan (retsexp, erroff, buffer, length, 0,
1398 dummy_arg_ptr, NULL);
1399}
1400
1401
1402/* Figure out a suitable encoding for BUFFER of LENGTH.
1403 Returns: 0 = Binary
1404 1 = String possible
1405 2 = Token possible
1406*/
1407static int
1408suitable_encoding (const unsigned char *buffer, size_t length)
1409{
1410 const unsigned char *s;
1411 int maybe_token = 1;
1412
1413 if (!length)
1414 return 1;
1415
1416 for (s=buffer; length; s++, length--)
1417 {
1418 if ( (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0))
1419 && !strchr ("\b\t\v\n\f\r\"\'\\", *s))
1420 return 0; /*binary*/
1421 if ( maybe_token
1422 && !alphap (s) && !digitp (s) && !strchr (TOKEN_SPECIALS, *s))
1423 maybe_token = 0;
1424 }
1425 s = buffer;
1426 if ( maybe_token && !digitp (s) )
1427 return 2;
1428 return 1;
1429}
1430
1431
1432static int
1433convert_to_hex (const unsigned char *src, size_t len, unsigned char *dest)
1434{
1435 int i;
1436
1437 if (dest)
1438 {
1439 *dest++ = '#';
1440 for (i=0; i < len; i++, dest += 2 )
1441 sprintf (dest, "%02X", src[i]);
1442 *dest++ = '#';
1443 }
1444 return len*2+2;
1445}
1446
1447static int
1448convert_to_string (const unsigned char *s, size_t len, unsigned char *dest)
1449{
1450 if (dest)
1451 {
1452 unsigned char *p = dest;
1453 *p++ = '\"';
1454 for (; len; len--, s++ )
1455 {
1456 switch (*s)
1457 {
1458 case '\b': *p++ = '\\'; *p++ = 'b'; break;
1459 case '\t': *p++ = '\\'; *p++ = 't'; break;
1460 case '\v': *p++ = '\\'; *p++ = 'v'; break;
1461 case '\n': *p++ = '\\'; *p++ = 'n'; break;
1462 case '\f': *p++ = '\\'; *p++ = 'f'; break;
1463 case '\r': *p++ = '\\'; *p++ = 'r'; break;
1464 case '\"': *p++ = '\\'; *p++ = '\"'; break;
1465 case '\'': *p++ = '\\'; *p++ = '\''; break;
1466 case '\\': *p++ = '\\'; *p++ = '\\'; break;
1467 default:
1468 if ( (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0)))
1469 {
1470 sprintf (p, "\\x%02x", *s);
1471 p += 4;
1472 }
1473 else
1474 *p++ = *s;
1475 }
1476 }
1477 *p++ = '\"';
1478 return p - dest;
1479 }
1480 else
1481 {
1482 int count = 2;
1483 for (; len; len--, s++ )
1484 {
1485 switch (*s)
1486 {
1487 case '\b':
1488 case '\t':
1489 case '\v':
1490 case '\n':
1491 case '\f':
1492 case '\r':
1493 case '\"':
1494 case '\'':
1495 case '\\': count += 2; break;
1496 default:
1497 if ( (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0)))
1498 count += 4;
1499 else
1500 count++;
1501 }
1502 }
1503 return count;
1504 }
1505}
1506
1507
1508
1509static int
1510convert_to_token (const unsigned char *src, size_t len, unsigned char *dest)
1511{
1512 if (dest)
1513 memcpy (dest, src, len);
1514 return len;
1515}
1516
1517
1518/****************
1519 * Print SEXP to buffer using the MODE. Returns the length of the
1520 * SEXP in buffer or 0 if the buffer is too short (We have at least an
1521 * empty list consisting of 2 bytes). If a buffer of NULL is provided,
1522 * the required length is returned.
1523 */
1524size_t
1525gcry_sexp_sprint( const gcry_sexp_t list, int mode,
1526 char *buffer, size_t maxlength )
1527{
1528 static byte empty[3] = { ST_OPEN, ST_CLOSE, ST_STOP };
1529 const byte *s;
1530 char *d;
1531 DATALEN n;
1532 char numbuf[20];
1533 size_t len = 0;
1534 int i, indent = 0;
1535
1536 s = list? list->d : empty;
1537 d = buffer;
1538 while ( *s != ST_STOP )
1539 {
1540 switch ( *s )
1541 {
1542 case ST_OPEN:
1543 s++;
1544 if ( mode != GCRYSEXP_FMT_CANON )
1545 {
1546 if (indent)
1547 len++;
1548 len += indent;
1549 }
1550 len++;
1551 if ( buffer )
1552 {
1553 if ( len >= maxlength )
1554 return 0;
1555 if ( mode != GCRYSEXP_FMT_CANON )
1556 {
1557 if (indent)
1558 *d++ = '\n';
1559 for (i=0; i < indent; i++)
1560 *d++ = ' ';
1561 }
1562 *d++ = '(';
1563 }
1564 indent++;
1565 break;
1566 case ST_CLOSE:
1567 s++;
1568 len++;
1569 if ( buffer )
1570 {
1571 if ( len >= maxlength )
1572 return 0;
1573 *d++ = ')';
1574 }
1575 indent--;
1576 if (*s != ST_OPEN && *s != ST_STOP && mode != GCRYSEXP_FMT_CANON)
1577 {
1578 len++;
1579 len += indent;
1580 if (buffer)
1581 {
1582 if (len >= maxlength)
1583 return 0;
1584 *d++ = '\n';
1585 for (i=0; i < indent; i++)
1586 *d++ = ' ';
1587 }
1588 }
1589 break;
1590 case ST_DATA:
1591 s++;
1592 memcpy ( &n, s, sizeof n ); s += sizeof n;
1593 if (mode == GCRYSEXP_FMT_ADVANCED)
1594 {
1595 int type;
1596 size_t nn;
1597
1598 switch ( (type=suitable_encoding (s, n)))
1599 {
1600 case 1: nn = convert_to_string (s, n, NULL); break;
1601 case 2: nn = convert_to_token (s, n, NULL); break;
1602 default: nn = convert_to_hex (s, n, NULL); break;
1603 }
1604 len += nn;
1605 if (buffer)
1606 {
1607 if (len >= maxlength)
1608 return 0;
1609 switch (type)
1610 {
1611 case 1: convert_to_string (s, n, d); break;
1612 case 2: convert_to_token (s, n, d); break;
1613 default: convert_to_hex (s, n, d); break;
1614 }
1615 d += nn;
1616 }
1617 if (s[n] != ST_CLOSE)
1618 {
1619 len++;
1620 if (buffer)
1621 {
1622 if (len >= maxlength)
1623 return 0;
1624 *d++ = ' ';
1625 }
1626 }
1627 }
1628 else
1629 {
1630 sprintf (numbuf, "%u:", (unsigned int)n );
1631 len += strlen (numbuf) + n;
1632 if ( buffer )
1633 {
1634 if ( len >= maxlength )
1635 return 0;
1636 d = stpcpy ( d, numbuf );
1637 memcpy ( d, s, n ); d += n;
1638 }
1639 }
1640 s += n;
1641 break;
1642 default:
1643 BUG ();
1644 }
1645 }
1646 if ( mode != GCRYSEXP_FMT_CANON )
1647 {
1648 len++;
1649 if (buffer)
1650 {
1651 if ( len >= maxlength )
1652 return 0;
1653 *d++ = '\n';
1654 }
1655 }
1656 if (buffer)
1657 {
1658 if ( len >= maxlength )
1659 return 0;
1660 *d++ = 0; /* for convenience we make a C string */
1661 }
1662 else
1663 len++; /* we need one byte more for this */
1664
1665 return len;
1666}
1667
1668
1669/* Scan a cannocial encoded buffer with implicit length values and
1670 return the actual length this S-expression uses. For a valid S-Exp
1671 it should never return 0. If LENGTH is not zero, the maximum
1672 length to scan is given - this can be used for syntax checks of
1673 data passed from outside. errorcode and erroff may both be passed as
1674 NULL. */
1675size_t
1676gcry_sexp_canon_len (const unsigned char *buffer, size_t length,
1677 size_t *erroff, gcry_error_t *errcode)
1678{
1679 const unsigned char *p;
1680 const char *disphint=NULL;
1681 unsigned int datalen = 0;
1682 size_t dummy_erroff;
1683 gcry_error_t dummy_errcode;
1684 size_t count = 0;
1685 int level = 0;
1686
1687 if (!erroff)
1688 erroff = &dummy_erroff;
1689 if (!errcode)
1690 errcode = &dummy_errcode;
1691
1692 *errcode = gcry_error (GPG_ERR_NO_ERROR);
1693 *erroff = 0;
1694 if (!buffer)
1695 return 0;
1696 if (*buffer != '(')
1697 {
1698 *errcode = gcry_error (GPG_ERR_SEXP_NOT_CANONICAL);
1699 return 0;
1700 }
1701
1702 for (p=buffer; ; p++, count++ )
1703 {
1704 if (length && count >= length)
1705 {
1706 *erroff = count;
1707 *errcode = gcry_error (GPG_ERR_SEXP_STRING_TOO_LONG);
1708 return 0;
1709 }
1710
1711 if (datalen)
1712 {
1713 if (*p == ':')
1714 {
1715 if (length && (count+datalen) >= length)
1716 {
1717 *erroff = count;
1718 *errcode = gcry_error (GPG_ERR_SEXP_STRING_TOO_LONG);
1719 return 0;
1720 }
1721 count += datalen;
1722 p += datalen;
1723 datalen = 0;
1724 }
1725 else if (digitp(p))
1726 datalen = datalen*10 + atoi_1(p);
1727 else
1728 {
1729 *erroff = count;
1730 *errcode = gcry_error (GPG_ERR_SEXP_INV_LEN_SPEC);
1731 return 0;
1732 }
1733 }
1734 else if (*p == '(')
1735 {
1736 if (disphint)
1737 {
1738 *erroff = count;
1739 *errcode = gcry_error (GPG_ERR_SEXP_UNMATCHED_DH);
1740 return 0;
1741 }
1742 level++;
1743 }
1744 else if (*p == ')')
1745 { /* walk up */
1746 if (!level)
1747 {
1748 *erroff = count;
1749 *errcode = gcry_error (GPG_ERR_SEXP_UNMATCHED_PAREN);
1750 return 0;
1751 }
1752 if (disphint)
1753 {
1754 *erroff = count;
1755 *errcode = gcry_error (GPG_ERR_SEXP_UNMATCHED_DH);
1756 return 0;
1757 }
1758 if (!--level)
1759 return ++count; /* ready */
1760 }
1761 else if (*p == '[')
1762 {
1763 if (disphint)
1764 {
1765 *erroff = count;
1766 *errcode = gcry_error (GPG_ERR_SEXP_NESTED_DH);
1767 return 0;
1768 }
1769 disphint = p;
1770 }
1771 else if (*p == ']')
1772 {
1773 if( !disphint )
1774 {
1775 *erroff = count;
1776 *errcode = gcry_error (GPG_ERR_SEXP_UNMATCHED_DH);
1777 return 0;
1778 }
1779 disphint = NULL;
1780 }
1781 else if (digitp (p) )
1782 {
1783 if (*p == '0')
1784 {
1785 *erroff = count;
1786 *errcode = gcry_error (GPG_ERR_SEXP_ZERO_PREFIX);
1787 return 0;
1788 }
1789 datalen = atoi_1 (p);
1790 }
1791 else if (*p == '&' || *p == '\\')
1792 {
1793 *erroff = count;
1794 *errcode = gcry_error (GPG_ERR_SEXP_UNEXPECTED_PUNC);
1795 return 0;
1796 }
1797 else
1798 {
1799 *erroff = count;
1800 *errcode = gcry_error (GPG_ERR_SEXP_BAD_CHARACTER);
1801 return 0;
1802 }
1803 }
1804}