summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cipher/ChangeLog6
-rw-r--r--cipher/pubkey.c333
-rw-r--r--mpi/ChangeLog4
-rw-r--r--mpi/config.links10
-rw-r--r--src/ChangeLog9
-rw-r--r--src/Makefile.am7
-rw-r--r--src/gcrypt.h17
-rw-r--r--src/sexp.c825
-rw-r--r--src/testapi.c60
9 files changed, 798 insertions, 473 deletions
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index 72129a89..f13c0fb9 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,9 @@
+Tue Jul 25 17:44:15 CEST 2000 Werner Koch <wk@openit.de>
+
+ * pubkey.c (exp_to_key,sexp_to_sig,sexp_to_enc,gcry_pk_encrypt,
+ gcry_pk_decrypt,gcry_pk_sign,gcry_pk_genkey): Changed to work with
+ the new S-Exp interface.
+
Mon Jul 17 16:35:47 CEST 2000 Werner Koch <wk@>
* random.c (gather_faked): Replaced make_timestamp by time(2) again.
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index b139720d..7ef6f18b 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -701,25 +701,38 @@ sexp_to_key( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo)
:"public-key", 0 );
if( !list )
return GCRYERR_INV_OBJ; /* Does not contain a public- or private-key object */
- list = gcry_sexp_cdr( list );
+ l2 = gcry_sexp_cdr( list );
+ gcry_sexp_release ( list );
+ list = l2;
if( !list )
return GCRYERR_NO_OBJ; /* no cdr for the key object */
+ l2 = gcry_sexp_car( list );
+ gcry_sexp_release ( list );
+ list = l2;
+ if( !list )
+ return GCRYERR_NO_OBJ; /* no car for the key object */
name = gcry_sexp_car_data( list, &n );
- if( !name )
+ if( !name ) {
+ gcry_sexp_release ( list );
return GCRYERR_INV_OBJ; /* invalid structure of object */
+ }
for(i=0; (s=algo_info_table[i].name); i++ ) {
if( strlen(s) == n && !memcmp( s, name, n ) )
break;
}
- if( !s )
+ if( !s ) {
+ gcry_sexp_release ( list );
return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
+ }
algo = algo_info_table[i].algo;
elems1 = algo_info_table[i].common_elements;
elems2 = want_private? algo_info_table[i].secret_elements
: algo_info_table[i].public_elements;
array = g10_calloc( strlen(elems1)+strlen(elems2)+1, sizeof *array );
- if( !array )
+ if( !array ) {
+ gcry_sexp_release ( list );
return GCRYERR_NO_MEM;
+ }
idx = 0;
for(s=elems1; *s; s++, idx++ ) {
@@ -728,13 +741,16 @@ sexp_to_key( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo)
for(i=0; i<idx; i++)
g10_free( array[i] );
g10_free( array );
+ gcry_sexp_release ( list );
return GCRYERR_NO_OBJ; /* required parameter not found */
}
array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
+ gcry_sexp_release ( l2 );
if( !array[idx] ) {
for(i=0; i<idx; i++)
g10_free( array[i] );
g10_free( array );
+ gcry_sexp_release ( list );
return GCRYERR_INV_OBJ; /* required parameter is invalid */
}
}
@@ -744,18 +760,21 @@ sexp_to_key( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo)
for(i=0; i<idx; i++)
g10_free( array[i] );
g10_free( array );
+ gcry_sexp_release ( list );
return GCRYERR_NO_OBJ; /* required parameter not found */
}
- /* FIXME: put the MPI in secure memory when needed */
array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
+ gcry_sexp_release ( l2 );
if( !array[idx] ) {
for(i=0; i<idx; i++)
g10_free( array[i] );
g10_free( array );
+ gcry_sexp_release ( list );
return GCRYERR_INV_OBJ; /* required parameter is invalid */
}
}
+ gcry_sexp_release ( list );
*retarray = array;
*retalgo = algo;
@@ -778,38 +797,55 @@ sexp_to_sig( GCRY_SEXP sexp, MPI **retarray, int *retalgo)
list = gcry_sexp_find_token( sexp, "sig-val" , 0 );
if( !list )
return GCRYERR_INV_OBJ; /* Does not contain a signature value object */
- list = gcry_sexp_cdr( list );
+ l2 = gcry_sexp_cdr( list );
+ gcry_sexp_release ( list );
+ list = l2;
if( !list )
return GCRYERR_NO_OBJ; /* no cdr for the sig object */
+ l2 = gcry_sexp_car( list );
+ gcry_sexp_release ( list );
+ list = l2;
+ if( !list )
+ return GCRYERR_NO_OBJ; /* no car for the key object */
name = gcry_sexp_car_data( list, &n );
- if( !name )
+ if( !name ) {
+ gcry_sexp_release ( list );
return GCRYERR_INV_OBJ; /* invalid structure of object */
+ }
for(i=0; (s=sig_info_table[i].name); i++ ) {
if( strlen(s) == n && !memcmp( s, name, n ) )
break;
}
- if( !s )
+ if( !s ) {
+ gcry_sexp_release ( list );
return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
+ }
algo = sig_info_table[i].algo;
elems = sig_info_table[i].elements;
array = g10_calloc( (strlen(elems)+1) , sizeof *array );
- if( !array )
+ if( !array ) {
+ gcry_sexp_release ( list );
return GCRYERR_NO_MEM;
+ }
idx = 0;
for(s=elems; *s; s++, idx++ ) {
l2 = gcry_sexp_find_token( list, s, 1 );
if( !l2 ) {
g10_free( array );
+ gcry_sexp_release ( list );
return GCRYERR_NO_OBJ; /* required parameter not found */
}
array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
+ gcry_sexp_release ( l2 );
if( !array[idx] ) {
g10_free( array );
+ gcry_sexp_release ( list );
return GCRYERR_INV_OBJ; /* required parameter is invalid */
}
}
+ gcry_sexp_release ( list );
*retarray = array;
*retalgo = algo;
@@ -837,38 +873,53 @@ sexp_to_enc( GCRY_SEXP sexp, MPI **retarray, int *retalgo)
list = gcry_sexp_find_token( sexp, "enc-val" , 0 );
if( !list )
return GCRYERR_INV_OBJ; /* Does not contain a encrypted value object */
- list = gcry_sexp_cdr( list );
- if( !list )
+ l2 = gcry_sexp_cdr( list );
+ gcry_sexp_release ( list );
+ list = l2;
+ if( !list ) {
+ gcry_sexp_release ( list );
return GCRYERR_NO_OBJ; /* no cdr for the data object */
+ }
name = gcry_sexp_car_data( list, &n );
- if( !name )
+ if( !name ) {
+ gcry_sexp_release ( list );
return GCRYERR_INV_OBJ; /* invalid structure of object */
+ }
for(i=0; (s=enc_info_table[i].name); i++ ) {
if( strlen(s) == n && !memcmp( s, name, n ) )
break;
}
- if( !s )
+ if( !s ) {
+ gcry_sexp_release ( list );
return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
+ }
+
algo = enc_info_table[i].algo;
elems = enc_info_table[i].elements;
array = g10_calloc( (strlen(elems)+1) , sizeof *array );
- if( !array )
+ if( !array ) {
+ gcry_sexp_release ( list );
return GCRYERR_NO_MEM;
+ }
idx = 0;
for(s=elems; *s; s++, idx++ ) {
l2 = gcry_sexp_find_token( list, s, 1 );
if( !l2 ) {
g10_free( array );
+ gcry_sexp_release ( list );
return GCRYERR_NO_OBJ; /* required parameter not found */
}
array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
+ gcry_sexp_release ( l2 );
if( !array[idx] ) {
g10_free( array );
+ gcry_sexp_release ( list );
return GCRYERR_INV_OBJ; /* required parameter is invalid */
}
}
+ gcry_sexp_release ( list );
*retarray = array;
*retalgo = algo;
@@ -900,7 +951,6 @@ gcry_pk_encrypt( GCRY_SEXP *r_ciph, GCRY_SEXP s_data, GCRY_SEXP s_pkey )
{
MPI *pkey, data, *ciph;
const char *algo_name, *algo_elems;
- GCRY_SEXP *s_elems;
int i, rc, algo;
/* get the key */
@@ -933,26 +983,61 @@ gcry_pk_encrypt( GCRY_SEXP *r_ciph, GCRY_SEXP s_data, GCRY_SEXP s_pkey )
release_mpi_array( pkey );
mpi_free( data );
if( rc ) {
+ release_mpi_array( ciph );
g10_free( ciph );
return rc;
}
/* We did it. Now build the return list */
- s_elems = g10_xcalloc( (strlen(algo_elems)+2), sizeof *s_elems );
- s_elems[0] = SEXP_NEW( algo_name, 0 );
- for(i=0; algo_elems[i]; i++ ) {
- char tmp[2];
- tmp[0] = algo_elems[i];
- tmp[1] = 0;
- s_elems[i+1] = gcry_sexp_new_name_mpi( tmp, ciph[i] );
+ {
+ char *string, *p;
+ size_t nelem, needed= strlen(algo_name) + 20;
+
+ /* count elements, so that we can allocate enough space */
+ for(nelem=0; algo_elems[nelem]; nelem++ )
+ needed += 10; /* 6 + a safety margin */
+ /* build the string */
+ string = p = g10_xmalloc ( needed );
+ p = stpcpy ( p, "(enc-val(" );
+ p = stpcpy ( p, algo_name );
+ for(i=0; algo_elems[i]; i++ ) {
+ *p++ = '(';
+ *p++ = algo_elems[i];
+ p = stpcpy ( p, "%m)" );
+ }
+ strcpy ( p, "))" );
+ /* and now the ugly part: we don't have a function to
+ * pass an array to a format string, so we have to do it this way :-(
+ */
+ switch ( nelem ) {
+ case 1: rc = gcry_sexp_build ( r_ciph, NULL, string,
+ ciph[0]
+ ); break;
+ case 2: rc = gcry_sexp_build ( r_ciph, NULL, string,
+ ciph[0], ciph[1]
+ ); break;
+ case 3: rc = gcry_sexp_build ( r_ciph, NULL, string,
+ ciph[0], ciph[1], ciph[2]
+ ); break;
+ case 4: rc = gcry_sexp_build ( r_ciph, NULL, string,
+ ciph[0], ciph[1], ciph[2], ciph[3]
+ ); break;
+ case 5: rc = gcry_sexp_build ( r_ciph, NULL, string,
+ ciph[0], ciph[1], ciph[2], ciph[3], ciph[4]
+ ); break;
+ case 6: rc = gcry_sexp_build ( r_ciph, NULL, string,
+ ciph[0], ciph[1], ciph[2], ciph[3], ciph[4], ciph[5]
+ ); break;
+ default: BUG ();
+ }
+ if ( rc )
+ BUG ();
+ g10_free ( string );
}
release_mpi_array( ciph );
g10_free( ciph );
- *r_ciph = SEXP_CONS( SEXP_NEW( "enc-val", 0 ),
- gcry_sexp_alist( s_elems ) );
- g10_free( s_elems );
return 0;
}
@@ -1003,7 +1088,9 @@ gcry_pk_decrypt( GCRY_SEXP *r_plain, GCRY_SEXP s_data, GCRY_SEXP s_skey )
return -1; /* fixme: add real errornumber - decryption failed */
}
- *r_plain = gcry_sexp_new_mpi( plain );
+ if ( gcry_sexp_build( r_plain, NULL, "%m", plain ) )
+ BUG ();
+
mpi_free( plain );
release_mpi_array( data );
release_mpi_array( skey );
@@ -1042,7 +1129,6 @@ gcry_pk_sign( GCRY_SEXP *r_sig, GCRY_SEXP s_hash, GCRY_SEXP s_skey )
MPI *result;
int i, algo, rc;
const char *algo_name, *algo_elems;
- GCRY_SEXP *s_elems;
rc = sexp_to_key( s_skey, 1, &skey, &algo );
if( rc )
@@ -1074,21 +1160,54 @@ gcry_pk_sign( GCRY_SEXP *r_sig, GCRY_SEXP s_hash, GCRY_SEXP s_skey )
return rc;
}
- s_elems = g10_xcalloc( (strlen(algo_elems)+2), sizeof *s_elems );
- s_elems[0] = SEXP_NEW( algo_name, 0 );
- for(i=0; algo_elems[i]; i++ ) {
- char tmp[2];
- tmp[0] = algo_elems[i];
- tmp[1] = 0;
- s_elems[i+1] = gcry_sexp_new_name_mpi( tmp, result[i] );
+ {
+ char *string, *p;
+ size_t nelem, needed= strlen(algo_name) + 20;
+
+ /* count elements, so that we can allocate enough space */
+ for(nelem=0; algo_elems[nelem]; nelem++ )
+ needed += 10; /* 6 + a safety margin */
+ /* build the string */
+ string = p = g10_xmalloc ( needed );
+ p = stpcpy ( p, "(sig-val(" );
+ p = stpcpy ( p, algo_name );
+ for(i=0; algo_elems[i]; i++ ) {
+ *p++ = '(';
+ *p++ = algo_elems[i];
+ p = stpcpy ( p, "%m)" );
+ }
+ strcpy ( p, "))" );
+ /* and now the ugly part: we don't have a function to
+ * pass an array to a format string, so we have to do it this way :-(
+ */
+ switch ( nelem ) {
+ case 1: rc = gcry_sexp_build ( r_sig, NULL, string,
+ result[0]
+ ); break;
+ case 2: rc = gcry_sexp_build ( r_sig, NULL, string,
+ result[0], result[1]
+ ); break;
+ case 3: rc = gcry_sexp_build ( r_sig, NULL, string,
+ result[0], result[1], result[2]
+ ); break;
+ case 4: rc = gcry_sexp_build ( r_sig, NULL, string,
+ result[0], result[1], result[2], result[3]
+ ); break;
+ case 5: rc = gcry_sexp_build ( r_sig, NULL, string,
+ result[0], result[1], result[2], result[3], result[4]
+ ); break;
+ case 6: rc = gcry_sexp_build ( r_sig, NULL, string,
+ result[0], result[1], result[2], result[3], result[4], result[5]
+ ); break;
+ default: BUG ();
+ }
+ if ( rc )
+ BUG ();
+ g10_free ( string );
}
release_mpi_array( result );
g10_free( result );
- *r_sig = SEXP_CONS( SEXP_NEW( "sig-val", 0 ),
- gcry_sexp_alist( s_elems ) );
-
- g10_free( s_elems );
return 0;
}
@@ -1199,7 +1318,7 @@ gcry_pk_testkey( GCRY_SEXP s_key )
int
gcry_pk_genkey( GCRY_SEXP *r_key, GCRY_SEXP s_parms )
{
- GCRY_SEXP list, l2, *s_elems, pub_list, sec_list, misc_list;
+ GCRY_SEXP list, l2;
const char *name;
const char *s;
size_t n;
@@ -1213,18 +1332,24 @@ gcry_pk_genkey( GCRY_SEXP *r_key, GCRY_SEXP s_parms )
list = gcry_sexp_find_token( s_parms, "genkey", 0 );
if( !list )
return GCRYERR_INV_OBJ; /* Does not contain genkey data */
- list = gcry_sexp_cdr( list );
+ l2 = gcry_sexp_cdr( list );
+ gcry_sexp_release ( list );
+ list = l2;
if( !list )
return GCRYERR_NO_OBJ; /* no cdr for the genkey */
name = gcry_sexp_car_data( list, &n );
- if( !name )
+ if( !name ) {
+ gcry_sexp_release ( list );
return GCRYERR_INV_OBJ; /* algo string missing */
+ }
for(i=0; (s=algo_info_table[i].name); i++ ) {
if( strlen(s) == n && !memcmp( s, name, n ) )
break;
}
- if( !s )
+ if( !s ) {
+ gcry_sexp_release ( list );
return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
+ }
algo = algo_info_table[i].algo;
algo_name = algo_info_table[i].name;
@@ -1234,11 +1359,15 @@ gcry_pk_genkey( GCRY_SEXP *r_key, GCRY_SEXP s_parms )
strcat( sec_elems, algo_info_table[i].secret_elements );
l2 = gcry_sexp_find_token( list, "nbits", 0 );
- if( !l2 )
+ gcry_sexp_release ( list );
+ list = l2;
+ if( !list )
return GCRYERR_NO_OBJ; /* no nbits aparemter */
- name = gcry_sexp_cdr_data( l2, &n );
- if( !name )
+ name = gcry_sexp_cdr_data( list, &n );
+ if( !name ) {
+ gcry_sexp_release ( list );
return GCRYERR_INV_OBJ; /* nbits without a cdr */
+ }
{
char *p = g10_xmalloc(n+1);
memcpy(p, name, n );
@@ -1246,56 +1375,84 @@ gcry_pk_genkey( GCRY_SEXP *r_key, GCRY_SEXP s_parms )
nbits = (unsigned int)strtol( p, NULL, 0 );
g10_free( p );
}
+ gcry_sexp_release ( list );
rc = pubkey_generate( algo, nbits, skey, &factors );
if( rc ) {
return rc;
}
- /* build the public key list */
- s_elems = g10_xcalloc( (strlen(pub_elems)+2), sizeof *s_elems );
- s_elems[0] = SEXP_NEW( algo_name, 0 );
- for(i=0; pub_elems[i]; i++ ) {
- char tmp[2];
- tmp[0] = pub_elems[i];
- tmp[1] = 0;
- s_elems[i+1] = gcry_sexp_new_name_mpi( tmp, skey[i] );
- }
- pub_list = SEXP_CONS( SEXP_NEW( "public-key", 0 ),
- gcry_sexp_alist( s_elems ) );
- g10_free( s_elems );
-
- /* build the secret key list */
- s_elems = g10_xcalloc( (strlen(sec_elems)+2), sizeof *s_elems );
- s_elems[0] = SEXP_NEW( algo_name, 0 );
- for(i=0; sec_elems[i]; i++ ) {
- char tmp[2];
- tmp[0] = sec_elems[i];
- tmp[1] = 0;
- s_elems[i+1] = gcry_sexp_new_name_mpi( tmp, skey[i] );
- }
- sec_list = SEXP_CONS( SEXP_NEW( "private-key", 0 ),
- gcry_sexp_alist( s_elems ) );
- g10_free( s_elems );
-
- /* build the list of factors */
- for(n=0; factors[n]; n++ )
- ;
- s_elems = g10_xcalloc( n+2, sizeof *s_elems );
- s_elems[0] = SEXP_NEW( "pm1-factors", 0 );
- for(i=0; factors[i]; i++ ) {
- s_elems[i+1] = gcry_sexp_new_mpi( factors[i] );
+ {
+ char *string, *p;
+ size_t nelem=0, needed=0;
+ GCRY_MPI mpis[30];
+
+
+ /* count elements, so that we can allocate enough space */
+ for(i=0; pub_elems[i]; i++, nelem++ )
+ needed += 10; /* 6 + a safety margin */
+ for(i=0; sec_elems[i]; i++, nelem++ )
+ needed += 10; /* 6 + a safety margin */
+ for(i=0; factors[i]; i++, nelem++ )
+ needed += 10; /* 6 + a safety margin */
+ needed += 2* strlen(algo_name) + 300;
+ if ( nelem > DIM(mpis) )
+ BUG ();
+
+ /* build the string */
+ nelem = 0;
+ string = p = g10_xmalloc ( needed );
+ p = stpcpy ( p, "(key-data(" );
+
+ p = stpcpy ( p, "(public-key(" );
+ p = stpcpy ( p, algo_name );
+ for(i=0; pub_elems[i]; i++ ) {
+ *p++ = '(';
+ *p++ = pub_elems[i];
+ p = stpcpy ( p, "%m)" );
+ mpis[nelem++] = skey[i];
+ }
+ strcpy ( p, "))" );
+
+ p = stpcpy ( p, "(private-key(" );
+ p = stpcpy ( p, algo_name );
+ for(i=0; sec_elems[i]; i++ ) {
+ *p++ = '(';
+ *p++ = sec_elems[i];
+ p = stpcpy ( p, "%m)" );
+ mpis[nelem++] = skey[i];
+ }
+ strcpy ( p, "))" );
+
+ p = stpcpy ( p, "(misc-key-info(pm1-factors" );
+ for(i=0; factors[i]; i++ ) {
+ p = stpcpy ( p, "%m" );
+ mpis[nelem++] = factors[i];
+ }
+ strcpy ( p, "))" );
+
+ while ( nelem < DIM(mpis) )
+ mpis[nelem++] = NULL;
+
+ /* and now the ugly part: we don't have a function to
+ * pass an array to a format string, so we have just pass everything
+ * we have. which normally should be no problem as only those
+ * with a corresponding %m are used
+ */
+ if ( gcry_sexp_build ( r_key, NULL, string,
+ mpis[0], mpis[1], mpis[2], mpis[3], mpis[4], mpis[5],
+ mpis[6], mpis[7], mpis[8], mpis[9], mpis[10], mpis[11],
+ mpis[12], mpis[13], mpis[14], mpis[15], mpis[16], mpis[17],
+ mpis[18], mpis[19], mpis[20], mpis[21], mpis[22], mpis[23],
+ mpis[24], mpis[25], mpis[26], mpis[27], mpis[28], mpis[29]
+ ) )
+ BUG ();
+ assert ( DIM(mpis) == 29 );
+ g10_free ( string );
}
- misc_list = SEXP_CONS( SEXP_NEW( "misc-key-info", 0 ),
- gcry_sexp_alist( s_elems ) );
- g10_free( s_elems );
-
- /* and put all together */
- *r_key = gcry_sexp_vlist( SEXP_NEW( "key-data", 0 ),
- pub_list, sec_list, misc_list, NULL );
- gcry_sexp_release( pub_list );
- gcry_sexp_release( sec_list );
- gcry_sexp_release( misc_list );
+ release_mpi_array ( skey );
+ release_mpi_array ( factors );
+
return 0;
}
diff --git a/mpi/ChangeLog b/mpi/ChangeLog
index 7119d1e2..6bdeaf25 100644
--- a/mpi/ChangeLog
+++ b/mpi/ChangeLog
@@ -1,3 +1,7 @@
+Tue Jul 25 17:44:15 CEST 2000 Werner Koch <wk@openit.de>
+
+ * config.links: Support for powerpc--netbsd by Gabriel Rosenkoetter.
+
Mon Jul 17 16:35:47 CEST 2000 Werner Koch <wk@>
* power/: Add all files from GMP for this CPU. Converted comments to
diff --git a/mpi/config.links b/mpi/config.links
index 6a2cbfb5..6f6b276d 100644
--- a/mpi/config.links
+++ b/mpi/config.links
@@ -178,6 +178,16 @@ case "${target}" in
cat $srcdir/mpi/powerpc32/syntax.h >>./mpi/asm-syntax.h
path="powerpc32"
;;
+
+ powerpc*-*-netbsd*)
+ echo '/* configured NetBSD on powerpc */' >>./mpi/asm-syntax.h
+ echo '#define ELF_SYNTAX' >>./mpi/asm-syntax.h
+ cat $srcdir/mpi/powerpc32/syntax.h >>./mpi/asm-syntax.h
+ mpi_sflags="-Wa,-mppc"
+ path="powerpc32"
+ ;;
+
+
rs6000-*-aix[456789]* | \
rs6000-*-aix3.2.[456789])
mpi_sflags="-Wa,-mpwr"
diff --git a/src/ChangeLog b/src/ChangeLog
index 83d1517c..e0818eb2 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,12 @@
+Tue Jul 25 17:44:15 CEST 2000 Werner Koch <wk@openit.de>
+
+ * sexp.c: Major rewrite.
+ (gcry_sexp_sscan): Reordered arguments. Moved functionality to ..
+ (sexp_sscan): .. this.
+ (gcry_sexp_build): New.
+ (gcry_sexp_new_name_mpi, gcry_sexp_new_name_data, gcry_sexp_new_data,
+ gcry_sexp_new_mpi): Removed.
+
Fri Jul 14 19:38:23 CEST 2000 Werner Koch <wk@>
* gcrypt.h (gcry_md_start_debug, gcry_md_stop_debug): New.
diff --git a/src/Makefile.am b/src/Makefile.am
index 359bc1cf..fd1182c9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -12,15 +12,14 @@ bin_SCRIPTS = gcrypt-config
m4datadir = $(datadir)/aclocal
m4data_DATA = gcrypt.m4
-noinst_PROGRAMS = testapi sexp
-sexp_SOURCES = sexp.c
-sexp_LDADD = libgcrypt.la
+noinst_PROGRAMS = testapi
testapi_SOURCES = testapi.c
testapi_LDADD = libgcrypt.la
include_HEADERS = gcrypt.h
-libgcrypt_la_LDFLAGS = -version-info 0:0:0 -export-symbols libgcrypt.sym
+# libgcrypt_la_LDFLAGS = -version-info 0:0:0 -export-symbols libgcrypt.sym
+libgcrypt_la_LDFLAGS = -version-info 0:0:0
libgcrypt_la_SOURCES = g10lib.h \
mpi.h \
cipher.h \
diff --git a/src/gcrypt.h b/src/gcrypt.h
index aaeb95b1..a362ec25 100644
--- a/src/gcrypt.h
+++ b/src/gcrypt.h
@@ -35,7 +35,7 @@ extern "C" {
* header matches the installed library.
* Note: Do not edit the next line as configure may fix the string here.
*/
-#define GCRYPT_VERSION "1.1.0a"
+#define GCRYPT_VERSION "1.1.0b"
#ifndef HAVE_BYTE_TYPEDEF
@@ -152,11 +152,6 @@ enum gcry_sexp_format {
};
-GCRY_SEXP gcry_sexp_new_data( const char *buffer, size_t length );
-GCRY_SEXP gcry_sexp_new_mpi( GCRY_MPI mpi );
-GCRY_SEXP gcry_sexp_new_name_data( const char *name,
- const char *buffer, size_t length );
-GCRY_SEXP gcry_sexp_new_name_mpi( const char *name, GCRY_MPI mpi );
void gcry_sexp_release( GCRY_SEXP sexp );
void gcry_sexp_dump( GCRY_SEXP a );
GCRY_SEXP gcry_sexp_cons( GCRY_SEXP a, GCRY_SEXP b );
@@ -164,9 +159,11 @@ GCRY_SEXP gcry_sexp_alist( GCRY_SEXP *array );
GCRY_SEXP gcry_sexp_vlist( GCRY_SEXP a, ... );
GCRY_SEXP gcry_sexp_append( GCRY_SEXP a, GCRY_SEXP n );
GCRY_SEXP gcry_sexp_prepend( GCRY_SEXP a, GCRY_SEXP n );
-int gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
- size_t length, size_t *erroff );
-size_t gcry_sexp_sprint( GCRY_SEXP sexp, int mode, char *buffer,
+int gcry_sexp_sscan( GCRY_SEXP *retsexp, size_t *erroff,
+ const char *buffer, size_t length );
+int gcry_sexp_build( GCRY_SEXP *retsexp, size_t *erroff,
+ const char *format, ... );
+size_t gcry_sexp_sprint( GCRY_SEXP sexp, int mode, char *buffer,
size_t maxlength );
GCRY_SEXP gcry_sexp_find_token( GCRY_SEXP list,
const char *tok, size_t toklen );
@@ -197,7 +194,7 @@ enum gcry_mpi_format {
GCRYMPI_FMT_NONE= 0,
GCRYMPI_FMT_STD = 1, /* twos complement stored without length */
GCRYMPI_FMT_PGP = 2, /* As used by OpenPGP */
- GCRYMPI_FMT_SSH = 3, /* As used by SSH (same as 0 but with length)*/
+ GCRYMPI_FMT_SSH = 3, /* As used by SSH (same as 1 but with length)*/
GCRYMPI_FMT_HEX = 4, /* hex format */
GCRYMPI_FMT_USG = 5, /* like STD but this is an unsigned one */
};
diff --git a/src/sexp.c b/src/sexp.c
index cd7af7a3..e62ade9c 100644
--- a/src/sexp.c
+++ b/src/sexp.c
@@ -19,14 +19,6 @@
*/
-/****************
- * TODO:
- * - implement reference counting to defere freeing of
- * data and make copies of the data on demand.
- * --> do we really need this?
- *
- */
-
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
@@ -39,38 +31,20 @@
#include "g10lib.h"
#include "memory.h"
-
-
-#if 0
-struct sexp_node;
-typedef struct sexp_node *NODE;
-
-struct gcry_sexp {
- int orig_format; /* format which we used to create this object */
- NODE sexp; /* a NULL indicates an empty list */
-};
-#else
typedef struct gcry_sexp *NODE;
-#endif
-
-
-enum node_types { ntLIST, ntDATA, ntMPI };
+typedef unsigned short DATALEN;
struct gcry_sexp {
- NODE next;
- NODE up; /* helper needed for faster traversal */
- enum node_types type;
- union {
- NODE list;
- GCRY_MPI mpi;
- struct {
- size_t len;
- byte d[1];
- } data;
- } u;
+ 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 )
{
@@ -84,6 +58,7 @@ dump_mpi( GCRY_MPI a )
else
fputs( buffer, stderr );
}
+#endif
static void
dump_string( FILE *fp, const byte *p, size_t n, int delim )
@@ -110,107 +85,54 @@ dump_string( FILE *fp, const byte *p, size_t n, int delim )
putc(*p, fp);
}
-static void
-do_dump_list( NODE node, int indent )
+
+void
+gcry_sexp_dump( GCRY_SEXP a )
{
- for( ; node; node = node->next ) {
- switch( node->type ) {
- case ntLIST:
+ 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 )
- putc('\n', stderr);
- fprintf(stderr, "%*s(", indent, "");
- do_dump_list( node->u.list, indent+1 );
- putc(')', stderr);
+ indent--;
+ fprintf ( stderr, "%*s[close]\n", 2*indent, "" );
break;
- case ntDATA:
- if( !node->u.data.len )
- fputs("EMPTY", stderr );
- else
- dump_string(stderr, node->u.data.d, node->u.data.len, ')');
- putc(' ', stderr);
+ case ST_DATA:
+ fprintf ( stderr, "%*s[data=\"", 2*indent, "" );
+ dump_string ( stderr, p, n, '\"' );
+ fputs ( "\"]\n", stderr );
+ p += n;
break;
- case ntMPI:
- dump_mpi( node->u.mpi );
- putc(' ', stderr);
+ default:
+ fprintf ( stderr, "%*s[unknown tag %d]\n", 2*indent, "", type );
+ p += n;
break;
}
- if( !indent )
- putc('\n', stderr);
}
}
-static void
-dump_sexp( NODE node )
-{
- do_dump_list( node, 0 );
-}
-
-
-void
-gcry_sexp_dump( GCRY_SEXP a )
-{
- do_dump_list( a, 0 );
-}
-
-
-/****************
- * Create a new SEXP element (data)
- * If length is 0 it is assumed that buffer is a C string.
- */
-GCRY_SEXP
-gcry_sexp_new_data( const char *buffer, size_t length )
-{
- NODE list, node;
-
- if( !length )
- length = strlen(buffer);
- node = g10_xcalloc( 1, sizeof *node + length );
- node->type = ntDATA;
- node->u.data.len = length;
- memcpy(node->u.data.d, buffer, length );
- list = g10_xcalloc( 1, sizeof *list );
- list->type = ntLIST;
- list->u.list = node;
- return list;
-}
-
-/****************
- * Create a new SEXP element (mpi)
- */
-GCRY_SEXP
-gcry_sexp_new_mpi( GCRY_MPI mpi )
-{
- NODE list, node;
-
- node = g10_xcalloc( 1, sizeof *node );
- node->type = ntMPI;
- node->u.mpi = gcry_mpi_copy( mpi );
- list = g10_xcalloc( 1, sizeof *list );
- list->type = ntLIST;
- list->u.list = node;
- return list;
-}
-
-
-/****************
- * Create a pair of a name and some arbitrary data.
- */
-GCRY_SEXP
-gcry_sexp_new_name_data( const char *name, const char *buffer, size_t length )
-{
- return gcry_sexp_cons( gcry_sexp_new_data( name, 0 ),
- gcry_sexp_new_data( buffer, length ) );
-}
-
-/****************
- * Create a pair of a name and a MPI
- */
-GCRY_SEXP
-gcry_sexp_new_name_mpi( const char *name, GCRY_MPI mpi )
-{
- return gcry_sexp_cons( gcry_sexp_new_data( name, 0 ),
- gcry_sexp_new_mpi( mpi ) );
-}
/****************
@@ -219,11 +141,26 @@ gcry_sexp_new_name_mpi( const char *name, GCRY_MPI mpi )
void
gcry_sexp_release( GCRY_SEXP sexp )
{
- /* FIXME! */
+ 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.
@@ -233,197 +170,105 @@ gcry_sexp_release( GCRY_SEXP sexp )
GCRY_SEXP
gcry_sexp_cons( GCRY_SEXP a, GCRY_SEXP b )
{
- NODE head;
-
- if( a->type != ntLIST ) {
- fputs("sexp_cons: arg 1 is not a list\n", stderr );
- return NULL;
- }
- if( b->type != ntLIST ) {
- fputs("sexp_cons: arg 2 is not a list\n", stderr );
- return NULL;
- }
-
-
- head = g10_xcalloc( 1, sizeof *head );
- head->type = ntLIST;
- if( !a->u.list->next ) { /* a has only one item */
- NODE tmp = a;
- a = a->u.list;
- /* fixme: release tmp here */
- }
- if( !b->u.list->next ) { /* b has only one item */
- NODE tmp = b;
- b = b->u.list;
- /* fixme: release tmp here */
- }
-
- head->u.list = a;
- a->up = head;
- a->next = b;
- b->up = head;
-
- return head;
+ /* 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
- * Don't use the passed lists later on, they are void.
*/
GCRY_SEXP
gcry_sexp_alist( GCRY_SEXP *array )
{
- NODE head, tail = NULL, node;
- va_list arg_ptr ;
- int i;
-
- if( !*array )
- return NULL;
-
- head = g10_xcalloc( 1, sizeof *node );
- head->type = ntLIST;
-
- for( i=0; (node = array[i]); i++ ) {
- if( node->type != ntLIST ) {
- fputs("sexp_alist: an arg is not a list\n", stderr );
- return NULL; /* fixme: we should release already allocated nodes */
- }
- if( !node->u.list->next ) { /* node has only one item */
- NODE tmp = node;
- node = node->u.list;
- /* fixme: release tmp here */
- }
- if( !tail ) {
- head->u.list = node;
- }
- else
- tail->next = node;
- node->up = head;
- tail = node;
- }
-
- return head;
+ /* 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
- * don't use the passed lists later on, they are void.
*/
GCRY_SEXP
gcry_sexp_vlist( GCRY_SEXP a, ... )
{
- NODE head, tail, node;
- va_list arg_ptr ;
-
- if( a->type != ntLIST ) {
- fputs("sexp_vlist: arg 1 is not a list\n", stderr );
- return NULL;
- }
- head = g10_xcalloc( 1, sizeof *node );
- head->type = ntLIST;
- if( !a->u.list->next ) { /* a has only one item */
- NODE tmp = a;
- a = a->u.list;
- /* fixme: release tmp here */
- }
- head->u.list = a;
- a->up = head;
- tail = a;
-
- va_start( arg_ptr, a ) ;
- while( (node = va_arg( arg_ptr, NODE )) ) {
- if( node->type != ntLIST ) {
- fputs("sexp_vlist: an arg is not a list\n", stderr );
- return NULL; /* fixme: we should release already allocated nodes */
- }
- if( !node->u.list->next ) { /* node has only one item */
- NODE tmp = node;
- node = node->u.list;
- /* fixme: release tmp here */
- }
- tail->next = node;
- node->up = head;
- tail = node;
- }
-
- va_end( arg_ptr );
- return head;
+ /* NYI: Implementaion should be quite easy with our new data representation */
+ BUG ();
+ return NULL;
}
/****************
* Append n to the list a
- * Don't use n later on.
* Returns: a new ist (which maybe a)
*/
GCRY_SEXP
gcry_sexp_append( GCRY_SEXP a, GCRY_SEXP n )
{
- GCRY_SEXP node;
-
- if( a->type != ntLIST ) {
- fputs("sexp_append: a is not a list\n", stderr );
- return a;
- }
-
- if( n->type != ntLIST ) {
- fputs("sexp_append: n is not a list\n", stderr );
- return a;
- }
-
- for( node = a; node->next; node = node->next )
- ;
-
- node->next = n;
- return a;
+ /* 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 )
{
-
- fputs("sexp_prepend: not impl.\n", stderr );
- return a;
+ /* NYI: Implementaion should be quite easy with our new data representation */
+ BUG ();
+ return NULL;
}
/****************
- * Locate data in a list. Data must be the first item in the list.
- * Returns: The sublist with that Data (don't modify it!)
+ * 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 )
{
- NODE node;
+ byte *p = list->d;
+ DATALEN n;
+ int type;
if( !toklen )
toklen = strlen(tok);
-
- for( node=list ; node; node = node->next )
- {
- switch( node->type ) {
- case ntLIST: {
- NODE n = gcry_sexp_find_token( node->u.list, tok, toklen );
- if( n )
- return n;
+ 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;
+ }
}
- break;
- case ntDATA:
- if( node == list
- && node->u.data.len == toklen
- && !memcmp( node->u.data.d, tok, toklen ) )
- {
- return node;
- }
- break;
- case ntMPI:
- break;
+ p = pp + nn;
}
- }
-
+ else {
+ p += n;
+ }
+ }
return NULL;
}
@@ -442,6 +287,9 @@ gcry_sexp_find_token( GCRY_SEXP list, const char *tok, size_t toklen )
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 )
@@ -468,30 +316,54 @@ gcry_sexp_enum( GCRY_SEXP list, void **context, int mode )
/* release resources and return nil */
return gcry_sexp_enum( NULL, context, mode );
+ #endif
}
/****************
- * Get the CAR
+ * Extract the CAR of the given list
*/
GCRY_SEXP
gcry_sexp_car( GCRY_SEXP list )
{
- return 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
+ * 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 )
{
- if( list && list->type == ntLIST && !list->next )
- list = list->u.list;
- if( list && list->type == ntDATA ) {
- *datalen = list->u.data.len;
- return list->u.data.d;
+ 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;
@@ -503,17 +375,26 @@ gcry_sexp_car_data( GCRY_SEXP list, size_t *datalen )
GCRY_MPI
gcry_sexp_car_mpi( GCRY_SEXP list, int mpifmt )
{
- if( list && list->type == ntLIST && !list->next )
- list = list->u.list;
- if( mpifmt && list->type == ntDATA ) {
+ 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 n = list->u.data.len;
- if( gcry_mpi_scan( &a, mpifmt, list->u.data.d, &n ) )
- return NULL;
- return a;
+ size_t nbytes;
+
+ memcpy ( &n, ++p, sizeof n );
+ p += sizeof n;
+ nbytes = n;
+ if( !gcry_mpi_scan( &a, mpifmt, p, &nbytes ) )
+ return a;
}
- else if( list->type == ntMPI )
- return gcry_mpi_copy( list->u.mpi );
return NULL;
}
@@ -524,9 +405,48 @@ gcry_sexp_car_mpi( GCRY_SEXP list, int mpifmt )
GCRY_SEXP
gcry_sexp_cdr( GCRY_SEXP list )
{
- if( list && (list = list->next) )
- return list;
- return NULL;
+ 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;
}
/****************
@@ -535,11 +455,27 @@ gcry_sexp_cdr( GCRY_SEXP list )
const char *
gcry_sexp_cdr_data( GCRY_SEXP list, size_t *datalen )
{
- if( list && (list = list->next) && list->type == ntDATA ) {
- *datalen = list->u.data.len;
- return list->u.data.d;
+ 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;
}
@@ -553,21 +489,35 @@ gcry_sexp_cdr_data( GCRY_SEXP list, size_t *datalen )
GCRY_MPI
gcry_sexp_cdr_mpi( GCRY_SEXP list, int mpifmt )
{
- NODE node = list;
+ 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;
- if( !node || !(node = node->next) || node == ntLIST )
- return NULL;
- if( mpifmt && node->type == ntDATA ) {
- MPI a;
- size_t n = node->u.data.len;
- if( gcry_mpi_scan( &a, mpifmt, node->u.data.d, &n ) )
- return NULL;
- return a;
+ memcpy ( &n, ++p, sizeof n );
+ p += sizeof n;
+ nbytes =n;
+ if( !gcry_mpi_scan( &a, mpifmt, p, &nbytes ) )
+ return a;
+ }
}
- else if( node->type == ntMPI )
- return gcry_mpi_copy( node->u.mpi );
- else
- return NULL;
+ return NULL;
}
@@ -603,38 +553,111 @@ hextobyte( const byte *s )
* 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.
*/
-int
-gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
- size_t length, size_t *erroff )
+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;
- NODE head, tail, node;
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;
- tail = head = NULL;
+ /* 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 ) {
@@ -689,37 +712,21 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
if( isxdigit( *p ) )
hexcount++;
else if( *p == '#' ) {
- int i;
-
if( (hexcount & 1) ) {
*erroff = p - buffer;
return -12; /* odd number of hex digits */
}
- /* make a new list entry */
datalen = hexcount/2;
- node = g10_xcalloc( 1, sizeof *node + datalen );
- if( first ) { /* stuff it into the first node */
- first = 0;
- node->up = tail;
- tail->u.list = node;
- }
- else {
- node->up = tail->up;
- tail->next = node;
- }
- tail = node;
- /* and fill in the value (we store the value in the node)*/
- node->type = ntDATA;
- node->u.data.len = datalen;
- for(i=0, hexfmt++; hexfmt < p; hexfmt++ ) {
+ MAKE_SPACE (datalen);
+ *pos++ = ST_DATA;
+ STORE_LEN (pos, datalen);
+ for( hexfmt++; hexfmt < p; hexfmt++ ) {
if( isspace( *hexfmt ) )
continue;
- node->u.data.d[i++] = hextobyte( hexfmt );
+ *pos++ = hextobyte( hexfmt );
hexfmt++;
}
- assert( hexfmt == p );
- assert( i == datalen );
hexfmt = NULL;
}
else if( !isspace( *p ) ) {
@@ -746,22 +753,11 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
return -2; /* buffer too short */
}
/* make a new list entry */
- node = g10_xcalloc( 1, sizeof *node + datalen );
- if( first ) { /* stuff it into the first node */
- first = 0;
- node->up = tail;
- tail->u.list = node;
- }
- else {
- node->up = tail->up;
- tail->next = node;
- }
- tail = node;
- /* and fill in the value (we store the value in the node)*/
- node->type = ntDATA;
- node->u.data.len = datalen;
- memcpy(node->u.data.d, p+1, datalen );
-
+ MAKE_SPACE (datalen);
+ *pos++ = ST_DATA;
+ STORE_LEN (pos, datalen);
+ memcpy (pos, p+1, datalen );
+ pos += datalen;
n -= datalen;
p += datalen;
}
@@ -784,36 +780,98 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *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 */
}
- node = g10_xcalloc( 1, sizeof *node );
- if( !head )
- head = node;
- else {
- node->up = tail->up;
- tail->next = node;
- }
- node->type = ntLIST;
- tail = node;
+ 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( !head ) {
+ if( !n_fixups ) {
*erroff = 0;
- return -4; /* not a list */
- }
- tail = tail->up;
- if( !tail ) {
- *erroff = p - buffer;
- return -3;
+ 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;
@@ -864,16 +922,45 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
*erroff = p - buffer;
return -10; /* unexpected reserved punctuation */
}
+ else if( arg_ptr && *p == '%' ) {
+ percent = p;
+ }
else { /* bad or unavailable*/
*erroff = p - buffer;
return -5;
}
}
- *retsexp = head;
+ 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
@@ -891,7 +978,7 @@ gcry_sexp_sprint( GCRY_SEXP sexp, int mode, char *buffer, size_t maxlength )
-#if 1
+#if 0
/***********************************************************/
const char *
diff --git a/src/testapi.c b/src/testapi.c
index a42b037c..faa26ebd 100644
--- a/src/testapi.c
+++ b/src/testapi.c
@@ -7,11 +7,67 @@
#include <gcrypt.h>
+#define BUG() do {fprintf ( stderr, "Ooops at %s:%d\n", __FILE__ , __LINE__ );\
+ exit(2);} while(0)
+
+/* an ElGamal public key */
+struct {
+ const char *p,*g,*y;
+} elg_testkey1 = {
+ "0x9D559F31A6D30492C383213844AEBB7772963A85D3239F3611AAB93A2A985F64FB735B9259EC326BF5720F909980D609D37C288C9223B0350FBE493C3B5AF54CA23031E952E92F8A3DBEDBC5A684993D452CD54F85B85160166FCD25BD7AB6AE9B1EB4FCC9D300DAFF081C4CBA6694906D3E3FF18196A5CCF7F0A6182962166B",
+ "0x5",
+ "0x9640024BB2A277205813FF685048AA27E2B192B667163E7C59E381E27003D044C700C531CE8FD4AA781B463BC9FFE74956AF09A38A098322B1CF72FC896F009E3A6BFF053D3B1D1E1994BF9CC07FA12963D782F027B51511DDE8C5F43421FBC12734A9C070F158C729A370BEE5FC51A772219438EDA8202C35FA3F5D8CD1997B"
+};
+
+void
+test_sexp ( int argc, char **argv )
+{
+ int rc, nbits;
+ GCRY_SEXP sexp;
+ GCRY_MPI key[3];
+
+ if ( gcry_mpi_scan( &key[0], GCRYMPI_FMT_HEX, elg_testkey1.p, NULL ) )
+ BUG();
+ if ( gcry_mpi_scan( &key[1], GCRYMPI_FMT_HEX, elg_testkey1.g, NULL ) )
+ BUG();
+ if ( gcry_mpi_scan( &key[2], GCRYMPI_FMT_HEX, elg_testkey1.y, NULL ) )
+ BUG();
+
+ /* get nbits from a key */
+ rc = gcry_sexp_build ( &sexp, NULL,
+ "(public-key(elg(p%m)(g%m)(y%m)))",
+ key[0], key[1], key[2] );
+ if (rc) {
+ fprintf (stderr, "gcry_sexp_build failed: rc=%d\n", rc );
+ return;
+ }
+ fputs ( "DUMP of PK:\n", stderr );
+ gcry_sexp_dump ( sexp );
+ { GCRY_SEXP x;
+ x = gcry_sexp_cdr ( sexp );
+ fputs ( "DUMP of CDR:\n", stderr );
+ gcry_sexp_dump ( x );
+ gcry_sexp_release ( x );
+ }
+ nbits = gcry_pk_get_nbits( sexp );
+ printf ( "elg_testkey1 - nbits=%d\n", nbits );
+ gcry_sexp_release( sexp );
+}
+
+
int
main( int argc, char **argv )
{
- printf("%s\n", gcry_check_version ( argc > 1 ? argv[1] : NULL ) );
-
+ if ( argc < 2 )
+ printf("%s\n", gcry_check_version ( NULL ) );
+ else if ( !strcmp ( argv[1], "version") )
+ printf("%s\n", gcry_check_version ( argc > 2 ? argv[2] : NULL ) );
+ else if ( !strcmp ( argv[1], "sexp" ) )
+ test_sexp ( argc-2, argv+2 );
+ else {
+ fprintf (stderr, "usage: testapi mode-string [mode-args]\n");
+ return 1;
+ }
return 0;
}