Page MenuHome GnuPG

sexp.c
No OneTemporary

/* sexp.c - S-Expression handling
* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <assert.h>
#define GCRYPT_NO_MPI_MACROS 1
#include "g10lib.h"
#include "memory.h"
typedef struct gcry_sexp *NODE;
typedef unsigned short DATALEN;
struct gcry_sexp {
byte d[1];
};
#define ST_STOP 0 /* datalen does not follow this tag */
#define ST_DATA 1
#define ST_HINT 2
#define ST_OPEN 3
#define ST_CLOSE 4 /* datalen does not follow this tag */
#if 0
static void
dump_mpi( GCRY_MPI a )
{
char buffer[1000];
size_t n = 1000;
if( !a )
fputs("[no MPI]", stderr );
else if( gcry_mpi_print( GCRYMPI_FMT_HEX, buffer, &n, a ) )
fputs("[MPI too large to print]", stderr );
else
fputs( buffer, stderr );
}
#endif
static void
dump_string( FILE *fp, const byte *p, size_t n, int delim )
{
for( ; n; n--, p++ )
if( iscntrl( *p ) || *p == delim ) {
putc('\\', fp);
if( *p == '\n' )
putc('n', fp);
else if( *p == '\r' )
putc('r', fp);
else if( *p == '\f' )
putc('f', fp);
else if( *p == '\v' )
putc('v', fp);
else if( *p == '\b' )
putc('b', fp);
else if( !*p )
putc('0', fp);
else
fprintf(fp, "x%02x", *p );
}
else
putc(*p, fp);
}
void
gcry_sexp_dump( GCRY_SEXP a )
{
const byte *p;
DATALEN n;
int indent = 0;
int type;
if ( !a ) {
fputs ( "[NULL]\n", stderr );
return;
}
p = a->d;
while ( (type = *p) != ST_STOP ) {
if ( type == ST_CLOSE ) {
n = 0;
p++;
}
else {
memcpy ( &n, ++p, sizeof n );
p += sizeof n;
}
switch ( type ) {
case ST_OPEN:
fprintf ( stderr, "%*s[open len=%u]\n", 2*indent, "", n );
indent++;
break;
case ST_CLOSE:
if( indent )
indent--;
fprintf ( stderr, "%*s[close]\n", 2*indent, "" );
break;
case ST_DATA:
fprintf ( stderr, "%*s[data=\"", 2*indent, "" );
dump_string ( stderr, p, n, '\"' );
fputs ( "\"]\n", stderr );
p += n;
break;
default:
fprintf ( stderr, "%*s[unknown tag %d]\n", 2*indent, "", type );
p += n;
break;
}
}
}
/****************
* Release resource of the given SEXP object.
*/
void
gcry_sexp_release( GCRY_SEXP sexp )
{
g10_free ( sexp );
}
static GCRY_SEXP
new_empty_list ( void )
{
GCRY_SEXP newlist;
byte *p;
DATALEN n;
newlist = g10_xmalloc ( sizeof *newlist + 3 + sizeof(DATALEN) - 1 );
p = newlist->d;
*p++ = ST_OPEN;
n = 1; /* the close is the only element */
memcpy ( p, &n, sizeof n ); p += sizeof n;
*p++ = ST_CLOSE;
*p++ = ST_STOP;
return newlist;
}
/****************
* Make a pair from lists a and b, don't use a or b later on.
* Special behaviour: If one is a single element list we put the
* element straight into the new pair.
*/
GCRY_SEXP
gcry_sexp_cons( GCRY_SEXP a, GCRY_SEXP b )
{
/* NYI: Implementation should be quite easy with our new data representation */
BUG ();
return NULL;
}
/****************
* Make a list from all items in the array the end of the array is marked
* with a NULL. y a NULL
*/
GCRY_SEXP
gcry_sexp_alist( GCRY_SEXP *array )
{
/* NYI: Implementaion should be quite easy with our new data representation */
BUG ();
return NULL;
}
/****************
* Make a list from all items, the end of list is indicated by a NULL
*/
GCRY_SEXP
gcry_sexp_vlist( GCRY_SEXP a, ... )
{
/* NYI: Implementaion should be quite easy with our new data representation */
BUG ();
return NULL;
}
/****************
* Append n to the list a
* Returns: a new ist (which maybe a)
*/
GCRY_SEXP
gcry_sexp_append( GCRY_SEXP a, GCRY_SEXP n )
{
/* NYI: Implementaion should be quite easy with our new data representation */
BUG ();
return NULL;
}
GCRY_SEXP
gcry_sexp_prepend( GCRY_SEXP a, GCRY_SEXP n )
{
/* NYI: Implementaion should be quite easy with our new data representation */
BUG ();
return NULL;
}
/****************
* Locate token in a list. The token must be the car of a sublist.
* Returns: A new list with this sublist or NULL if not found.
*/
GCRY_SEXP
gcry_sexp_find_token( GCRY_SEXP list, const char *tok, size_t toklen )
{
byte *p = list->d;
DATALEN n;
int type;
if( !toklen )
toklen = strlen(tok);
while ( (type=*p) != ST_STOP ) {
byte *head = p;
DATALEN headlen;
p++;
if ( type == ST_CLOSE )
n = 0;
else {
memcpy ( &n, p, sizeof n );
p += sizeof n;
}
headlen = n + 1 + sizeof(DATALEN);
if ( type == ST_OPEN ) {
int type2 = *p;
byte *pp = p+1;
DATALEN nn;
memcpy ( &nn, pp, sizeof nn );
pp += sizeof nn;
if ( type2 == ST_DATA ) {
if ( nn == toklen && !memcmp( pp, tok, toklen ) ) { /* found it */
GCRY_SEXP sexp = g10_xmalloc ( sizeof *sexp + headlen + 1 );
memcpy ( sexp->d, head, headlen );
sexp->d[headlen] = ST_CLOSE;
sexp->d[headlen+1] = ST_STOP;
return sexp;
}
}
p = pp + nn;
}
else {
p += n;
}
}
return NULL;
}
/****************
* Enumerate all objects in the list. Ther first time you call this, pass
* the address of a void pointer initialized to NULL. Then don't touch this
* variable anymore but pass it verbatim to the function; you will get
* all lists back in turn. End of lists is indicated by a returned NIL in
* which case you should not continue to use this function
* (it would wrap around). If you decide to cancel the operation before
* the final NIL you have to release the context by calling the function
* with a the context but a LIST set to NULL.
* Note that this function returns only lists and not single objects.
*/
GCRY_SEXP
gcry_sexp_enum( GCRY_SEXP list, void **context, int mode )
{
return NULL;
#warning gcry_sexp_enum is not implemented
#if 0
NODE node;
if( mode )
return NULL; /* mode is reserved and must be 0 */
if( !list ) {
/* we are lucky that we can hold all information in the pointer
* value ;-) - so there is no need to release any memory */
*context = NULL;
return NULL;
}
if( !*context ) /* start enumeration */
node = list;
else {
node = *context;
node = node->next;
}
for( ; node; node = node->next ) {
*context = node; /* store our context */
if( node->type == ntLIST )
return node->u.list;
return node;
}
/* release resources and return nil */
return gcry_sexp_enum( NULL, context, mode );
#endif
}
/****************
* Extract the CAR of the given list
*/
GCRY_SEXP
gcry_sexp_car( GCRY_SEXP list )
{
const byte *p;
DATALEN n;
GCRY_SEXP newlist;
byte *d;
if ( !list || list->d[0] != ST_OPEN )
return new_empty_list ();
p = list->d;
memcpy ( &n, ++p, sizeof n ); p += sizeof n;
newlist = g10_xmalloc ( sizeof *newlist + n + 1 );
d = newlist->d;
memcpy ( d, p, n ); d += n;
if ( *p == ST_OPEN )
*d++ = ST_CLOSE;
*d++ = ST_STOP;
return newlist;
}
/****************
* Get data from the car. The returned value is valid as long as the list
* is not modified.
*/
const char *
gcry_sexp_car_data( GCRY_SEXP list, size_t *datalen )
{
byte *p = list->d;
DATALEN n;
if ( *p == ST_OPEN ) {
p += 1 + sizeof n;
}
if ( *p == ST_DATA ) {
memcpy ( &n, ++p, sizeof n );
*datalen = n;
return p + sizeof n;
}
return NULL;
}
/****************
* Get a MPI from the car
*/
GCRY_MPI
gcry_sexp_car_mpi( GCRY_SEXP list, int mpifmt )
{
byte *p = list->d;
DATALEN n;
if ( !mpifmt )
mpifmt = GCRYMPI_FMT_STD;
if ( *p == ST_OPEN ) {
p += 1 + sizeof n;
}
if ( *p == ST_DATA ) {
MPI a;
size_t nbytes;
memcpy ( &n, ++p, sizeof n );
p += sizeof n;
nbytes = n;
if( !gcry_mpi_scan( &a, mpifmt, p, &nbytes ) )
return a;
}
return NULL;
}
/****************
* Get the CDR
*/
GCRY_SEXP
gcry_sexp_cdr( GCRY_SEXP list )
{
const byte *head, *p;
DATALEN n;
GCRY_SEXP newlist;
byte *d;
if ( !list || list->d[0] != ST_OPEN )
return new_empty_list ();
p = list->d;
p++;
p += sizeof n; /* don't care about the length of the list */
if ( *p == ST_CLOSE )
return new_empty_list (); /* cdr of an empty list is an empty list */
/* skip over the first element of the list */
if ( *p == ST_STOP )
BUG (); /* oops */
memcpy ( &n, ++p, sizeof n ); p += sizeof n;
p += n;
/* save position and find the end of the list */
head = p;
while ( *p != ST_CLOSE ) {
if ( *p == ST_STOP )
BUG (); /* oops */
memcpy ( &n, ++p, sizeof n ); p += sizeof n;
p += n;
}
/* allocate enough space for the open, close and stop tag */
newlist = g10_xmalloc ( sizeof *newlist + 3 + sizeof(DATALEN)
+ ( p - head ) - 1 );
d = newlist->d;
/* and create the new list */
*d++ = ST_OPEN;
n = ( p - head );
memcpy ( d, &n, sizeof n ); d += sizeof n;
memcpy ( d, head, n ); d += n;
*d++ = ST_CLOSE;
*d++ = ST_STOP;
return newlist;
}
/****************
* Get data from the cdr assuming this is a pair
*/
const char *
gcry_sexp_cdr_data( GCRY_SEXP list, size_t *datalen )
{
byte *p = list->d;
DATALEN n;
if ( *p == ST_OPEN ) {
memcpy ( &n, ++p, sizeof n );
p += sizeof n;
/* skip over the first element */
if ( *p == ST_STOP )
BUG (); /* at least we expect an list end here */
memcpy ( &n, ++p, sizeof n );
p += sizeof n;
p += n; /* actually skip over the car */
/* we can only return stuff if the element is of type data */
if ( *p == ST_DATA ) {
memcpy ( &n, ++p, sizeof n );
p += sizeof n;
*datalen = n;
return p;
}
}
return NULL;
}
/****************
* cdr the mpi from the list or NULL if there is no MPI.
* This function tries to convert plain data to an MPI.
* Actually this funtion returns only the second item of the list
* and ignores any further arguments.
*/
GCRY_MPI
gcry_sexp_cdr_mpi( GCRY_SEXP list, int mpifmt )
{
byte *p = list->d;
DATALEN n;
if ( !mpifmt )
mpifmt = GCRYMPI_FMT_STD;
if ( *p == ST_OPEN ) {
memcpy ( &n, ++p, sizeof n );
p += sizeof n;
/* skip over the first element */
if ( *p == ST_STOP )
BUG (); /* at least we expect an list end here */
memcpy ( &n, ++p, sizeof n );
p += sizeof n;
p += n; /* actually skip over the car */
/* we can only return stuff if the element is of type data */
if ( *p == ST_DATA ) {
MPI a;
size_t nbytes;
memcpy ( &n, ++p, sizeof n );
p += sizeof n;
nbytes =n;
if( !gcry_mpi_scan( &a, mpifmt, p, &nbytes ) )
return a;
}
}
return NULL;
}
static int
hextobyte( const byte *s )
{
int c=0;
if( *s >= '0' && *s <= '9' )
c = 16 * (*s - '0');
else if( *s >= 'A' && *s <= 'F' )
c = 16 * (10 + *s - 'A');
else if( *s >= 'a' && *s <= 'f' ) {
c = 16 * (10 + *s - 'a');
}
s++;
if( *s >= '0' && *s <= '9' )
c += *s - '0';
else if( *s >= 'A' && *s <= 'F' )
c += 10 + *s - 'A';
else if( *s >= 'a' && *s <= 'f' ) {
c += 10 + *s - 'a';
}
return c;
}
/****************
* Scan the provided buffer and return the S expression in our internal
* format. Returns a newly allocated expression. If erroff is not NULL and
* a parsing error has occured, the offset into buffer will be returned.
* If ARG_PTR is not NULL, the function supports some printf like
* expressions.
* These are:
* %m - MPI
* %s - string (no autoswitch to secure allocation)
* %d - integer stored as string (no autoswitch to secure allocation)
* all other format elements are currently not defined and return an error.
* this includes the "%%" sequence becauce the percent sign is not an
* allowed character.
* FIXME: We should find a way to store the secure-MPIS not in the string
* but as reference to somewhere - this can help us to save huge amounts
* of secure memory. The problem is, taht if only one element is secure, all
* other elements are automagicaly copied to secure meory too, so the most
* common operation gcry_sexp_cdr_mpi() will always return a secure MPI
* regardless whether it is needed or not.
*/
static int
sexp_sscan( GCRY_SEXP *retsexp, size_t *erroff ,
const char *buffer, size_t length, va_list arg_ptr )
{
static const char tokenchars[] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789-./_:*+=";
const char *p;
size_t n;
const char *digptr=NULL;
const char *quoted=NULL;
const char *tokenp=NULL;
const char *hexfmt=NULL;
const char *base64=NULL;
const char *disphint=NULL;
const char *percent=NULL;
int hexcount=0;
int quoted_esc=0;
int datalen=0;
int first;
size_t dummy_erroff;
byte *head, *pos, *tail;
size_t allocated;
byte **fixups = NULL;
int max_fixups = 0;
int n_fixups = 0;
if( !erroff )
erroff = &dummy_erroff;
/* FIXME: replace all the returns by a jump to the leave label
* and invent better error codes. Make sure that everything is cleaned up*/
#define MAKE_SPACE(n) do {if ( pos + (n)+sizeof(DATALEN)+1 >= tail ) { \
GCRY_SEXP newsexp; \
byte *newhead; \
int i; \
allocated += 2*((n)+sizeof(DATALEN)+1); \
newsexp = g10_xrealloc ( *retsexp, \
sizeof *newsexp + allocated - 1 ); \
newhead = newsexp->d; \
pos = newhead + ( pos - head ); \
for ( i=0; i < n_fixups; i++ ) \
fixups[i] = newhead+(fixups[i]-head); \
head = newhead; \
*retsexp = newsexp; \
tail = head + allocated; \
} \
} while (0)
#define STORE_LEN(p,n) do { \
DATALEN ashort = (n); \
memcpy ( (p), &ashort, sizeof(ashort) ); \
(p) += sizeof (ashort); \
} while (0)
#define PUSH_FIXUP(p) do { \
if ( !fixups ) { \
max_fixups = 3; \
fixups = g10_xcalloc( max_fixups, \
sizeof *fixups ); \
n_fixups = 0; \
} \
if ( n_fixups >= max_fixups ) { \
max_fixups += 10; \
fixups = g10_xrealloc(fixups, max_fixups); \
} \
fixups[n_fixups++] = p; \
} while (0)
/* We assume that the internal representation takes less memory
* than the provided one. However, we add space for one extra datalen
* so that the code which does the ST_CLOSE can use MAKE_SPACE */
allocated = length + sizeof(DATALEN);
*retsexp = g10_xmalloc ( sizeof **retsexp + allocated - 1 );
head = pos = (*retsexp)->d;
tail = head + allocated - 1;
first = 0;
for(p=buffer,n=length; n; p++, n-- ) {
if( tokenp && !hexfmt ) {
if( strchr( tokenchars, *p ) )
continue;
datalen = p - tokenp;
MAKE_SPACE ( datalen );
*pos++ = ST_DATA;
STORE_LEN ( pos, datalen );
memcpy ( pos, tokenp, datalen );
pos += datalen;
tokenp = NULL;
}
if( quoted ) {
if( quoted_esc ) {
switch( *p ) {
case 'b': case 't': case 'v': case 'n': case 'f':
case 'r': case '"': case '\'': case '\\':
quoted_esc = 0;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7':
if( !(n > 2 && p[1] >= '0' && p[1] <= '7'
&& p[2] >= '0' && p[2] <= '7') ) {
*erroff = p - buffer;
return -6; /* invalid octal value */
}
p += 2; n -= 2;
quoted_esc = 0;
break;
case 'x':
if( !(n > 2 && isxdigit(p[1]) && isxdigit(p[2]) ) ) {
*erroff = p - buffer;
return -6; /* invalid hex value */
}
p += 2; n -= 2;
quoted_esc = 0;
break;
case '\r': /* ignore CR[,LF] */
if( n && p[1] == '\n' ) {
p++; n--;
}
quoted_esc = 0;
break;
case '\n': /* ignore LF[,CR] */
if( n && p[1] == '\r' ) {
p++; n--;
}
quoted_esc = 0;
break;
default:
*erroff = p - buffer;
return -6; /* invalid quoted string escape */
}
}
else if( *p == '\\' )
quoted_esc = 1;
else if( *p == '\"' ) {
/* fixme: add item */
quoted = NULL;
}
}
else if( hexfmt ) {
if( isxdigit( *p ) )
hexcount++;
else if( *p == '#' ) {
if( (hexcount & 1) ) {
*erroff = p - buffer;
return -12; /* odd number of hex digits */
}
datalen = hexcount/2;
MAKE_SPACE (datalen);
*pos++ = ST_DATA;
STORE_LEN (pos, datalen);
for( hexfmt++; hexfmt < p; hexfmt++ ) {
if( isspace( *hexfmt ) )
continue;
*pos++ = hextobyte( hexfmt );
hexfmt++;
}
hexfmt = NULL;
}
else if( !isspace( *p ) ) {
*erroff = p - buffer;
return -11; /* invalid hex character */
}
}
else if( base64 ) {
if( *p == '|' )
base64 = NULL;
}
else if( digptr ) {
if( isdigit(*p) )
;
else if( *p == ':' ) {
if( !head ) {
*erroff = 0;
return -4; /* not a list */
}
datalen = atoi( digptr ); /* fixme: check for overflow */
digptr = NULL;
if( datalen > n-1 ) {
*erroff = p - buffer;
return -2; /* buffer too short */
}
/* make a new list entry */
MAKE_SPACE (datalen);
*pos++ = ST_DATA;
STORE_LEN (pos, datalen);
memcpy (pos, p+1, datalen );
pos += datalen;
n -= datalen;
p += datalen;
}
else if( *p == '\"' ) {
digptr = NULL; /* we ignore the optional length */
quoted = p;
quoted_esc = 0;
}
else if( *p == '#' ) {
digptr = NULL; /* we ignore the optional length */
hexfmt = p;
hexcount = 0;
}
else if( *p == '|' ) {
digptr = NULL; /* we ignore the optional length */
base64 = p;
}
else {
*erroff = p - buffer;
return -1;
}
}
else if ( percent ) {
if ( *p == 'm' ) { /* insert an MPI */
GCRY_MPI m = va_arg (arg_ptr, GCRY_MPI);
size_t nm;
if ( gcry_mpi_print( GCRYMPI_FMT_STD, NULL, &nm, m ) )
BUG ();
if ( !g10_is_secure ( head )
&& gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE ) ) {
/* we have to switch to secure allocation and while we
* are already at it we check wether we have to increase
* the size */
GCRY_SEXP newsexp;
byte *newhead;
if ( pos + nm+sizeof(DATALEN)+1 >= tail ) {
allocated += nm+sizeof(DATALEN)+1;
}
newsexp = g10_xrealloc ( *retsexp,
sizeof *newsexp + allocated - 1 );
newhead = newsexp->d;
memcpy ( newhead, head, (pos - head) );
pos = newhead + ( pos - head );
g10_free ( head );
head = newhead;
*retsexp = newsexp;
tail = head + allocated;
}
MAKE_SPACE (nm);
*pos++ = ST_DATA;
STORE_LEN (pos, nm);
if ( gcry_mpi_print( GCRYMPI_FMT_STD, pos, &nm, m ) )
BUG ();
pos += nm;
}
else if ( *p == 's' ) { /* insert an string */
const char *astr = va_arg (arg_ptr, const char *);
size_t alen = strlen ( astr );
MAKE_SPACE (alen);
*pos++ = ST_DATA;
STORE_LEN (pos, alen);
memcpy ( pos, astr, alen );
}
else if ( *p == 'd' ) { /* insert an integer as string */
int aint = va_arg (arg_ptr, int);
size_t alen;
char buf[20];
sprintf ( buf, "%d", aint );
alen = strlen ( buf );
MAKE_SPACE (alen);
*pos++ = ST_DATA;
STORE_LEN (pos, alen);
memcpy ( pos, buf, alen );
pos += alen;
}
else {
*erroff = p - buffer;
return -1; /* invalid format specifier */
}
percent = NULL;
}
else if( *p == '(' ) {
if( disphint ) {
*erroff = p - buffer;
return -9; /* open display hint */
}
MAKE_SPACE (0);
*pos++ = ST_OPEN;
PUSH_FIXUP ( pos );
STORE_LEN ( pos, 0 ); /* reserve */
first = 1;
}
else if( *p == ')' ) { /* walk up */
byte *fixup;
if( disphint ) {
*erroff = p - buffer;
return -9; /* open display hint */
}
if( !n_fixups ) {
*erroff = 0;
return -4; /* no open list */
}
MAKE_SPACE (0);
fixup = fixups[--n_fixups];
*pos++ = ST_CLOSE;
STORE_LEN ( fixup, pos - fixup - sizeof(DATALEN) );
}
else if( *p == '\"' ) {
quoted = p;
quoted_esc = 0;
}
else if( *p == '#' ) {
hexfmt = p;
hexcount = 0;
}
else if( *p == '|' )
base64 = p;
else if( *p == '[' ) {
if( disphint ) {
*erroff = p - buffer;
return -8; /* nested display hints */
}
disphint = p;
}
else if( *p == ']' ) {
if( !disphint ) {
*erroff = p - buffer;
return -9; /* unmatched display hint close */
}
disphint = NULL;
}
else if( isdigit(*p) ) {
if( *p == '0' ) { /* a length may not begin with zero */
*erroff = p - buffer;
return -7;
}
digptr = p;
}
else if( strchr( tokenchars, *p ) )
tokenp = p;
else if( isspace(*p) )
;
else if( *p == '{' ) {
/* fixme: handle rescanning:
* we can do this by saving our current state
* and start over at p+1 -- Hmmm. At this point here
* we are in a well defined state, so we don't need to save
* it. Great.
*/
*erroff = p - buffer;
return -10; /* unexpected reserved punctuation */
}
else if( strchr( "&\\", *p ) ) { /*reserved punctuation*/
*erroff = p - buffer;
return -10; /* unexpected reserved punctuation */
}
else if( arg_ptr && *p == '%' ) {
percent = p;
}
else { /* bad or unavailable*/
*erroff = p - buffer;
return -5;
}
}
MAKE_SPACE (0);
*pos++ = ST_STOP;
leave:
g10_free ( fixups );
return 0;
#undef MAKE_SPACE
#undef STORE_LEN
#undef PUISH_FIXUP
}
int
gcry_sexp_sscan( GCRY_SEXP *retsexp, size_t *erroff,
const char *buffer, size_t length )
{
return sexp_sscan( retsexp, erroff, buffer, length, NULL );
}
int
gcry_sexp_build( GCRY_SEXP *retsexp, size_t *erroff, const char *format, ... )
{
int rc;
va_list arg_ptr ;
va_start( arg_ptr, format ) ;
rc = sexp_sscan( retsexp, erroff, format, strlen(format), arg_ptr );
va_end(arg_ptr);
return rc;
}
/****************
* Print SEXP to buffer using the MODE. Returns the length of the
* SEXP in buffer or 0 if the buffer is too short (We have at least an
* empty list consisting of 2 bytes). If a buffer of NULL is provided,
* the required length is returned.
*/
size_t
gcry_sexp_sprint( GCRY_SEXP sexp, int mode, char *buffer, size_t maxlength )
{
return 0;
}
#if 0
/***********************************************************/
const char *
strusage( int level )
{
return "?";
}
#if 0
static int
sexp_to_pk( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo)
{
GCRY_SEXP list, l2;
const char *name;
const char *s;
size_t n;
int i, idx;
int algo;
const char *elems1, *elems2;
GCRY_MPI *array;
static struct { const char* name; int algo;
const char* common_elements;
const char* public_elements;
const char* secret_elements;
} algos[] = {
{ "dsa" , PUBKEY_ALGO_DSA , "pqgy", "", "x" },
{ "rsa" , PUBKEY_ALGO_RSA , "ne", "", "dpqu" },
{ "openpgp-dsa" , PUBKEY_ALGO_DSA , "pqgy", "", "x" },
{ "openpgp-rsa" , PUBKEY_ALGO_RSA , "pqgy", "", "x" },
{ "openpgp-elg" , PUBKEY_ALGO_ELGAMAL_E , "pgy", "", "x" },
{ "openpgp-elg-sig", PUBKEY_ALGO_ELGAMAL , "pgy", "", "x" },
{ NULL }};
/* check that the first element is valid */
list = gcry_sexp_find_token( sexp, want_private? "private-key"
:"public-key", 0 );
if( !list )
return -1; /* Does not contain a public- or private-key object */
list = gcry_sexp_cdr( list );
if( !list )
return -2; /* no cdr for the key object */
name = gcry_sexp_car_data( list, &n );
if( !name )
return -3; /* invalid structure of object */
fprintf(stderr, "algorithm name: `%.*s'\n", (int)n, name );
for(i=0; (s=algos[i].name); i++ ) {
if( strlen(s) == n && !memcmp( s, name, n ) )
break;
}
if( !s )
return -4; /* unknown algorithm */
algo = algos[i].algo;
elems1 = algos[i].common_elements;
elems2 = want_private? algos[i].secret_elements : algos[i].public_elements;
array = g10_xcalloc( (strlen(elems1)+strlen(elems2)+1) , sizeof *array );
idx = 0;
for(s=elems1; *s; s++, idx++ ) {
l2 = gcry_sexp_find_token( list, s, 1 );
if( !l2 ) {
g10_free( array );
return -5; /* required parameter not found */
}
array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
if( !array[idx] ) {
g10_free( array );
return -6; /* required parameter is invalid */
}
}
for(s=elems2; *s; s++, idx++ ) {
l2 = gcry_sexp_find_token( list, s, 1 );
if( !l2 ) {
g10_free( array );
return -5; /* required parameter not found */
}
/* FIXME: put the MPI in secure memory when needed */
array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
if( !array[idx] ) {
g10_free( array );
return -6; /* required parameter is invalid */
}
}
*retarray = array;
*retalgo = algo;
return 0;
}
#endif
int
main(int argc, char **argv)
{
char buffer[5000];
size_t erroff;
int rc, n;
FILE *fp;
GCRY_SEXP s_pk, s_dsa, s_p, s_q, s_g, s_y, sexp;
#if 1
fp = stdin;
n = fread(buffer, 1, 5000, fp );
rc = gcry_sexp_sscan( &sexp, buffer, n, &erroff );
if( rc ) {
fprintf(stderr, "parse error %d at offset %u\n", rc, erroff );
exit(1);
}
fputs("We have this S-Exp:\n",stderr);
dump_sexp( sexp );
#else
s_pk = SEXP_NEW( "public-key", 10 );
fputs("pk:\n",stderr);dump_sexp( s_pk );
s_dsa = SEXP_NEW( "dsa", 3 );
s_p = SEXP_CONS( SEXP_NEW( "p", 1 ), SEXP_NEW( "PPPPPP", 6 ) );
fputs("p:\n",stderr);dump_sexp( s_p );
s_y = SEXP_CONS( SEXP_NEW( "y", 1 ), SEXP_NEW( "YYYYYYYY", 8 ) );
fputs("y:\n",stderr);dump_sexp( s_y );
s_q = gcry_sexp_new_name_data( "q", "QQQ", 3 );
fputs("q:\n",stderr);dump_sexp( s_q );
s_g = gcry_sexp_new_name_mpi( "g" , gcry_mpi_set_ui(NULL, 42) );
fputs("g:\n",stderr);dump_sexp( s_g );
sexp = SEXP_CONS( s_pk, gcry_sexp_vlist( s_dsa,
s_y,
s_p,
s_q,
s_g,
NULL ));
fputs("Here is what we have:\n",stderr);
dump_sexp( sexp );
#endif
/* now find something */
if( argc > 1 )
{
GCRY_SEXP s1;
s1 = gcry_sexp_find_token( sexp, argv[1], strlen(argv[1]) );
if( !s1 )
{
fprintf(stderr, "didn't found `%s'\n", argv[1] );
}
else
{
fprintf(stderr, "found `%s':\n", argv[1] );
dump_sexp( s1 );
}
#if 0
{ int i,rc, algo;
GCRY_MPI *array;
rc = sexp_to_pk( s1, 0, &array, &algo);
if( rc )
fprintf(stderr, "sexp_to_pk failed: rc=%d\n", rc );
else {
for(i=0; array[i]; i++ ) {
fprintf(stderr, "MPI[%d]: ", i);
dump_mpi( array[i] );
fprintf(stderr, "\n");
}
}
}
#endif
if( argc > 2 ) /* get the MPI out of the list */
#if 0
{
GCRY_SEXP s2;
const char *p;
size_t n;
p = gcry_sexp_car_data( s1, &n );
if( !p ) {
fputs("no CAR\n", stderr );
exit(1);
}
fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
p = gcry_sexp_cdr_data( s1, &n );
if( !p ) {
s2 = gcry_sexp_cdr( s1 );
if( !s2 ) {
fputs("no CDR at all\n", stderr );
exit(1);
}
p = gcry_sexp_car_data( s2, &n );
}
if( !p ) {
fputs("no CDR data\n", stderr );
exit(1);
}
fprintf(stderr, "CDR=`%.*s'\n", (int)n, p );
}
#elif 1
{
GCRY_SEXP s2;
MPI a;
const char *p;
size_t n;
fprintf(stderr,"*********************************\n");
p = gcry_sexp_car_data( s1, &n );
if( !p ) {
fputs("no CAR\n", stderr );
exit(1);
}
fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
s2 = gcry_sexp_cdr( s1 );
if( !s2 ) {
fputs("no CDR\n", stderr );
exit(1);
}
p = gcry_sexp_car_data( s2, &n );
if( !p ) {
fputs("no data at CAR\n", stderr );
exit(1);
}
fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
s2 = gcry_sexp_find_token( s1, argv[2], strlen(argv[2]) );
if( !s2 )
{
fprintf(stderr, "didn't found `%s'\n", argv[2] );
exit(1);
}
p = gcry_sexp_car_data( s2, &n );
if( !p ) {
fputs("no CAR\n", stderr );
exit(1);
}
fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
a = gcry_sexp_cdr_mpi( s2, GCRYMPI_FMT_USG );
if( a ) {
fprintf(stderr, "MPI: ");
dump_mpi( a );
fprintf(stderr, "\n");
}
else
fprintf(stderr, "cannot cdr a mpi\n" );
}
#else
{ /* print all MPIs */
void *ctx = NULL;
GCRY_SEXP s2;
MPI a;
while( (s2 = gcry_sexp_enum( s1, &ctx, 0 )) )
{
const char *car_d;
size_t car_n;
car_d = gcry_sexp_car_data( s2, &car_n );
if( car_d ) {
fprintf(stderr, "CAR: %.*s=", (int)car_n, car_d );
a = gcry_sexp_cdr_mpi( s2, GCRYMPI_FMT_USG );
dump_mpi( a );
fprintf(stderr, "\n");
}
else
fprintf(stderr, "no CAR\n");
}
}
#endif
}
return 0;
}
#endif

File Metadata

Mime Type
text/x-c
Expires
Mon, Dec 23, 5:29 PM (2 h, 43 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
78/d6/8c345ebff9414ed6885b581ee20c

Event Timeline