See ChangeLog: Tue Jul 25 17:44:15 CEST 2000 Werner Koch
authorWerner Koch <wk@gnupg.org>
Tue, 25 Jul 2000 15:38:11 +0000 (15:38 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 25 Jul 2000 15:38:11 +0000 (15:38 +0000)
cipher/ChangeLog
cipher/pubkey.c
mpi/ChangeLog
mpi/config.links
src/ChangeLog
src/Makefile.am
src/gcrypt.h
src/sexp.c
src/testapi.c

index 72129a8..f13c0fb 100644 (file)
@@ -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.
index b139720..7ef6f18 100644 (file)
@@ -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;
 }
 
index 7119d1e..6bdeaf2 100644 (file)
@@ -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
index 6a2cbfb..6f6b276 100644 (file)
@@ -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"
index 83d1517..e0818eb 100644 (file)
@@ -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.
index 359bc1c..fd1182c 100644 (file)
@@ -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 \
index aaeb95b..a362ec2 100644 (file)
@@ -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 */
 };
index cd7af7a..e62ade9 100644 (file)
  */
 
 
-/****************
- * 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>
 #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 *
index a42b037..faa26eb 100644 (file)
@@ -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;
 }