diff options
author | Werner Koch <wk@gnupg.org> | 1998-06-11 09:16:50 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 1998-06-11 09:16:50 +0200 |
commit | d9b3dc000085007bdd198ca4c0500e80a72475d7 (patch) | |
tree | bb3ffa42fa8b9e30476fdbc843632c896fcfec37 /cipher | |
parent | . (diff) | |
download | gnupg2-d9b3dc000085007bdd198ca4c0500e80a72475d7.tar.xz gnupg2-d9b3dc000085007bdd198ca4c0500e80a72475d7.zip |
update from tobold
Diffstat (limited to 'cipher')
-rw-r--r-- | cipher/ChangeLog | 5 | ||||
-rw-r--r-- | cipher/cipher.c | 104 | ||||
-rw-r--r-- | cipher/dynload.c | 187 | ||||
-rw-r--r-- | cipher/dynload.h | 7 | ||||
-rw-r--r-- | cipher/pubkey.c | 84 | ||||
-rw-r--r-- | cipher/rand-dummy.c | 2 |
6 files changed, 333 insertions, 56 deletions
diff --git a/cipher/ChangeLog b/cipher/ChangeLog index 79f3dc171..6e59455a9 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -1,3 +1,8 @@ +Wed Jun 10 07:52:08 1998 Werner Koch,mobil,,, (wk@tobold) + + * dynload.c: New + * cipher.c: Major changes to allow extensions. + Mon Jun 8 22:43:00 1998 Werner Koch (wk@isil.d.shuttle.de) * cipher.c: Major internal chnages to support extensions. diff --git a/cipher/cipher.c b/cipher/cipher.c index 5d39c3ca3..6ac468274 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -32,21 +32,23 @@ #include "blowfish.h" #include "cast5.h" #include "des.h" +#include "dynload.h" -#include <dlfcn.h> #define STD_BLOCKSIZE 8 #define TABLE_SIZE 20 -static struct { +struct cipher_table_s { const char *name; int algo; - int keylen; - int contextsize; /* allocate this amount of context */ + size_t keylen; + size_t contextsize; /* allocate this amount of context */ void (*setkey)( void *c, byte *key, unsigned keylen ); void (*encrypt)( void *c, byte *outbuf, byte *inbuf ); void (*decrypt)( void *c, byte *outbuf, byte *inbuf ); -} cipher_table[TABLE_SIZE]; +}; + +static struct cipher_table_s cipher_table[TABLE_SIZE]; struct cipher_handle_s { @@ -142,56 +144,54 @@ static int load_cipher_modules() { static int done = 0; + void *context = NULL; + struct cipher_table_s *ct; + int ct_idx; + size_t blocksize; + int i; + const char *name; + int any = 0; - if( !done ) { - void *handle; - char **name; - void *sym; - void * (*enumfunc)(int, int*, int*, int*); - const char *err; - - log_debug("load_cipher_modules\n"); - handle = dlopen("/sahara/proj/psst+g10/non-free-src/rsa+idea.so", RTLD_LAZY); - if( !handle ) - log_bug("dlopen(rsa+idea) failed: %s\n", dlerror() ); - name = (char**)dlsym(handle, "gnupgext_version"); - if( (err=dlerror()) ) - log_error("dlsym: gnupgext_version not found: %s\n", err ); - else { - log_debug("dlsym: gnupgext_version='%s'\n", *name ); - sym = dlsym(handle, "gnupgext_enum_func"); - if( (err=dlerror()) ) - log_error("dlsym: gnupgext_enum_func not found: %s\n", err ); - else { - int seq = 0; - int class, vers; - - enumfunc = (void *(*)(int,int*,int*,int*))sym; - while( (sym = enumfunc(0, &seq, &class, &vers)) ) { - if( vers != 1 ) { - log_debug("ignoring extfunc with version %d\n", vers); - continue; - } - switch( class ) { - case 11: - case 21: - case 31: - log_info("provides %s algorithm %d\n", - class == 11? "md" : - class == 21? "cipher" : "pubkey", - *(int*)sym); - break; - default: - log_debug("skipping class %d\n", class); - } - } - } + if( done ) + return 0; + done = 1; + + for(ct_idx=0, ct = cipher_table; ct_idx < TABLE_SIZE; ct_idx++,ct++ ) { + if( !ct->name ) + break; + } + if( ct_idx >= TABLE_SIZE-1 ) + BUG(); /* table already full */ + /* now load all extensions */ + while( (name = enum_gnupgext_ciphers( &context, &ct->algo, + &ct->keylen, &blocksize, &ct->contextsize, + &ct->setkey, &ct->encrypt, &ct->decrypt)) ) { + if( blocksize != STD_BLOCKSIZE ) { + log_info("skipping cipher %d: unsupported blocksize\n", ct->algo); + continue; + } + for(i=0; cipher_table[i].name; i++ ) + if( cipher_table[i].algo == ct->algo ) + break; + if( cipher_table[i].name ) { + log_info("skipping cipher %d: already loaded\n", ct->algo ); + continue; + } + /* put it into the table */ + log_info("loaded cipher %d (%s)\n", ct->algo, name); + ct->name = name; + ct_idx++; + ct++; + any = 1; + /* check whether there are more available table slots */ + if( ct_idx >= TABLE_SIZE-1 ) { + log_info("cipher table full; ignoring other extensions\n"); + break; } - dlclose(handle); - done = 1; } - - return 0; + enum_gnupgext_ciphers( &context, NULL, NULL, NULL, NULL, + NULL, NULL, NULL ); + return any; } diff --git a/cipher/dynload.c b/cipher/dynload.c index 19e035d9d..b40eb4056 100644 --- a/cipher/dynload.c +++ b/cipher/dynload.c @@ -18,13 +18,194 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ - - #include <config.h> #include <stdio.h> #include <stdlib.h> - +#include <string.h> +#include <dlfcn.h> +#include "util.h" +#include "cipher.h" #include "dynload.h" +typedef struct ext_list { + struct ext_list *next; + void *handle; /* handle from dlopen() */ + int failed; /* already tried but failed */ + void * (*enumfunc)(int, int*, int*, int*); + char name[1]; +} *EXTLIST; + +static EXTLIST extensions; + +typedef struct { + EXTLIST r; + int seq1; + int seq2; + void *sym; +} ENUMCONTEXT; + +/**************** + * Register an extension module. The last registered module will + * be loaded first. + */ +void +register_cipher_extension( const char *fname ) +{ + EXTLIST r, el; + + if( *fname != '/' ) { /* do tilde expansion etc */ + char *p ; + + if( strchr(fname, '/') ) + p = make_filename(fname, NULL); + else + p = make_filename(GNUPG_LIBDIR, fname, NULL); + el = m_alloc_clear( sizeof *el + strlen(p) ); + strcpy(el->name, p ); + m_free(p); + } + else { + el = m_alloc_clear( sizeof *el + strlen(fname) ); + strcpy(el->name, fname ); + } + /* check that it is not already registered */ + for(r = extensions; r; r = r->next ) + if( !compare_filenames(r->name, el->name) ) { + log_debug("extension '%s' already registered\n", el->name ); + m_free(el); + return; + } + log_debug("extension '%s' registered\n", el->name ); + /* and register */ + el->next = extensions; + extensions = el; +} + + +static int +load_extension( EXTLIST el ) +{ + char **name; + void *sym; + const char *err; + int seq = 0; + int class, vers; + + el->handle = dlopen(el->name, RTLD_LAZY); + if( !el->handle ) { + log_error("%s: error loading extension: %s\n", el->name, dlerror() ); + goto failure; + } + name = (char**)dlsym(el->handle, "gnupgext_version"); + if( (err=dlerror()) ) { + log_error("%s: not a gnupg extension: %s\n", el->name, err ); + goto failure; + } + + log_info("%s: version '%s'\n", el->name, *name ); + + sym = dlsym(el->handle, "gnupgext_enum_func"); + if( (err=dlerror()) ) { + log_error("%s: invalid gnupg extension: %s\n", el->name, err ); + goto failure; + } + el->enumfunc = (void *(*)(int,int*,int*,int*))sym; + + /* list the contents of the module */ + while( (sym = (*el->enumfunc)(0, &seq, &class, &vers)) ) { + if( vers != 1 ) { + log_error("%s: ignoring func with version %d\n", el->name, vers); + continue; + } + switch( class ) { + case 11: + case 21: + case 31: + log_info("%s: provides %s algorithm %d\n", el->name, + class == 11? "md" : + class == 21? "cipher" : "pubkey", + *(int*)sym); + break; + default: + log_debug("%s: skipping class %d\n", el->name, class); + } + } + return 0; + + failure: + if( el->handle ) { + dlclose(el->handle); + el->handle = NULL; + } + el->failed = 1; + return -1; +} + + + +const char * +enum_gnupgext_ciphers( void **enum_context, int *algo, + size_t *keylen, size_t *blocksize, size_t *contextsize, + void (**setkey)( void *c, byte *key, unsigned keylen ), + void (**encrypt)( void *c, byte *outbuf, byte *inbuf ), + void (**decrypt)( void *c, byte *outbuf, byte *inbuf ) + ) +{ + EXTLIST r; + ENUMCONTEXT *ctx; + const char * (*finfo)(int, size_t*, size_t*, size_t*, + void (**)( void *, byte *, unsigned), + void (**)( void *, byte *, byte *), + void (**)( void *, byte *, byte *)); + + if( !*enum_context ) { /* init context */ + ctx = m_alloc_clear( sizeof( *ctx ) ); + ctx->r = extensions; + *enum_context = ctx; + } + else if( !algo ) { /* release the context */ + m_free(*enum_context); + *enum_context = NULL; + return NULL; + } + else + ctx = *enum_context; + + for( r = ctx->r; r; r = r->next ) { + int class, vers; + if( r->failed ) + continue; + if( !r->handle && load_extension(r) ) + continue; + /* get a cipher info function */ + if( ctx->sym ) + goto inner_loop; + while( (ctx->sym = (*r->enumfunc)(20, &ctx->seq1, &class, &vers)) ) { + void *sym; + /* must check class because enumfunc may be wrong coded */ + if( vers != 1 || class != 20 ) + continue; + inner_loop: + finfo = ctx->sym; + while( (sym = (*r->enumfunc)(21, &ctx->seq2, &class, &vers)) ) { + const char *algname; + if( vers != 1 || class != 21 ) + continue; + *algo = *(int*)sym; + algname = (*finfo)( *algo, keylen, blocksize, contextsize, + setkey, encrypt, decrypt ); + log_debug("found algo %d (%s)\n", *algo, algname ); + if( algname ) { + ctx->r = r; + return algname; + } + } + ctx->seq2 = 0; + } + ctx->seq1 = 0; + } + ctx->r = r; + return NULL; +} diff --git a/cipher/dynload.h b/cipher/dynload.h index a839a91b3..78f41c644 100644 --- a/cipher/dynload.h +++ b/cipher/dynload.h @@ -20,5 +20,12 @@ #ifndef G10_CIPHER_DYNLOAD_H #define G10_CIPHER_DYNLOAD_H +const char * +enum_gnupgext_ciphers( void **enum_context, int *algo, + size_t *keylen, size_t *blocksize, size_t *contextsize, + void (**setkey)( void *c, byte *key, unsigned keylen ), + void (**encrypt)( void *c, byte *outbuf, byte *inbuf ), + void (**decrypt)( void *c, byte *outbuf, byte *inbuf ) + ); #endif /*G10_CIPHER_DYNLOAD_H*/ diff --git a/cipher/pubkey.c b/cipher/pubkey.c new file mode 100644 index 000000000..3ffc1ca33 --- /dev/null +++ b/cipher/pubkey.c @@ -0,0 +1,84 @@ +/* pubkey.c - pubkey dispatcher + * Copyright (C) 1998 Free Software Foundation, Inc. + * + * This file is part of GNUPG. + * + * GNUPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GNUPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include "util.h" +#include "errors.h" +#include "mpi.h" +#include "cipher.h" +#include "dynload.h" + + +/**************** + * This is the interface for the public key decryption. + * ALGO gives the algorithm to use and this implicitly determines + * the size of the arrays. + * result is a pointer to a mpi variable which will receive a + * newly allocated mpi or NULL in case of an error. + */ +int +pubkey_decrypt( int algo, MPI *result, int ndata, MPI *data, + int nskey, MPI *skey ) +{ + MPI plain = NULL; + + *result = NULL; /* so the caller can do always do an mpi_free */ + if( DBG_CIPHER ) { + int i; + log_debug("pubkey_decrypt: algo=%d\n", algo ); + for(i=0; i < nskey; i++ ) + log_mpidump(" skey:", skey[i] ); + for(i=0; i < ndata; i++ ) + log_mpidump(" data:", data[i] ); + } + if( is_ELGAMAL(algo) ) { + ELG_secret_key sk; + assert( ndata == 2 && nskey == 4 ); + sk.p = skey[0]; + sk.g = skey[1]; + sk.y = skey[2]; + sk.x = skey[3]; + plain = mpi_alloc_secure( mpi_get_nlimbs( sk.p ) ); + elg_decrypt( plain, data[0], data[1], &sk ); + } + else if( is_RSA(k->pubkey_algo) ) { + RSA_secret_key sk; + assert( ndata == 1 && nskey == 6 ); + sk.e = skey[0]; + sk.n = skey[1]; + sk.p = skey[2]; + sk.q = skey[3]; + sk.d = skey[4]; + sk.u = skey[5]; + plain = mpi_alloc_secure( mpi_get_nlimbs(sk.n) ); + rsa_secret( plain, data[0], &sk ); + } + else + return G10ERR_PUBKEY_ALGO; + *result = plain; + return 0; +} + + diff --git a/cipher/rand-dummy.c b/cipher/rand-dummy.c index 3e7a42573..e2c754ebb 100644 --- a/cipher/rand-dummy.c +++ b/cipher/rand-dummy.c @@ -69,7 +69,7 @@ fast_random_poll() { #if HAVE_GETHRTIME { hrtime_t tv; - tv = gethrtime(void); + tv = gethrtime(); add_randomness( &tv, sizeof(tv), 1 ); } #elif HAVE_GETTIMEOFTIME |