diff options
-rw-r--r-- | cipher/ChangeLog | 6 | ||||
-rw-r--r-- | cipher/pubkey.c | 333 | ||||
-rw-r--r-- | mpi/ChangeLog | 4 | ||||
-rw-r--r-- | mpi/config.links | 10 | ||||
-rw-r--r-- | src/ChangeLog | 9 | ||||
-rw-r--r-- | src/Makefile.am | 7 | ||||
-rw-r--r-- | src/gcrypt.h | 17 | ||||
-rw-r--r-- | src/sexp.c | 825 | ||||
-rw-r--r-- | src/testapi.c | 60 |
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 */ }; @@ -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; } |