e56e6c19f6ad0f80ebb5bf17fac765cd51520dc4
[libgcrypt.git] / src / sexp.c
1 /* sexp.c  -  S-Expression handling
2  *      Copyright (C) 1999 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21
22 /****************
23  * TODO:
24  *  - implement reference counting to defere freeing of
25  *    data and make copies of the data on demand.
26  *    --> do we really need this?
27  *
28  */
29
30 #include <config.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <ctype.h>
36 #include <assert.h>
37
38 #define GCRYPT_NO_MPI_MACROS 1
39 #include "g10lib.h"
40 #include "memory.h"
41
42
43
44 #if 0
45 struct sexp_node;
46 typedef struct sexp_node *NODE;
47
48 struct gcry_sexp {
49     int orig_format;  /* format which we used to create this object */
50     NODE sexp;        /* a NULL indicates an empty list */
51 };
52 #else
53 typedef struct gcry_sexp *NODE;
54 #endif
55
56
57 enum node_types { ntLIST, ntDATA, ntMPI };
58
59 struct gcry_sexp {
60     NODE next;
61     NODE up;        /* helper needed for faster traversal */
62     enum node_types type;
63     union {
64         NODE list;
65         GCRY_MPI mpi;
66         struct {
67             size_t len;
68             byte  d[1];
69         } data;
70     } u;
71 };
72
73
74 static void
75 dump_mpi( GCRY_MPI a )
76 {
77     char buffer[1000];
78     size_t n = 1000;
79
80     if( !a )
81         fputs("[no MPI]", stderr );
82     else if( gcry_mpi_print( GCRYMPI_FMT_HEX, buffer, &n, a ) )
83         fputs("[MPI too large to print]", stderr );
84     else
85         fputs( buffer, stderr );
86 }
87
88 static void
89 dump_string( FILE *fp, const byte *p, size_t n, int delim )
90 {
91     for( ; n; n--, p++ )
92         if( iscntrl( *p ) || *p == delim ) {
93             putc('\\', fp);
94             if( *p == '\n' )
95                 putc('n', fp);
96             else if( *p == '\r' )
97                 putc('r', fp);
98             else if( *p == '\f' )
99                 putc('f', fp);
100             else if( *p == '\v' )
101                 putc('v', fp);
102             else if( *p == '\b' )
103                 putc('b', fp);
104             else if( !*p )
105                 putc('0', fp);
106             else
107                 fprintf(fp, "x%02x", *p );
108         }
109         else
110             putc(*p, fp);
111 }
112
113 static void
114 do_dump_list( NODE node, int indent )
115 {
116     for( ; node; node = node->next ) {
117         switch( node->type ) {
118           case ntLIST:
119             if( indent )
120                 putc('\n', stderr);
121             fprintf(stderr, "%*s(", indent, "");
122             do_dump_list( node->u.list, indent+1 );
123             putc(')', stderr);
124             break;
125           case ntDATA:
126             if( !node->u.data.len )
127                 fputs("EMPTY", stderr );
128             else
129                 dump_string(stderr, node->u.data.d, node->u.data.len, ')');
130             putc(' ', stderr);
131             break;
132           case ntMPI:
133             dump_mpi( node->u.mpi );
134             putc(' ', stderr);
135             break;
136         }
137         if( !indent )
138             putc('\n', stderr);
139     }
140 }
141
142 static void
143 dump_sexp( NODE node )
144 {
145     do_dump_list( node, 0 );
146 }
147
148
149 void
150 gcry_sexp_dump( GCRY_SEXP a )
151 {
152     do_dump_list( a, 0 );
153 }
154
155
156 /****************
157  * Create a new SEXP element (data)
158  * If length is 0 it is assumed that buffer is a C string.
159  */
160 GCRY_SEXP
161 gcry_sexp_new_data( const char *buffer, size_t length )
162 {
163     NODE list, node;
164
165     if( !length )
166         length = strlen(buffer);
167     node = g10_xcalloc( 1, sizeof *node + length );
168     node->type = ntDATA;
169     node->u.data.len = length;
170     memcpy(node->u.data.d, buffer, length );
171     list = g10_xcalloc( 1, sizeof *list );
172     list->type = ntLIST;
173     list->u.list = node;
174     return list;
175 }
176
177 /****************
178  * Create a new SEXP element (mpi)
179  */
180 GCRY_SEXP
181 gcry_sexp_new_mpi( GCRY_MPI mpi )
182 {
183     NODE list, node;
184
185     node = g10_xcalloc( 1, sizeof *node );
186     node->type = ntMPI;
187     node->u.mpi = gcry_mpi_copy( mpi );
188     list = g10_xcalloc( 1, sizeof *list );
189     list->type = ntLIST;
190     list->u.list = node;
191     return list;
192 }
193
194
195 /****************
196  * Create a pair of a name and some arbitrary data.
197  */
198 GCRY_SEXP
199 gcry_sexp_new_name_data( const char *name, const char *buffer, size_t length )
200 {
201     return gcry_sexp_cons( gcry_sexp_new_data( name, 0 ),
202                            gcry_sexp_new_data( buffer, length ) );
203 }
204
205 /****************
206  * Create a pair of a name and a MPI
207  */
208 GCRY_SEXP
209 gcry_sexp_new_name_mpi( const char *name, GCRY_MPI mpi )
210 {
211     return gcry_sexp_cons( gcry_sexp_new_data( name, 0 ),
212                            gcry_sexp_new_mpi( mpi ) );
213 }
214
215
216 /****************
217  * Release resource of the given SEXP object.
218  */
219 void
220 gcry_sexp_release( GCRY_SEXP sexp )
221 {
222     /* FIXME! */
223 }
224
225
226
227
228 /****************
229  * Make a pair from lists a and b, don't use a or b later on.
230  * Special behaviour:  If one is a single element list we put the
231  * element straight into the new pair.
232  */
233 GCRY_SEXP
234 gcry_sexp_cons( GCRY_SEXP a, GCRY_SEXP b )
235 {
236     NODE head;
237
238     if( a->type != ntLIST ) {
239         fputs("sexp_cons: arg 1 is not a list\n", stderr );
240         return NULL;
241     }
242     if( b->type != ntLIST ) {
243         fputs("sexp_cons: arg 2 is not a list\n", stderr );
244         return NULL;
245     }
246
247
248     head = g10_xcalloc( 1, sizeof *head );
249     head->type = ntLIST;
250     if( !a->u.list->next ) { /* a has only one item */
251         NODE tmp = a;
252         a = a->u.list;
253         /* fixme: release tmp here */
254     }
255     if( !b->u.list->next ) { /* b has only one item */
256         NODE tmp = b;
257         b = b->u.list;
258         /* fixme: release tmp here */
259     }
260
261     head->u.list = a;
262     a->up = head;
263     a->next = b;
264     b->up = head;
265
266     return head;
267 }
268
269
270 /****************
271  * Make a list from all items in the array the end of the array is marked
272  * with a NULL.                                                                       y a NULL
273  * Don't use the passed lists later on, they are void.
274  */
275 GCRY_SEXP
276 gcry_sexp_alist( GCRY_SEXP *array )
277 {
278     NODE head, tail = NULL, node;
279     va_list arg_ptr ;
280     int i;
281
282     if( !*array )
283         return NULL;
284
285     head = g10_xcalloc( 1, sizeof *node );
286     head->type = ntLIST;
287
288     for( i=0; (node = array[i]); i++ ) {
289         if( node->type != ntLIST ) {
290             fputs("sexp_alist: an arg is not a list\n", stderr );
291             return NULL;  /* fixme: we should release already allocated nodes */
292         }
293         if( !node->u.list->next ) { /* node has only one item */
294             NODE tmp = node;
295             node = node->u.list;
296             /* fixme: release tmp here */
297         }
298         if( !tail )  {
299             head->u.list = node;
300         }
301         else
302             tail->next = node;
303         node->up = head;
304         tail = node;
305     }
306
307     return head;
308 }
309
310 /****************
311  * Make a list from all items, the end of list is indicated by a NULL
312  * don't use the passed lists later on, they are void.
313  */
314 GCRY_SEXP
315 gcry_sexp_vlist( GCRY_SEXP a, ... )
316 {
317     NODE head, tail, node;
318     va_list arg_ptr ;
319
320     if( a->type != ntLIST ) {
321         fputs("sexp_vlist: arg 1 is not a list\n", stderr );
322         return NULL;
323     }
324     head = g10_xcalloc( 1, sizeof *node );
325     head->type = ntLIST;
326     if( !a->u.list->next ) { /* a has only one item */
327         NODE tmp = a;
328         a = a->u.list;
329         /* fixme: release tmp here */
330     }
331     head->u.list = a;
332     a->up = head;
333     tail = a;
334
335     va_start( arg_ptr, a ) ;
336     while( (node = va_arg( arg_ptr, NODE )) ) {
337         if( node->type != ntLIST ) {
338             fputs("sexp_vlist: an arg is not a list\n", stderr );
339             return NULL;  /* fixme: we should release already allocated nodes */
340         }
341         if( !node->u.list->next ) { /* node has only one item */
342             NODE tmp = node;
343             node = node->u.list;
344             /* fixme: release tmp here */
345         }
346         tail->next = node;
347         node->up = head;
348         tail = node;
349     }
350
351     va_end( arg_ptr );
352     return head;
353 }
354
355
356 /****************
357  * Append n to the list a
358  * Don't use n later on.
359  * Returns: a new ist (which maybe a)
360  */
361 GCRY_SEXP
362 gcry_sexp_append( GCRY_SEXP a, GCRY_SEXP n )
363 {
364     GCRY_SEXP node;
365
366     if( a->type != ntLIST ) {
367         fputs("sexp_append: a is not a list\n", stderr );
368         return a;
369     }
370
371     if( n->type != ntLIST ) {
372         fputs("sexp_append: n is not a list\n", stderr );
373         return a;
374     }
375
376     for( node = a; node->next; node = node->next )
377         ;
378
379     node->next = n;
380     return a;
381 }
382
383 GCRY_SEXP
384 gcry_sexp_prepend( GCRY_SEXP a, GCRY_SEXP n )
385 {
386
387     fputs("sexp_prepend: not impl.\n", stderr );
388     return a;
389 }
390
391
392
393 /****************
394  * Locate data in a list. Data must be the first item in the list.
395  * Returns: The sublist with that Data (don't modify it!)
396  */
397 GCRY_SEXP
398 gcry_sexp_find_token( GCRY_SEXP list, const char *tok, size_t toklen )
399 {
400     NODE node;
401
402     if( !toklen )
403         toklen = strlen(tok);
404
405     for( node=list ; node; node = node->next )
406       {
407         switch( node->type ) {
408           case ntLIST: {
409                 NODE n = gcry_sexp_find_token( node->u.list, tok, toklen );
410                 if( n )
411                     return n;
412             }
413             break;
414           case ntDATA:
415             if( node == list
416                 && node->u.data.len == toklen
417                 && !memcmp( node->u.data.d, tok, toklen ) )
418               {
419                 return node;
420               }
421             break;
422           case ntMPI:
423             break;
424         }
425       }
426
427     return NULL;
428 }
429
430
431 /****************
432  * Enumerate all objects in the list.  Ther first time you call this, pass
433  * the address of a void pointer initialized to NULL.  Then don't touch this
434  * variable anymore but pass it verbatim to the function; you will get
435  * all lists back in turn. End of lists is indicated by a returned NIL in
436  * whic case you should not continue to use this function
437  * (it would wrap around).  If you decide to cancel the operation before
438  * the final NIL you vae to release the context by calling the function
439  * with a the context but a LIST set to NULL.
440  * Note that this function returns only lists and not single objects.
441  */
442 GCRY_SEXP
443 gcry_sexp_enum( GCRY_SEXP list, void **context, int mode )
444 {
445     NODE node;
446
447     if( mode )
448         return NULL; /* mode is reserved and must be 0 */
449     if( !list ) {
450         /* we are lucky that we can hold all information in the pointer
451          * value ;-) - so there is no need to release any memory */
452         *context = NULL;
453         return NULL;
454     }
455     if( !*context )  /* start enumeration */
456         node = list;
457     else {
458         node = *context;
459         node = node->next;
460     }
461
462     for( ; node; node = node->next ) {
463         *context = node; /* store our context */
464         if( node->type == ntLIST )
465             return node->u.list;
466         return node;
467     }
468
469     /* release resources and return nil */
470     return gcry_sexp_enum( NULL, context, mode );
471 }
472
473
474
475 /****************
476  * Get the CAR
477  */
478 GCRY_SEXP
479 gcry_sexp_car( GCRY_SEXP list )
480 {
481     return list;
482 }
483
484 /****************
485  * Get data from the car
486  */
487 const char *
488 gcry_sexp_car_data( GCRY_SEXP list, size_t *datalen )
489 {
490     if( list && list->type == ntLIST && !list->next )
491         list = list->u.list;
492     if( list && list->type == ntDATA ) {
493         *datalen = list->u.data.len;
494         return list->u.data.d;
495     }
496
497     return NULL;
498 }
499
500 /****************
501  * Get a MPI from the car
502  */
503 GCRY_MPI
504 gcry_sexp_car_mpi( GCRY_SEXP list, int mpifmt )
505 {
506     if( list && list->type == ntLIST && !list->next )
507         list = list->u.list;
508     if( mpifmt && list->type == ntDATA ) {
509         MPI a;
510         size_t n = list->u.data.len;
511         if( gcry_mpi_scan( &a, mpifmt, list->u.data.d, &n ) )
512             return NULL;
513         return a;
514     }
515     else if( list->type == ntMPI )
516         return gcry_mpi_copy( list->u.mpi );
517
518     return NULL;
519 }
520
521 /****************
522  * Get the CDR
523  */
524 GCRY_SEXP
525 gcry_sexp_cdr( GCRY_SEXP list )
526 {
527     if( list && (list = list->next) )
528         return list;
529     return NULL;
530 }
531
532 /****************
533  * Get data from the cdr assuming this is a pair
534  */
535 const char *
536 gcry_sexp_cdr_data( GCRY_SEXP list, size_t *datalen )
537 {
538     if( list && (list = list->next) && list->type == ntDATA ) {
539         *datalen = list->u.data.len;
540         return list->u.data.d;
541     }
542
543     return NULL;
544 }
545
546
547 /****************
548  * cdr the mpi from the list or NULL if there is no MPI.
549  * This function tries to convert plain data to an MPI.
550  * Actually this funtion returns only the second item of the list
551  * and ignores any further arguments.
552  */
553 GCRY_MPI
554 gcry_sexp_cdr_mpi( GCRY_SEXP list, int mpifmt )
555 {
556     NODE node = list;
557
558     if( !node || !(node = node->next) || node == ntLIST )
559         return NULL;
560     if( mpifmt && node->type == ntDATA ) {
561         MPI a;
562         size_t n = node->u.data.len;
563         if( gcry_mpi_scan( &a, mpifmt, node->u.data.d, &n ) )
564             return NULL;
565         return a;
566     }
567     else if( node->type == ntMPI )
568         return gcry_mpi_copy( node->u.mpi );
569     else
570         return NULL;
571 }
572
573
574 /****************
575  * Scan the provided buffer and return the S expression in our internal
576  * format.  Returns a newly allocated expression.  If erroff is not NULL and
577  * a parsing error has occured, the offset into buffer will be returned.
578  */
579 int
580 gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
581                                      size_t length, size_t *erroff )
582 {
583     static const char tokenchars[] = "abcdefghijklmnopqrstuvwxyz"
584                                      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
585                                      "0123456789-./_:*+=";
586     const char *p;
587     size_t n;
588     NODE head, tail, node;
589     const char *digptr=NULL;
590     const char *quoted=NULL;
591     const char *tokenp=NULL;
592     const char *hexfmt=NULL;
593     const char *base64=NULL;
594     const char *disphint=NULL;
595     int quoted_esc=0;
596     int datalen=0;
597     int first;
598
599     tail = head = NULL;
600     first = 0;
601     for(p=buffer,n=length; n; p++, n-- ) {
602         if( tokenp ) {
603             if( strchr( tokenchars, *p ) )
604                 continue;
605         }
606         if( quoted ) {
607             if( quoted_esc ) {
608                 switch( *p ) {
609                   case 'b': case 't': case 'v': case 'n': case 'f':
610                   case 'r': case '"': case '\'': case '\\':
611                     quoted_esc = 0;
612                     break;
613                   case '0': case '1': case '2': case '3': case '4':
614                   case '5': case '6': case '7':
615                     if( !(n > 2 && p[1] >= '0' && p[1] <= '7'
616                                 && p[2] >= '0' && p[2] <= '7') ) {
617                         *erroff = p - buffer;
618                         return -6;   /* invalid octal value */
619                     }
620                     p += 2; n -= 2;
621                     quoted_esc = 0;
622                     break;
623                   case 'x':
624                     if( !(n > 2 && isxdigit(p[1]) && isxdigit(p[2]) ) ) {
625                         *erroff = p - buffer;
626                         return -6;   /* invalid hex value */
627                     }
628                     p += 2; n -= 2;
629                     quoted_esc = 0;
630                     break;
631                   case '\r':  /* ignore CR[,LF] */
632                     if( n && p[1] == '\n' ) {
633                         p++; n--;
634                     }
635                     quoted_esc = 0;
636                     break;
637                   case '\n':  /* ignore LF[,CR] */
638                     if( n && p[1] == '\r' ) {
639                         p++; n--;
640                     }
641                     quoted_esc = 0;
642                     break;
643                   default:
644                     *erroff = p - buffer;
645                     return -6;   /* invalid quoted string escape */
646                 }
647             }
648             else if( *p == '\\' )
649                 quoted_esc = 1;
650             else if( *p == '\"' ) {
651                 /* fixme: add item */
652                 quoted = NULL;
653             }
654         }
655         else if( hexfmt ) {
656             if( *p == '#' )
657                hexfmt = NULL;
658         }
659         else if( base64 ) {
660             if( *p == '|' )
661                base64 = NULL;
662         }
663         else if( digptr ) {
664             if( isdigit(*p) )
665                 ;
666             else if( *p == ':' ) {
667                 if( !head ) {
668                     *erroff = 0;
669                     return -4;   /* not a list */
670                 }
671                 datalen = atoi( digptr ); /* fixme: check for overflow */
672                 digptr = NULL;
673                 if( datalen > n-1 ) {
674                     *erroff = p - buffer;
675                     return -2; /* buffer too short */
676                 }
677                 /* make a new list entry */
678                 node = g10_xcalloc( 1, sizeof *node + datalen );
679                 if( first ) { /* stuff it into the first node */
680                     first = 0;
681                     node->up = tail;
682                     tail->u.list = node;
683                 }
684                 else {
685                     node->up = tail->up;
686                     tail->next = node;
687                 }
688                 tail = node;
689                 /* and fill in the value (we store the value in the node)*/
690                 node->type = ntDATA;
691                 node->u.data.len = datalen;
692                 memcpy(node->u.data.d, p+1, datalen );
693
694                 n -= datalen;
695                 p += datalen;
696             }
697             else if( *p == '\"' ) {
698                 digptr = NULL; /* we ignore the optional length */
699                 quoted = p;
700                 quoted_esc = 0;
701             }
702             else if( *p == '#' ) {
703                 digptr = NULL; /* we ignore the optional length */
704                 hexfmt = p;
705             }
706             else if( *p == '|' ) {
707                 digptr = NULL; /* we ignore the optional length */
708                 base64 = p;
709             }
710             else {
711                 *erroff = p - buffer;
712                 return -1;
713             }
714         }
715         else if( *p == '(' ) {
716             if( disphint ) {
717                 *erroff = p - buffer;
718                 return -9; /* open display hint */
719             }
720             node = g10_xcalloc( 1, sizeof *node );
721             if( !head )
722                 head = node;
723             else {
724                 node->up = tail->up;
725                 tail->next = node;
726             }
727             node->type = ntLIST;
728             tail = node;
729             first = 1;
730         }
731         else if( *p == ')' ) { /* walk up */
732             if( disphint ) {
733                 *erroff = p - buffer;
734                 return -9; /* open display hint */
735             }
736             if( !head ) {
737                 *erroff = 0;
738                 return -4;   /* not a list */
739             }
740             tail = tail->up;
741             if( !tail ) {
742                 *erroff = p - buffer;
743                 return -3;
744             }
745         }
746         else if( *p == '\"' ) {
747             quoted = p;
748             quoted_esc = 0;
749         }
750         else if( *p == '#' )
751             hexfmt = p;
752         else if( *p == '|' )
753             base64 = p;
754         else if( *p == '[' ) {
755             if( disphint ) {
756                 *erroff = p - buffer;
757                 return -8; /* nested display hints */
758             }
759             disphint = p;
760         }
761         else if( *p == ']' ) {
762             if( !disphint ) {
763                 *erroff = p - buffer;
764                 return -9; /* unmatched display hint close */
765             }
766             disphint = NULL;
767         }
768         else if( isdigit(*p) ) {
769             if( *p == '0' ) { /* a length may not begin with zero */
770                 *erroff = p - buffer;
771                 return -7;
772             }
773             digptr = p;
774         }
775         else if( strchr( tokenchars, *p ) )
776             tokenp = p;
777         else if( isspace(*p) )
778             ;
779         else if( *p == '{' ) {
780             /* fixme: handle rescanning:
781              * we can do this by saving our current state
782              * and start over at p+1 -- Hmmm. At this point here
783              * we are in a well defined state, so we don't need to save
784              * it.  Great.
785              */
786             *erroff = p - buffer;
787             return -10; /* unexpected reserved punctuation */
788         }
789         else if( strchr( "&\\", *p ) ) { /*reserved punctuation*/
790             *erroff = p - buffer;
791             return -10; /* unexpected reserved punctuation */
792         }
793         else { /* bad or unavailable*/
794             *erroff = p - buffer;
795             return -5;
796         }
797
798     }
799     *retsexp = head;
800     return 0;
801 }
802
803
804 /****************
805  * Print SEXP to buffer using the MODE.  Returns the length of the
806  * SEXP in buffer or 0 if the buffer is too short (We have at least an
807  * empty list consisting of 2 bytes).  If a buffer of NULL is provided,
808  * the required length is returned.
809  */
810 size_t
811 gcry_sexp_sprint( GCRY_SEXP sexp, int mode, char *buffer, size_t maxlength )
812 {
813     return 0;
814 }
815
816
817
818
819
820 #if 0
821 /***********************************************************/
822
823 const char *
824 strusage( int level )
825 {
826     return default_strusage(level);
827 }
828
829
830 static int
831 sexp_to_pk( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo)
832 {
833     GCRY_SEXP list, l2;
834     const char *name;
835     const char *s;
836     size_t n;
837     int i, idx;
838     int algo;
839     const char *elems1, *elems2;
840     GCRY_MPI *array;
841     static struct { const char* name; int algo;
842                     const char* common_elements;
843                     const char* public_elements;
844                     const char* secret_elements;
845                   } algos[] = {
846         {  "dsa"            , PUBKEY_ALGO_DSA       , "pqgy", "", "x"    },
847         {  "rsa"            , PUBKEY_ALGO_RSA       , "ne",   "", "dpqu" },
848         {  "openpgp-dsa"    , PUBKEY_ALGO_DSA       , "pqgy", "", "x"    },
849         {  "openpgp-rsa"    , PUBKEY_ALGO_RSA       , "pqgy", "", "x"    },
850         {  "openpgp-elg"    , PUBKEY_ALGO_ELGAMAL_E , "pgy",  "", "x"    },
851         {  "openpgp-elg-sig", PUBKEY_ALGO_ELGAMAL   , "pgy",  "", "x"    },
852         {  NULL }};
853
854     /* check that the first element is valid */
855     list = gcry_sexp_find_token( sexp, want_private? "private-key"
856                                                     :"public-key", 0 );
857     if( !list )
858         return -1; /* Does not contain a public- or private-key object */
859     list = gcry_sexp_cdr( list );
860     if( !list )
861         return -2; /* no cdr for the key object */
862     name = gcry_sexp_car_data( list, &n );
863     if( !name )
864         return -3; /* invalid structure of object */
865     fprintf(stderr, "algorithm name: `%.*s'\n", (int)n, name );
866     for(i=0; (s=algos[i].name); i++ ) {
867         if( strlen(s) == n && !memcmp( s, name, n ) )
868             break;
869     }
870     if( !s )
871         return -4; /* unknown algorithm */
872     algo = algos[i].algo;
873     elems1 = algos[i].common_elements;
874     elems2 = want_private? algos[i].secret_elements : algos[i].public_elements;
875     array = g10_xcalloc( (strlen(elems1)+strlen(elems2)+1) , sizeof *array );
876     idx = 0;
877     for(s=elems1; *s; s++, idx++ ) {
878         l2 = gcry_sexp_find_token( list, s, 1 );
879         if( !l2 ) {
880             g10_free( array );
881             return -5; /* required parameter not found */
882         }
883         array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
884         if( !array[idx] ) {
885             g10_free( array );
886             return -6; /* required parameter is invalid */
887         }
888     }
889     for(s=elems2; *s; s++, idx++ ) {
890         l2 = gcry_sexp_find_token( list, s, 1 );
891         if( !l2 ) {
892             g10_free( array );
893             return -5; /* required parameter not found */
894         }
895         /* FIXME: put the MPI in secure memory when needed */
896         array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
897         if( !array[idx] ) {
898             g10_free( array );
899             return -6; /* required parameter is invalid */
900         }
901     }
902
903     *retarray = array;
904     *retalgo = algo;
905
906     return 0;
907 }
908
909
910
911 int
912 main(int argc, char **argv)
913 {
914     char buffer[5000];
915     size_t erroff;
916     int rc, n;
917     FILE *fp;
918     GCRY_SEXP s_pk, s_dsa, s_p, s_q, s_g, s_y, sexp;
919
920   #if 0
921     fp = stdin;
922     n = fread(buffer, 1, 5000, fp );
923     rc = gcry_sexp_sscan( &sexp, buffer, n, &erroff );
924     if( rc ) {
925         fprintf(stderr, "parse error %d at offset %u\n", rc, erroff );
926         exit(1);
927     }
928     fputs("We have this S-Exp:\n",stderr);
929     dump_sexp( sexp );
930   #else
931     s_pk = SEXP_NEW( "public-key", 10 );
932     fputs("pk:\n",stderr);dump_sexp( s_pk );
933     s_dsa = SEXP_NEW( "dsa", 3 );
934     s_p = SEXP_CONS( SEXP_NEW( "p", 1 ), SEXP_NEW( "PPPPPP", 6 ) );
935     fputs("p:\n",stderr);dump_sexp( s_p );
936     s_y = SEXP_CONS( SEXP_NEW( "y", 1 ), SEXP_NEW( "YYYYYYYY", 8 ) );
937     fputs("y:\n",stderr);dump_sexp( s_y );
938     s_q = gcry_sexp_new_name_data( "q", "QQQ", 3 );
939     fputs("q:\n",stderr);dump_sexp( s_q );
940     s_g = gcry_sexp_new_name_mpi( "g" , gcry_mpi_set_ui(NULL, 42) );
941     fputs("g:\n",stderr);dump_sexp( s_g );
942     sexp = SEXP_CONS( s_pk, gcry_sexp_vlist( s_dsa,
943                                              s_y,
944                                              s_p,
945                                              s_q,
946                                              s_g,
947                                              NULL ));
948     fputs("Here is what we have:\n",stderr);
949     dump_sexp( sexp );
950   #endif
951
952     /* now find something */
953     if( argc > 1 )
954       {
955         GCRY_SEXP s1;
956
957         s1 = gcry_sexp_find_token( sexp, argv[1], strlen(argv[1]) );
958         if( !s1 )
959           {
960             fprintf(stderr, "didn't found `%s'\n", argv[1] );
961           }
962         else
963           {
964             fprintf(stderr, "found `%s':\n", argv[1] );
965             dump_sexp( s1 );
966           }
967
968         #if 1
969         {  int i,rc, algo;
970            GCRY_MPI *array;
971
972            rc = sexp_to_pk( s1, 0, &array, &algo);
973            if( rc )
974               fprintf(stderr, "sexp_to_pk failed: rc=%d\n", rc );
975            else {
976                for(i=0; array[i]; i++ ) {
977                    fprintf(stderr, "MPI[%d]: ", i);
978                    dump_mpi( array[i] );
979                    fprintf(stderr, "\n");
980                }
981             }
982         }
983         #endif
984
985
986         if( argc > 2 ) /* get the MPI out of the list */
987         #if 0
988           {
989             GCRY_SEXP s2;
990             const char *p;
991             size_t n;
992
993             p = gcry_sexp_car_data( s1, &n );
994             if( !p ) {
995                 fputs("no CAR\n", stderr );
996                 exit(1);
997             }
998             fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
999
1000             p = gcry_sexp_cdr_data( s1, &n );
1001             if( !p ) {
1002                 s2 = gcry_sexp_cdr( s1 );
1003                 if( !s2 ) {
1004                     fputs("no CDR at all\n", stderr );
1005                     exit(1);
1006                 }
1007                 p = gcry_sexp_car_data( s2, &n );
1008             }
1009             if( !p ) {
1010                 fputs("no CDR data\n", stderr );
1011                 exit(1);
1012             }
1013             fprintf(stderr, "CDR=`%.*s'\n", (int)n, p );
1014
1015
1016
1017           }
1018         #elif 1
1019           {
1020             GCRY_SEXP s2;
1021             MPI a;
1022             const char *p;
1023             size_t n;
1024
1025             fprintf(stderr,"*********************************\n");
1026             p = gcry_sexp_car_data( s1, &n );
1027             if( !p ) {
1028                 fputs("no CAR\n", stderr );
1029                 exit(1);
1030             }
1031             fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
1032             s2 = gcry_sexp_cdr( s1 );
1033             if( !s2 ) {
1034                 fputs("no CDR\n", stderr );
1035                 exit(1);
1036
1037             }
1038             p = gcry_sexp_car_data( s2, &n );
1039             if( !p ) {
1040                 fputs("no data at CAR\n", stderr );
1041                 exit(1);
1042             }
1043             fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
1044
1045             s2 = gcry_sexp_find_token( s1, argv[2], strlen(argv[2]) );
1046             if( !s2 )
1047             {
1048                fprintf(stderr, "didn't found `%s'\n", argv[2] );
1049                exit(1);
1050             }
1051             p = gcry_sexp_car_data( s2, &n );
1052             if( !p ) {
1053                 fputs("no CAR\n", stderr );
1054                 exit(1);
1055             }
1056             fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
1057
1058             a = gcry_sexp_cdr_mpi( s2, GCRYMPI_FMT_USG );
1059             if( a ) {
1060                 fprintf(stderr, "MPI: ");
1061                 dump_mpi( a );
1062                 fprintf(stderr, "\n");
1063             }
1064             else
1065                 fprintf(stderr, "cannot cdr a mpi\n" );
1066           }
1067          #else
1068           {    /* print all MPIs */
1069             void *ctx = NULL;
1070             GCRY_SEXP s2;
1071             MPI a;
1072
1073             while( (s2 = gcry_sexp_enum( s1, &ctx, 0 )) )
1074               {
1075                 const char *car_d;
1076                 size_t car_n;
1077
1078                 car_d = gcry_sexp_car_data( s2, &car_n );
1079                 if( car_d ) {
1080                    fprintf(stderr, "CAR: %.*s=", (int)car_n, car_d );
1081                    a = gcry_sexp_cdr_mpi( s2, GCRYMPI_FMT_USG );
1082                    dump_mpi( a );
1083                    fprintf(stderr, "\n");
1084
1085                 }
1086                 else
1087                     fprintf(stderr, "no CAR\n");
1088               }
1089           }
1090          #endif
1091       }
1092     return 0;
1093 }
1094 #endif