diff options
author | Moritz Schulte <mo@g10code.com> | 2005-01-23 18:53:26 +0000 |
---|---|---|
committer | Moritz Schulte <mo@g10code.com> | 2005-01-23 18:53:26 +0000 |
commit | ac5a46b1e07b43f934daa964457aebee28f5f744 (patch) | |
tree | 17c14d843477a9a58ec4006acd80064d11761f4a | |
parent | 254c52e2578bb334565e3d7e27174678c879df14 (diff) | |
download | libgcrypt-mo.tar.gz |
Updated from HEADmo
-rw-r--r-- | src/ath.c | 172 | ||||
-rw-r--r-- | src/ath.h | 92 | ||||
-rw-r--r-- | src/cipher.h | 66 | ||||
-rw-r--r-- | src/global.c | 154 | ||||
-rw-r--r-- | src/libgcrypt-config.in | 109 | ||||
-rw-r--r-- | src/libgcrypt.m4 | 50 | ||||
-rw-r--r-- | src/misc.c | 13 | ||||
-rw-r--r-- | src/missing-string.c | 3 | ||||
-rw-r--r-- | src/module.c | 43 | ||||
-rw-r--r-- | src/secmem.c | 80 | ||||
-rw-r--r-- | src/secmem.h | 8 | ||||
-rw-r--r-- | src/sexp.c | 781 |
12 files changed, 994 insertions, 577 deletions
@@ -1,20 +1,20 @@ /* ath.c - Thread-safeness library. - Copyright (C) 2002, 2003 g10 Code GmbH + Copyright (C) 2002, 2003, 2004 g10 Code GmbH This file is part of Libgcrypt. Libgcrypt 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. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. Libgcrypt 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 Libgcrypt; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with Libgcrypt; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ @@ -31,18 +31,109 @@ #endif #include <sys/types.h> #include <sys/wait.h> +#include <errno.h> #include "ath.h" + +/* The interface table. */ +static struct ath_ops ops; +/* True if we should use the external callbacks. */ +static int ops_set; + + +/* For the dummy interface. */ #define MUTEX_UNLOCKED ((ath_mutex_t) 0) #define MUTEX_LOCKED ((ath_mutex_t) 1) #define MUTEX_DESTROYED ((ath_mutex_t) 2) + +/* The lock we take while checking for lazy lock initialization. */ +static ath_mutex_t check_init_lock = ATH_MUTEX_INITIALIZER; + +int +ath_init (void) +{ + int err = 0; + + if (ops_set) + { + if (ops.init) + err = (*ops.init) (); + if (err) + return err; + err = (*ops.mutex_init) (&check_init_lock); + } + return err; +} + + +/* Initialize the locking library. Returns 0 if the operation was + successful, EINVAL if the operation table was invalid and EBUSY if + we already were initialized. */ +gpg_err_code_t +ath_install (struct ath_ops *ath_ops, int check_only) +{ + if (check_only) + { + enum ath_thread_option option = ATH_THREAD_OPTION_DEFAULT; + + /* Check if the requested thread option is compatible to the + thread option we are already committed to. */ + if (ath_ops) + option = ath_ops->option; + + if (!ops_set && option) + return GPG_ERR_NOT_SUPPORTED; + + if (ops.option == ATH_THREAD_OPTION_USER + || option == ATH_THREAD_OPTION_USER + || ops.option != option) + return GPG_ERR_NOT_SUPPORTED; + + return 0; + } + + if (ath_ops) + { + /* It is convenient to not require DESTROY. */ + if (!ath_ops->mutex_init || !ath_ops->mutex_lock + || !ath_ops->mutex_unlock) + return GPG_ERR_INV_ARG; + + ops = *ath_ops; + ops_set = 1; + } + else + ops_set = 0; + + return 0; +} + + +static int +mutex_init (ath_mutex_t *lock, int just_check) +{ + int err = 0; + + if (just_check) + (*ops.mutex_lock) (&check_init_lock); + if (*lock == ATH_MUTEX_INITIALIZER || !just_check) + err = (*ops.mutex_init) (lock); + if (just_check) + (*ops.mutex_unlock) (&check_init_lock); + return err; +} + + int ath_mutex_init (ath_mutex_t *lock) { + if (ops_set) + return mutex_init (lock, 0); + #ifndef NDEBUG *lock = MUTEX_UNLOCKED; #endif @@ -53,6 +144,19 @@ ath_mutex_init (ath_mutex_t *lock) int ath_mutex_destroy (ath_mutex_t *lock) { + if (ops_set) + { + int err = mutex_init (lock, 1); + + if (err) + return err; + + if (ops.mutex_destroy) + return (*ops.mutex_destroy) (lock); + else + return 0; + } + #ifndef NDEBUG assert (*lock == MUTEX_UNLOCKED); @@ -65,6 +169,14 @@ ath_mutex_destroy (ath_mutex_t *lock) int ath_mutex_lock (ath_mutex_t *lock) { + if (ops_set) + { + int ret = mutex_init (lock, 1); + if (ret) + return ret; + return (*ops.mutex_lock) (lock); + } + #ifndef NDEBUG assert (*lock == MUTEX_UNLOCKED); @@ -77,6 +189,14 @@ ath_mutex_lock (ath_mutex_t *lock) int ath_mutex_unlock (ath_mutex_t *lock) { + if (ops_set) + { + int ret = mutex_init (lock, 1); + if (ret) + return ret; + return (*ops.mutex_unlock) (lock); + } + #ifndef NDEBUG assert (*lock == MUTEX_LOCKED); @@ -89,14 +209,20 @@ ath_mutex_unlock (ath_mutex_t *lock) ssize_t ath_read (int fd, void *buf, size_t nbytes) { - return read (fd, buf, nbytes); + if (ops_set && ops.read) + return (*ops.read) (fd, buf, nbytes); + else + return read (fd, buf, nbytes); } ssize_t ath_write (int fd, const void *buf, size_t nbytes) { - return write (fd, buf, nbytes); + if (ops_set && ops.write) + return (*ops.write) (fd, buf, nbytes); + else + return write (fd, buf, nbytes); } @@ -104,40 +230,58 @@ ssize_t ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset, struct timeval *timeout) { - return select (nfd, rset, wset, eset, timeout); + if (ops_set && ops.select) + return (*ops.select) (nfd, rset, wset, eset, timeout); + else + return select (nfd, rset, wset, eset, timeout); } ssize_t ath_waitpid (pid_t pid, int *status, int options) { - return waitpid (pid, status, options); + if (ops_set && ops.waitpid) + return (*ops.waitpid) (pid, status, options); + else + return waitpid (pid, status, options); } int ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr) { - return accept (s, addr, length_ptr); + if (ops_set && ops.accept) + return (*ops.accept) (s, addr, length_ptr); + else + return accept (s, addr, length_ptr); } int ath_connect (int s, struct sockaddr *addr, socklen_t length) { - return connect (s, addr, length); + if (ops_set && ops.connect) + return (*ops.connect) (s, addr, length); + else + return connect (s, addr, length); } int ath_sendmsg (int s, const struct msghdr *msg, int flags) { - return sendmsg (s, msg, flags); + if (ops_set && ops.sendmsg) + return (*ops.sendmsg) (s, msg, flags); + else + return sendmsg (s, msg, flags); } int ath_recvmsg (int s, struct msghdr *msg, int flags) { - return recvmsg (s, msg, flags); + if (ops_set && ops.recvmsg) + return (*ops.recvmsg) (s, msg, flags); + else + return recvmsg (s, msg, flags); } @@ -1,28 +1,38 @@ -/* ath.h - Interfaces for thread-safeness library. - Copyright (C) 2002, 2003 g10 Code GmbH +/* ath.h - Thread-safeness library. + Copyright (C) 2002, 2003, 2004 g10 Code GmbH This file is part of Libgcrypt. Libgcrypt 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. + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. Libgcrypt 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 Libgcrypt; if not, write to the Free Software + You should have received a copy of the GNU Lesser General Public + License along with Libgcrypt; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef ATH_H #define ATH_H +#ifdef _WIN32 +#warning We need to replace these hacks by cleaner code. +typedef int ssize_t; +typedef int pid_t; +#include <windows.h> +#else #include <sys/types.h> #include <sys/socket.h> +#endif +#include <gpg-error.h> + +#include <config.h> /* Define _ATH_EXT_SYM_PREFIX if you want to give all external symbols @@ -33,6 +43,8 @@ #define _ATH_PREFIX1(x,y) x ## y #define _ATH_PREFIX2(x,y) _ATH_PREFIX1(x,y) #define _ATH_PREFIX(x) _ATH_PREFIX2(_ATH_EXT_SYM_PREFIX,x) +#define ath_install _ATH_PREFIX(ath_install) +#define ath_init _ATH_PREFIX(ath_init) #define ath_mutex_init _ATH_PREFIX(ath_mutex_init) #define ath_mutex_destroy _ATH_PREFIX(ath_mutex_destroy) #define ath_mutex_lock _ATH_PREFIX(ath_mutex_lock) @@ -48,32 +60,19 @@ #endif -typedef void *ath_mutex_t; -#define ATH_MUTEX_INITIALIZER 0; - -/* Functions for mutual exclusion. */ -int ath_mutex_init (ath_mutex_t *mutex); -int ath_mutex_destroy (ath_mutex_t *mutex); -int ath_mutex_lock (ath_mutex_t *mutex); -int ath_mutex_unlock (ath_mutex_t *mutex); +enum ath_thread_option + { + ATH_THREAD_OPTION_DEFAULT = 0, + ATH_THREAD_OPTION_USER = 1, + ATH_THREAD_OPTION_PTH = 2, + ATH_THREAD_OPTION_PTHREAD = 3 + }; -/* Replacement for the POSIX functions, which can be used to allow - other (user-level) threads to run. */ -ssize_t ath_read (int fd, void *buf, size_t nbytes); -ssize_t ath_write (int fd, const void *buf, size_t nbytes); -ssize_t ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset, - struct timeval *timeout); -ssize_t ath_waitpid (pid_t pid, int *status, int options); -int ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr); -int ath_connect (int s, struct sockaddr *addr, socklen_t length); -int ath_sendmsg (int s, const struct msghdr *msg, int flags); -int ath_recvmsg (int s, struct msghdr *msg, int flags); - -#define _ATH_COMPAT -#ifdef _ATH_COMPAT struct ath_ops { - int (*mutex_init) (void **priv, int just_check); + enum ath_thread_option option; + int (*init) (void); + int (*mutex_init) (void **priv); int (*mutex_destroy) (void *priv); int (*mutex_lock) (void *priv); int (*mutex_unlock) (void *priv); @@ -88,15 +87,30 @@ struct ath_ops int (*recvmsg) (int s, struct msghdr *msg, int flags); }; -/* Initialize the any-thread package. */ -#define ath_init _ATH_PREFIX(ath_init) -void ath_init (void); +gpg_err_code_t ath_install (struct ath_ops *ath_ops, int check_only); +int ath_init (void); -/* Used by ath_pkg_init. */ -#define ath_pthread_available _ATH_PREFIX(ath_pthread_available) -struct ath_ops *ath_pthread_available (void); -#define ath_pth_available _ATH_PREFIX(ath_pth_available) -struct ath_ops *ath_pth_available (void); -#endif + +/* Functions for mutual exclusion. */ +typedef void *ath_mutex_t; +#define ATH_MUTEX_INITIALIZER 0 + +int ath_mutex_init (ath_mutex_t *mutex); +int ath_mutex_destroy (ath_mutex_t *mutex); +int ath_mutex_lock (ath_mutex_t *mutex); +int ath_mutex_unlock (ath_mutex_t *mutex); + + +/* Replacement for the POSIX functions, which can be used to allow + other (user-level) threads to run. */ +ssize_t ath_read (int fd, void *buf, size_t nbytes); +ssize_t ath_write (int fd, const void *buf, size_t nbytes); +ssize_t ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset, + struct timeval *timeout); +ssize_t ath_waitpid (pid_t pid, int *status, int options); +int ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr); +int ath_connect (int s, struct sockaddr *addr, socklen_t length); +int ath_sendmsg (int s, const struct msghdr *msg, int flags); +int ath_recvmsg (int s, struct msghdr *msg, int flags); #endif /* ATH_H */ diff --git a/src/cipher.h b/src/cipher.h index 000223bf..a5f194e9 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -26,43 +26,55 @@ #include "../cipher/random.h" +#define PUBKEY_FLAG_NO_BLINDING (1 << 0) + /*-- rmd160.c --*/ void _gcry_rmd160_hash_buffer (char *outbuf, const char *buffer, size_t length); +/*-- sha1.c --*/ +void _gcry_sha1_hash_buffer (char *outbuf, const char *buffer, size_t length); +/*-- dsa.c --*/ +void _gcry_register_pk_dsa_progress (gcry_handler_progress_t cbc, void *cb_data); +/*-- elgamal.c --*/ +void _gcry_register_pk_elg_progress (gcry_handler_progress_t cb, void *cb_data); /*-- primegen.c --*/ void _gcry_register_primegen_progress (gcry_handler_progress_t cb, void *cb_data); +/*-- pubkey.c --*/ +const char * _gcry_pk_aliased_algo_name (int algorithm); + /* Declarations for the cipher specifications. */ -extern gcry_cipher_spec_t cipher_spec_blowfish; -extern gcry_cipher_spec_t cipher_spec_des; -extern gcry_cipher_spec_t cipher_spec_tripledes; -extern gcry_cipher_spec_t cipher_spec_arcfour; -extern gcry_cipher_spec_t cipher_spec_cast5; -extern gcry_cipher_spec_t cipher_spec_aes; -extern gcry_cipher_spec_t cipher_spec_aes192; -extern gcry_cipher_spec_t cipher_spec_aes256; -extern gcry_cipher_spec_t cipher_spec_twofish; -extern gcry_cipher_spec_t cipher_spec_twofish128; -extern gcry_cipher_spec_t cipher_spec_serpent128; -extern gcry_cipher_spec_t cipher_spec_serpent192; -extern gcry_cipher_spec_t cipher_spec_serpent256; +extern gcry_cipher_spec_t _gcry_cipher_spec_blowfish; +extern gcry_cipher_spec_t _gcry_cipher_spec_des; +extern gcry_cipher_spec_t _gcry_cipher_spec_tripledes; +extern gcry_cipher_spec_t _gcry_cipher_spec_arcfour; +extern gcry_cipher_spec_t _gcry_cipher_spec_cast5; +extern gcry_cipher_spec_t _gcry_cipher_spec_aes; +extern gcry_cipher_spec_t _gcry_cipher_spec_aes192; +extern gcry_cipher_spec_t _gcry_cipher_spec_aes256; +extern gcry_cipher_spec_t _gcry_cipher_spec_twofish; +extern gcry_cipher_spec_t _gcry_cipher_spec_twofish128; +extern gcry_cipher_spec_t _gcry_cipher_spec_serpent128; +extern gcry_cipher_spec_t _gcry_cipher_spec_serpent192; +extern gcry_cipher_spec_t _gcry_cipher_spec_serpent256; +extern gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_40; /* Declarations for the digest specifications. */ -extern gcry_md_spec_t digest_spec_crc32; -extern gcry_md_spec_t digest_spec_crc32_rfc1510; -extern gcry_md_spec_t digest_spec_crc24_rfc2440; -extern gcry_md_spec_t digest_spec_md4; -extern gcry_md_spec_t digest_spec_md5; -extern gcry_md_spec_t digest_spec_rmd160; -extern gcry_md_spec_t digest_spec_sha1; -extern gcry_md_spec_t digest_spec_sha256; -extern gcry_md_spec_t digest_spec_sha512; -extern gcry_md_spec_t digest_spec_sha384; -extern gcry_md_spec_t digest_spec_tiger; +extern gcry_md_spec_t _gcry_digest_spec_crc32; +extern gcry_md_spec_t _gcry_digest_spec_crc32_rfc1510; +extern gcry_md_spec_t _gcry_digest_spec_crc24_rfc2440; +extern gcry_md_spec_t _gcry_digest_spec_md4; +extern gcry_md_spec_t _gcry_digest_spec_md5; +extern gcry_md_spec_t _gcry_digest_spec_rmd160; +extern gcry_md_spec_t _gcry_digest_spec_sha1; +extern gcry_md_spec_t _gcry_digest_spec_sha256; +extern gcry_md_spec_t _gcry_digest_spec_sha512; +extern gcry_md_spec_t _gcry_digest_spec_sha384; +extern gcry_md_spec_t _gcry_digest_spec_tiger; /* Declarations for the pubkey cipher specifications. */ -extern gcry_ac_spec_t ac_spec_rsa; -extern gcry_ac_spec_t ac_spec_elg; -extern gcry_ac_spec_t ac_spec_dsa; +extern gcry_pk_spec_t _gcry_pubkey_spec_rsa; +extern gcry_pk_spec_t _gcry_pubkey_spec_elg; +extern gcry_pk_spec_t _gcry_pubkey_spec_dsa; #endif /*G10_CIPHER_H*/ diff --git a/src/global.c b/src/global.c index 8ac05c49..dece54ea 100644 --- a/src/global.c +++ b/src/global.c @@ -1,5 +1,6 @@ /* global.c - global control functions - * Copyright (C) 1998,1999,2000,2001,2002,2003 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 + * 2004 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * @@ -24,7 +25,6 @@ #include <string.h> #include <stdarg.h> #include <ctype.h> -#include <assert.h> #include <limits.h> #include <errno.h> @@ -63,14 +63,14 @@ global_init (void) if (any_init_done) return; any_init_done = 1; - ath_init (); + err = ath_init (); if (! err) _gcry_cipher_init (); if (! err) _gcry_md_init (); if (! err) - _gcry_ac_init (); + _gcry_pk_init (); if (err) /* FIXME? */ @@ -159,13 +159,6 @@ gcry_control (enum gcry_ctl_cmds cmd, ...) va_start (arg_ptr, cmd); switch (cmd) { -#if 0 - case GCRYCTL_NO_MEM_IS_FATAL: - break; - case GCRYCTL_SET_FATAL_FNC: - break; -#endif - case GCRYCTL_ENABLE_M_GUARD: _gcry_private_enable_m_guard (); break; @@ -269,11 +262,24 @@ gcry_control (enum gcry_ctl_cmds cmd, ...) if (! init_finished) { global_init (); - _gcry_random_initialize (); + /* Do only a basic ranom initialization, i.e. inti the + mutexes. */ + _gcry_random_initialize (0); init_finished = 1; } break; + case GCRYCTL_SET_THREAD_CBS: + err = ath_install (va_arg (arg_ptr, void *), any_init_done); + break; + + case GCRYCTL_FAST_POLL: + /* We need to do make sure that the random pool is really + initialized so that the poll fucntion is not a NOP. */ + _gcry_random_initialize (1); + _gcry_fast_random_poll (); + break; + default: err = GPG_ERR_INV_OP; } @@ -377,28 +383,57 @@ gcry_set_outofcore_handler( int (*f)( void*, size_t, unsigned int ), outofcore_handler_value = value; } +gcry_err_code_t +_gcry_malloc (size_t n, unsigned int flags, void **mem) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + void *m = NULL; + + if ((flags & GCRY_ALLOC_FLAG_SECURE) && !no_secure_memory) + { + if (alloc_secure_func) + m = (*alloc_secure_func) (n); + else + m = _gcry_private_malloc_secure (n); + } + else + { + if (alloc_func) + m = (*alloc_func) (n); + else + m = _gcry_private_malloc (n); + } + if (! m) + err = gpg_err_code_from_errno (ENOMEM); + else + *mem = m; + return err; +} + void * -gcry_malloc( size_t n ) +gcry_malloc (size_t n) { - if( alloc_func ) - return alloc_func( n ) ; - return _gcry_private_malloc( n ); + void *mem = NULL; + + _gcry_malloc (n, 0, &mem); + + return mem; } void * -gcry_malloc_secure( size_t n ) +gcry_malloc_secure (size_t n) { - if (no_secure_memory) - return gcry_malloc (n); - if (alloc_secure_func) - return alloc_secure_func (n) ; - return _gcry_private_malloc_secure (n); + void *mem = NULL; + + _gcry_malloc (n, GCRY_ALLOC_FLAG_SECURE, &mem); + + return mem; } int -gcry_is_secure( const void *a ) +gcry_is_secure (const void *a) { if (no_secure_memory) return 0; @@ -430,13 +465,13 @@ gcry_realloc (void *a, size_t n) void gcry_free( void *p ) { - if( !p ) - return; + if( !p ) + return; - if( free_func ) - free_func( p ); - else - _gcry_private_free( p ); + if (free_func) + free_func (p); + else + _gcry_private_free (p); } void * @@ -445,7 +480,8 @@ gcry_calloc (size_t n, size_t m) size_t bytes; void *p; - bytes = n * m; /* size_t is unsigned so the behavior on overflow is defined. */ + bytes = n * m; /* size_t is unsigned so the behavior on overflow is + defined. */ if (m && bytes / m != n) { errno = ENOMEM; @@ -464,7 +500,8 @@ gcry_calloc_secure (size_t n, size_t m) size_t bytes; void *p; - bytes = n * m; /* size_t is unsigned so the behavior on overflow is defined. */ + bytes = n * m; /* size_t is unsigned so the behavior on overflow is + defined. */ if (m && bytes / m != n) { errno = ENOMEM; @@ -478,12 +515,27 @@ gcry_calloc_secure (size_t n, size_t m) } +/* Create and return a copy of the null-terminated string STRING. If + it is contained in secure memory, the copy will be contained in + secure memory as well. In an out-of-memory condition, NULL is + returned. */ char * -gcry_strdup( const char *string ) +gcry_strdup (const char *string) { - void *p = gcry_malloc( strlen(string)+1 ); - strcpy( p, string ); - return p; + char *string_cp = NULL; + size_t string_n = 0; + + string_n = strlen (string); + + if (gcry_is_secure (string)) + string_cp = gcry_malloc_secure (string_n + 1); + else + string_cp = gcry_malloc (string_n + 1); + + if (string_cp) + strcpy (string_cp, string); + + return string_cp; } @@ -547,11 +599,25 @@ gcry_xcalloc_secure( size_t n, size_t m ) } char * -gcry_xstrdup( const char *string ) +gcry_xstrdup (const char *string) { - void *p = gcry_xmalloc( strlen(string)+1 ); - strcpy( p, string ); - return p; + char *p; + + while ( !(p = gcry_strdup (string)) ) + { + size_t n = strlen (string); + int is_sec = !!gcry_is_secure (string); + + if (!outofcore_handler + || !outofcore_handler (outofcore_handler_value, n, is_sec) ) + { + _gcry_fatal_error (gpg_err_code_from_errno (errno), + is_sec? _("out of core in secure memory"):NULL); + } + } + + strcpy( p, string ); + return p; } @@ -600,9 +666,15 @@ _gcry_get_debug_flag( unsigned int mask ) Only used in debugging mode. */ void -gcry_set_progress_handler (gcry_handler_progress_t cb, void *cb_data) +gcry_set_progress_handler (void (*cb)(void *,const char*,int, int, int), + void *cb_data) { - _gcry_ac_progress_register (cb, cb_data); +#if USE_DSA + _gcry_register_pk_dsa_progress (cb, cb_data); +#endif +#if USE_ELGAMAL + _gcry_register_pk_elg_progress (cb, cb_data); +#endif _gcry_register_primegen_progress (cb, cb_data); _gcry_register_random_progress (cb, cb_data); } diff --git a/src/libgcrypt-config.in b/src/libgcrypt-config.in index 07713a6e..eac12aa2 100644 --- a/src/libgcrypt-config.in +++ b/src/libgcrypt-config.in @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (C) 1999, 2002 Free Software Foundation, Inc. +# Copyright (C) 1999, 2002, 2003, 2004 Free Software Foundation, Inc. # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without @@ -12,35 +12,32 @@ # General. prefix="@prefix@" exec_prefix="@exec_prefix@" -thread_module="" version="@VERSION@" +includedir="@includedir@" +libdir="@libdir@" gpg_error_libs="@GPG_ERROR_LIBS@" gpg_error_cflags="@GPG_ERROR_CFLAGS@" -# LIBS values. +# libgcrypt values. libs="@LIBGCRYPT_CONFIG_LIBS@" -libs_pthread="@LIBGCRYPT_CONFIG_LIBS_PTHREAD@" -libs_pth="@LIBGCRYPT_CONFIG_LIBS_PTH@" - -# CFLAGS values. cflags="@LIBGCRYPT_CONFIG_CFLAGS@" -cflags_pthread="@LIBGCRYPT_CONFIG_CFLAGS_PTHREAD@" -cflags_pth="@LIBGCRYPT_CONFIG_CFLAGS_PTH@" + +# API info +api_version="@LIBGCRYPT_CONFIG_API_VERSION@" # Misc information. symmetric_ciphers="@LIBGCRYPT_CIPHERS@" asymmetric_ciphers="@LIBGCRYPT_PUBKEY_CIPHERS@" digests="@LIBGCRYPT_DIGESTS@" -thread_modules="@LIBGCRYPT_THREAD_MODULES@" # State variables. -exec_prefix_set=no echo_libs=no echo_cflags=no echo_prefix=no echo_algorithms=no echo_exec_prefix=no echo_version=no +echo_api_version=no # Prints usage information. usage() @@ -48,10 +45,10 @@ usage() cat <<EOF Usage: $0 [OPTIONS] Options: - [--thread={${thread_modules}}] - [--prefix[=DIR]] - [--exec-prefix[=DIR]] + [--prefix] + [--exec-prefix] [--version] + [--api-version] [--libs] [--cflags] [--algorithms] @@ -77,34 +74,27 @@ while test $# -gt 0; do case $1 in --thread=*) - for thread_mod in $thread_modules; do - if test "$thread_mod" = "$optarg"; then - thread_module="$optarg"; - fi - done - if test "x$thread_module" = "x"; then - usage 1 1>&2 - fi - ;; - --prefix=*) - prefix=$optarg - if test $exec_prefix_set = no ; then - exec_prefix=$optarg - fi + echo "$0: --thread option obsolete: use the thread callback interface" 1>&2 + # exit 1 <-- enable this for 1.2.0. ;; + --prefix=*) + # For compatibility reasons with old M4 macros, we ignore + # setting of prefix. + ;; --prefix) echo_prefix=yes ;; - --exec-prefix=*) - exec_prefix=$optarg - exec_prefix_set=yes - ;; + --exec-prefix=*) + ;; --exec-prefix) echo_exec_prefix=yes ;; --version) echo_version=yes ;; + --api-version) + echo_api_version=yes + ;; --cflags) echo_cflags=yes ;; @@ -122,11 +112,11 @@ while test $# -gt 0; do done if test "$echo_prefix" = "yes"; then - echo $prefix + echo "$prefix" fi if test "$echo_exec_prefix" = "yes"; then - echo $exec_prefix + echo "$exec_prefix" fi if test "$echo_cflags" = "yes"; then @@ -134,26 +124,13 @@ if test "$echo_cflags" = "yes"; then cflags_final="$cflags" # Set up `includes'. - if test "@includedir@" != "/usr/include" ; then - includes="-I@includedir@" - for i in $cflags ; do - if test "$i" = "-I@includedir@" ; then - includes="" - fi - done + if test "x$includedir" != "x/usr/include" -a "x$includedir" != "x/include"; then + includes="-I$includedir" fi - # Set up `cflags_final'. - case "$thread_module" in - pthread) - cflags_final=$cflags_pthread - ;; - pth) - cflags_final=$cflags_pth - ;; - esac + cflags_final="$cflags_final $gpg_error_cflags" - echo "$includes" "$cflags_final" + echo "$includes $cflags_final" fi if test "$echo_libs" = "yes"; then @@ -161,34 +138,26 @@ if test "$echo_libs" = "yes"; then libs_final="$libs" # Set up `libdirs'. - if test "@libdir@" != "/usr/lib" ; then - libdirs="-L@libdir@" - for i in $libs ; do - if test "$i" = "-L@libdir@" ; then - libdirs="" - fi - done + if test "x$libdir" != "x/usr/lib" -a "x$libdir" != "x/lib"; then + libdirs="-L$libdir" fi # Set up `libs_final'. - case "$thread_module" in - pthread) - libs_final=$libs_pthread - ;; - pth) - libs_final=$libs_pth - ;; - esac + libs_final="$libs_final $gpg_error_libs" - echo $libdirs $libs_final + echo "$libdirs $libs_final" fi if test "$echo_version" = "yes"; then - echo $version + echo "$version" +fi + +if test "$echo_api_version" = "yes"; then + echo "$api_version" fi if test "$echo_algorithms" = "yes"; then - echo "Symmetric cipher algorithms: $ciphers" - echo "Public-key cipher algorithms: $pubkey_ciphers" + echo "Symmetric cipher algorithms: $symmetric_ciphers" + echo "Public-key cipher algorithms: $asymmetric_ciphers" echo "Message digest algorithms: $digests" fi diff --git a/src/libgcrypt.m4 b/src/libgcrypt.m4 index b57b5b33..20bd1055 100644 --- a/src/libgcrypt.m4 +++ b/src/libgcrypt.m4 @@ -1,5 +1,5 @@ dnl Autoconf macros for libgcrypt -dnl Copyright (C) 2002 Free Software Foundation, Inc. +dnl Copyright (C) 2002, 2004 Free Software Foundation, Inc. dnl dnl This file is free software; as a special exception the author gives dnl unlimited permission to copy and/or distribute it, with or without @@ -12,22 +12,35 @@ dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. dnl AM_PATH_LIBGCRYPT([MINIMUM-VERSION, dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) -dnl Test for liblibgcrypt and define LIBGCRYPT_CFLAGS and LIBGCRYPT_LIBS +dnl Test for libgcrypt and define LIBGCRYPT_CFLAGS and LIBGCRYPT_LIBS. +dnl MINIMUN-VERSION is a string with the version number optionalliy prefixed +dnl with the API version to also check the API compatibility. Example: +dnl a MINIMUN-VERSION of 1:1.2.5 won't pass the test unless the installed +dnl version of libgcrypt is at least 1.2.5 *and* the API number is 1. Using +dnl this features allows to prevent build against newer versions of libgcrypt +dnl with a changed API. dnl -AC_DEFUN(AM_PATH_LIBGCRYPT, +AC_DEFUN([AM_PATH_LIBGCRYPT], [ AC_ARG_WITH(libgcrypt-prefix, AC_HELP_STRING([--with-libgcrypt-prefix=PFX], [prefix where LIBGCRYPT is installed (optional)]), libgcrypt_config_prefix="$withval", libgcrypt_config_prefix="") if test x$libgcrypt_config_prefix != x ; then - libgcrypt_config_args="$libgcrypt_config_args --prefix=$libgcrypt_config_prefix" if test x${LIBGCRYPT_CONFIG+set} != xset ; then LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config fi fi AC_PATH_PROG(LIBGCRYPT_CONFIG, libgcrypt-config, no) - min_libgcrypt_version=ifelse([$1], ,0.4.4,$1) + tmp=ifelse([$1], ,1:1.2.0,$1) + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_libgcrypt_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_libgcrypt_api=0 + min_libgcrypt_version="$tmp" + fi + AC_MSG_CHECKING(for LIBGCRYPT - version >= $min_libgcrypt_version) ok=no if test "$LIBGCRYPT_CONFIG" != "no" ; then @@ -37,7 +50,7 @@ AC_DEFUN(AM_PATH_LIBGCRYPT, sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` req_micro=`echo $min_libgcrypt_version | \ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` - libgcrypt_config_version=`$LIBGCRYPT_CONFIG $libgcrypt_config_args --version` + libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version` major=`echo $libgcrypt_config_version | \ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` minor=`echo $libgcrypt_config_version | \ @@ -61,14 +74,33 @@ AC_DEFUN(AM_PATH_LIBGCRYPT, fi fi if test $ok = yes; then - LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG $libgcrypt_config_args --cflags` - LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG $libgcrypt_config_args --libs` AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + if test $ok = yes; then + # If we have a recent libgcrypt, we should also check that the + # API is compatible + if test "$req_libgcrypt_api" -gt 0 ; then + tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0` + if test "$tmp" -gt 0 ; then + AC_MSG_CHECKING([LIBGCRYPT API version]) + if test "$req_libgcrypt_api" -eq "$tmp" ; then + AC_MSG_RESULT(okay) + else + ok=no + AC_MSG_RESULT([does not match (want=$req_libgcrypt_api got=$tmp)]) + fi + fi + fi + fi + if test $ok = yes; then + LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags` + LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs` ifelse([$2], , :, [$2]) else LIBGCRYPT_CFLAGS="" LIBGCRYPT_LIBS="" - AC_MSG_RESULT(no) ifelse([$3], , :, [$3]) fi AC_SUBST(LIBGCRYPT_CFLAGS) @@ -23,7 +23,6 @@ #include <stdlib.h> #include <string.h> #include <stdarg.h> -#include <assert.h> #include <unistd.h> #include "g10lib.h" @@ -66,14 +65,14 @@ write2stderr( const char *s ) write( 2, s, strlen(s) ); } -/**************** +/* * This function is called for fatal errors. A caller might want to - * set his own handler becuase this function simply calls abort(). + * set his own handler because this function simply calls abort(). */ void _gcry_fatal_error (int rc, const char *text) { - if (! text) /* get a default text */ + if ( !text ) /* get a default text */ text = gpg_strerror (rc); if (fatal_error_handler) @@ -86,10 +85,10 @@ _gcry_fatal_error (int rc, const char *text) } void -gcry_set_log_handler( void (*logf)(void*,int, const char*, va_list ), +gcry_set_log_handler( void (*f)(void*,int, const char*, va_list ), void *opaque ) { - log_handler = logf; + log_handler = f; log_handler_value = opaque; } @@ -234,7 +233,7 @@ _gcry_burn_stack (int bytes) { char buf[64]; - memset (buf, 0, sizeof buf); + wipememory (buf, sizeof buf); bytes -= sizeof buf; if (bytes > 0) _gcry_burn_stack (bytes); diff --git a/src/missing-string.c b/src/missing-string.c index b648d292..80ff0521 100644 --- a/src/missing-string.c +++ b/src/missing-string.c @@ -1,5 +1,6 @@ /* missing-string.c - missing string utilities - * Copyright (C) 1994, 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc. + * Copyright (C) 1994, 1998, 1999, 2000, 2001, + * 2003 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * diff --git a/src/module.c b/src/module.c index 4e2a7f1e..69a79306 100644 --- a/src/module.c +++ b/src/module.c @@ -18,11 +18,12 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#include <assert.h> #include <config.h> #include <errno.h> #include "g10lib.h" +#define MODULE_ID_MIN 600 + /* Internal function. Generate a new, unique module ID for a module that should be inserted into the module chain starting at MODULES. */ @@ -31,7 +32,7 @@ _gcry_module_id_new (gcry_module_t modules, unsigned int *id_new) { /* FIXME, what should be the ID of the first module registered by the user? */ - unsigned int id_min = 600, id_max = (unsigned int) -1, mod_id; + unsigned int id_min = MODULE_ID_MIN, id_max = (unsigned int) -1, mod_id; gcry_err_code_t err = GPG_ERR_NO_ERROR; gcry_module_t module; @@ -171,36 +172,28 @@ _gcry_module_use (gcry_module_t module) according size. In case there are less cipher modules than *LIST_LENGTH, *LIST_LENGTH is updated to the correct number. */ gcry_err_code_t -_gcry_module_list (gcry_module_t modules, int **list, int *list_length) +_gcry_module_list (gcry_module_t modules, + int *list, int *list_length) { gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_module_t module = NULL; - unsigned int modules_n = 0; - int *list_new = NULL; - unsigned int i = 0; + gcry_module_t module; + int length, i; - for (module = modules; module; module = module->next) - modules_n++; + for (module = modules, length = 0; module; module = module->next, length++); - if (modules_n && list) + if (list) { - list_new = gcry_malloc (sizeof (*list_new) * modules_n); - if (! list_new) - err = gpg_err_code_from_errno (ENOMEM); - else - { - for (module = modules, i = 0; i < modules_n; module = module->next, i++) - list_new[i] = module->mod_id; - } - } + if (length > *list_length) + length = *list_length; - if (! err) - { - if (list) - *list = list_new; - if (list_length) - *list_length = modules_n; + for (module = modules, i = 0; i < length; module = module->next, i++) + list[i] = module->mod_id; + + if (length < *list_length) + *list_length = length; } + else + *list_length = length; return err; } diff --git a/src/secmem.c b/src/secmem.c index 0d038ae3..81360b99 100644 --- a/src/secmem.c +++ b/src/secmem.c @@ -1,5 +1,6 @@ /* secmem.c - memory allocation from a secure heap - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, + * 2003 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * @@ -176,11 +177,11 @@ mb_merge (memblock_t *mb) /* Return a new block, which can hold SIZE bytes. */ static memblock_t * -mb_get_new (memblock_t *pool, size_t size) +mb_get_new (memblock_t *block, size_t size) { memblock_t *mb, *mb_split; - for (mb = pool; BLOCK_VALID (mb); mb = mb_get_next (mb)) + for (mb = block; BLOCK_VALID (mb); mb = mb_get_next (mb)) if (! (mb->flags & MB_FLAG_ACTIVE) && mb->size >= size) { /* Found a free block. */ @@ -233,12 +234,15 @@ lock_pool (void *p, size_t n) if (err) { if (errno != EPERM -#ifdef EAGAIN /* OpenBSD returns this */ +#ifdef EAGAIN /* OpenBSD returns this */ && errno != EAGAIN #endif -#ifdef ENOSYS /* Some SCOs return this (function not implemented) */ +#ifdef ENOSYS /* Some SCOs return this (function not implemented) */ && errno != ENOSYS #endif +#ifdef ENOMEM /* Linux might return this. */ + && errno != ENOMEM +#endif ) log_error ("can't lock memory: %s\n", strerror (err)); show_warning = 1; @@ -251,6 +255,10 @@ lock_pool (void *p, size_t n) uid = getuid (); #ifdef HAVE_BROKEN_MLOCK + /* Under HP/UX mlock segfaults if called by non-root. Note, we have + noch checked whether mlock does really work under AIX where we + also detected a broken nlock. Note further, that using plock () + is not a good idea under AIX. */ if (uid) { errno = EPERM; @@ -262,11 +270,11 @@ lock_pool (void *p, size_t n) if (err && errno) err = errno; } -#else +#else /* !HAVE_BROKEN_MLOCK */ err = mlock (p, n); if (err && errno) err = errno; -#endif +#endif /* !HAVE_BROKEN_MLOCK */ if (uid && ! geteuid ()) { @@ -279,12 +287,15 @@ lock_pool (void *p, size_t n) if (err) { if (errno != EPERM -#ifdef EAGAIN /* OpenBSD returns this */ +#ifdef EAGAIN /* OpenBSD returns this. */ && errno != EAGAIN #endif -#ifdef ENOSYS /* Some SCOs return this (function not implemented) */ +#ifdef ENOSYS /* Some SCOs return this (function not implemented). */ && errno != ENOSYS #endif +#ifdef ENOMEM /* Linux might return this. */ + && errno != ENOMEM +#endif ) log_error ("can't lock memory: %s\n", strerror (err)); show_warning = 1; @@ -296,6 +307,15 @@ lock_pool (void *p, size_t n) * wipes out the memory on a free(). * Therefore it is sufficient to suppress the warning */ +#elif defined (HAVE_DOSISH_SYSTEM) || defined (__CYGWIN__) + /* It does not make sense to print such a warning, given the fact that + * this whole Windows !@#$% and their user base are inherently insecure + */ +#elif defined (__riscos__) + /* no virtual memory on RISC OS, so no pages are swapped to disc, + * besides we don't have mmap, so we don't use it! ;-) + * But don't complain, as explained above. + */ #else log_info ("Please note that you don't have secure memory on this system\n"); #endif @@ -433,13 +453,10 @@ _gcry_secmem_init (size_t n) { if (n < DEFAULT_POOL_SIZE) n = DEFAULT_POOL_SIZE; - if (! pool_okay) + if (!pool_okay) { init_pool (n); - if (! geteuid ()) - lock_pool (pool, n); - else - log_info ("Secure memory is not locked into core\n"); + lock_pool (pool, n); } else log_error ("Oops, secure memory pool already initialized\n"); @@ -457,8 +474,7 @@ _gcry_secmem_malloc_internal (size_t size) if (!pool_okay) { log_info (_ - ("operation is not possible without initialized secure memory\n")); - log_info (_("(you may have used the wrong program for this task)\n")); + ("operation is not possible without initialized secure memory\n")); exit (2); } if (show_warning && !suspend_warning) @@ -467,7 +483,7 @@ _gcry_secmem_malloc_internal (size_t size) print_warn (); } - /* blocks are always a multiple of 32 */ + /* Blocks are always a multiple of 32. */ size = ((size + 31) / 32) * 32; mb = mb_get_new ((memblock_t *) pool, size); @@ -542,13 +558,19 @@ _gcry_secmem_realloc (void *p, size_t newsize) mb = (memblock_t *) ((char *) p - ((size_t) &((memblock_t *) 0)->aligned.c)); size = mb->size; if (newsize < size) - return p; /* it is easier not to shrink the memory */ - a = _gcry_secmem_malloc_internal (newsize); - if (a) { - memcpy (a, p, size); - memset ((char *) a + size, 0, newsize - size); - _gcry_secmem_free_internal (p); + /* It is easier to not shrink the memory. */ + a = p; + } + else + { + a = _gcry_secmem_malloc_internal (newsize); + if (a) + { + memcpy (a, p, size); + memset ((char *) a + size, 0, newsize - size); + _gcry_secmem_free_internal (p); + } } SECMEM_UNLOCK; @@ -586,10 +608,10 @@ _gcry_secmem_term () if (!pool_okay) return; - memset (pool, 0xff, pool_size); - memset (pool, 0xaa, pool_size); - memset (pool, 0x55, pool_size); - memset (pool, 0x00, pool_size); + wipememory2 (pool, 0xff, pool_size); + wipememory2 (pool, 0xaa, pool_size); + wipememory2 (pool, 0x55, pool_size); + wipememory2 (pool, 0x00, pool_size); #if HAVE_MMAP if (pool_is_mmapped) munmap (pool, pool_size); @@ -607,8 +629,8 @@ _gcry_secmem_dump_stats () SECMEM_LOCK; if (pool_okay) - log_info ("secmem usage: %u/%u bytes in %u blocks\n", - cur_alloced, pool_size, cur_blocks); + log_info ("secmem usage: %u/%lu bytes in %u blocks\n", + cur_alloced, (unsigned long)pool_size, cur_blocks); SECMEM_UNLOCK; #else memblock_t *mb; diff --git a/src/secmem.h b/src/secmem.h index 54e16ba0..a0831968 100644 --- a/src/secmem.h +++ b/src/secmem.h @@ -28,11 +28,11 @@ void *_gcry_secmem_realloc (void *a, size_t newsize); void _gcry_secmem_free (void *a); void _gcry_secmem_dump_stats (void); void _gcry_secmem_set_flags (unsigned flags); -unsigned _gcry_secmem_get_flags(void) GCC_ATTR_PURE; -int _gcry_private_is_secure (const void *p) GCC_ATTR_PURE; +unsigned _gcry_secmem_get_flags(void); +int _gcry_private_is_secure (const void *p); /* Flags for _gcry_secmem_{set,get}_flags. */ -#define GCRY_SECMEM_FLAG_NO_WARNING 1 << 0 -#define GCRY_SECMEM_FLAG_SUSPEND_WARNING 1 << 1 +#define GCRY_SECMEM_FLAG_NO_WARNING (1 << 0) +#define GCRY_SECMEM_FLAG_SUSPEND_WARNING (1 << 1) #endif /* G10_SECMEM_H */ @@ -1,5 +1,6 @@ /* sexp.c - S-Expression handling - * Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + * Copyright (C) 1999, 2000, 2001, 2002, 2003, + * 2004 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * @@ -25,7 +26,6 @@ #include <string.h> #include <stdarg.h> #include <ctype.h> -#include <assert.h> #define GCRYPT_NO_MPI_MACROS 1 #include "g10lib.h" @@ -245,7 +245,39 @@ gcry_sexp_new (gcry_sexp_t *retsexp, const void *buffer, size_t length, void gcry_sexp_release( gcry_sexp_t sexp ) { - gcry_free ( sexp ); + if (sexp) + { + if (gcry_is_secure (sexp)) + { + /* Extra paranoid wiping. */ + const byte *p = sexp->d; + int type; + + while ( (type = *p) != ST_STOP ) + { + p++; + switch ( type ) + { + case ST_OPEN: + break; + case ST_CLOSE: + break; + case ST_DATA: + { + DATALEN n; + memcpy ( &n, p, sizeof n ); + p += sizeof n; + p += n; + } + break; + default: + break; + } + } + wipememory (sexp->d, p - sexp->d); + } + gcry_free ( sexp ); + } } @@ -257,22 +289,24 @@ gcry_sexp_release( gcry_sexp_t sexp ) gcry_sexp_t gcry_sexp_cons( const gcry_sexp_t a, const gcry_sexp_t b ) { - /* NYI: Implementation should be quite easy with our new data representation */ - BUG (); - return NULL; + /* 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 + * with a NULL. */ gcry_sexp_t gcry_sexp_alist( const gcry_sexp_t *array ) { - /* NYI: Implementaion should be quite easy with our new data representation */ - BUG (); - return NULL; + /* NYI: Implementation should be quite easy with our new data + representation. */ + BUG (); + return NULL; } /**************** @@ -281,9 +315,10 @@ gcry_sexp_alist( const gcry_sexp_t *array ) gcry_sexp_t gcry_sexp_vlist( const gcry_sexp_t a, ... ) { - /* NYI: Implementaion should be quite easy with our new data representation */ - BUG (); - return NULL; + /* NYI: Implementation should be quite easy with our new data + representation. */ + BUG (); + return NULL; } @@ -294,17 +329,19 @@ gcry_sexp_vlist( const gcry_sexp_t a, ... ) gcry_sexp_t gcry_sexp_append( const gcry_sexp_t a, const gcry_sexp_t n ) { - /* NYI: Implementaion should be quite easy with our new data representation */ - BUG (); - return NULL; + /* NYI: Implementation should be quite easy with our new data + representation. */ + BUG (); + return NULL; } gcry_sexp_t gcry_sexp_prepend( const gcry_sexp_t a, const gcry_sexp_t n ) { - /* NYI: Implementaion should be quite easy with our new data representation */ - BUG (); - return NULL; + /* NYI: Implementation should be quite easy with our new data + representation. */ + BUG (); + return NULL; } @@ -823,13 +860,15 @@ unquote_string (const unsigned char *string, size_t length, unsigned char *buf) * %m - MPI * %s - string (no autoswitch to secure allocation) * %d - integer stored as string (no autoswitch to secure allocation) + * %b - memory buffer; this takes _two_ arguments: an integer with the + * length of the buffer and a pointer to the buffer. * 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 + * 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, that if only one element is secure, all - * other elements are automagicaly copied to secure meory too, so the most + * other elements are automagicaly copied to secure memory too, so the most * common operation gcry_sexp_cdr_mpi() will always return a secure MPI * regardless whether it is needed or not. */ @@ -838,10 +877,11 @@ sexp_sscan (gcry_sexp_t *retsexp, size_t *erroff, const char *buffer, size_t length, int argflag, va_list arg_ptr, void **arg_list) { - static const char tokenchars[] = "\ -abcdefghijklmnopqrstuvwxyz\ -ABCDEFGHIJKLMNOPQRSTUVWXYZ\ -0123456789-./_:*+="; + gcry_err_code_t err = GPG_ERR_NO_ERROR; + static const char tokenchars[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789-./_:*+="; const char *p; size_t n; const char *digptr = NULL; @@ -857,13 +897,16 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ\ size_t dummy_erroff; struct make_space_ctx c; int arg_counter = 0; + int level = 0; + + /* FIXME: invent better error codes (?). */ if (! erroff) erroff = &dummy_erroff; /* Depending on wether ARG_LIST is non-zero or not, this macro gives us the next argument, either from the variable argument list as - specified by ARG_PTR or from the arugment array ARG_LIST. */ + specified by ARG_PTR or from the argument array ARG_LIST. */ #define ARG_NEXT(storage, type) \ do \ { \ @@ -874,8 +917,6 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ\ } \ while (0) - /* 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 { make_space ( &c, (n) ); } while (0) #define STORE_LEN(p,n) do { \ DATALEN ashort = (n); \ @@ -887,303 +928,421 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ\ * 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 */ c.allocated = length + sizeof(DATALEN); - c.sexp = gcry_xmalloc ( sizeof *c.sexp + c.allocated - 1 ); + if (buffer && length && gcry_is_secure (buffer)) + c.sexp = gcry_xmalloc_secure (sizeof *c.sexp + c.allocated - 1); + else + c.sexp = gcry_xmalloc (sizeof *c.sexp + c.allocated - 1); c.pos = c.sexp->d; - for(p=buffer,n=length; n; p++, n-- ) { - if( tokenp && !hexfmt ) { - if( strchr( tokenchars, *p ) ) - continue; - datalen = p - tokenp; - MAKE_SPACE ( datalen ); - *c.pos++ = ST_DATA; - STORE_LEN ( c.pos, datalen ); - memcpy ( c.pos, tokenp, datalen ); - c.pos += datalen; - tokenp = NULL; - } - if( quoted ) { - if( quoted_esc ) { - switch( *p ) { - case 'b': case 't': case 'v': case 'n': case 'f': - case 'r': case '"': case '\'': case '\\': - quoted_esc = 0; - break; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': - if( !(n > 2 && p[1] >= '0' && p[1] <= '7' - && p[2] >= '0' && p[2] <= '7') ) { - *erroff = p - buffer; - /* Invalid octal value. */ - return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION); - } - p += 2; n -= 2; - quoted_esc = 0; - break; - case 'x': - if( !(n > 2 && isxdigit(p[1]) && isxdigit(p[2]) ) ) { - *erroff = p - buffer; - /* Invalid hex value. */ - return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION); - } - p += 2; n -= 2; - quoted_esc = 0; - break; - case '\r': /* ignore CR[,LF] */ - if( n && p[1] == '\n' ) { - p++; n--; - } - quoted_esc = 0; - break; - case '\n': /* ignore LF[,CR] */ - if( n && p[1] == '\r' ) { - p++; n--; - } - quoted_esc = 0; - break; - default: - *erroff = p - buffer; - /* Invalid quoted string escape. */ - return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION); + for (p = buffer, n = length; n; p++, n--) + { + if (tokenp && (! hexfmt)) + { + if (strchr (tokenchars, *p)) + continue; + else + { + datalen = p - tokenp; + MAKE_SPACE (datalen); + *c.pos++ = ST_DATA; + STORE_LEN (c.pos, datalen); + memcpy (c.pos, tokenp, datalen); + c.pos += datalen; + tokenp = NULL; + } } - } - else if( *p == '\\' ) - quoted_esc = 1; - else if( *p == '\"' ) { - /* keep it easy - we know that the unquoted string will - never be larger */ - char *save; - size_t len; - - quoted++; /* skip leading quote */ - MAKE_SPACE (p - quoted); - *c.pos++ = ST_DATA; - save = c.pos; - STORE_LEN (c.pos, 0); /* will be fixed up later */ - len = unquote_string (quoted, p - quoted, c.pos); - c.pos += len; - STORE_LEN (save, len); - quoted = NULL; - } - } - else if( hexfmt ) { - if( isxdigit( *p ) ) - hexcount++; - else if( *p == '#' ) { - if( (hexcount & 1) ) { - *erroff = p - buffer; - return gcry_error (GPG_ERR_SEXP_ODD_HEX_NUMBERS); + + if (quoted) + { + if (quoted_esc) + { + switch (*p) + { + case 'b': case 't': case 'v': case 'n': case 'f': + case 'r': case '"': case '\'': case '\\': + quoted_esc = 0; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + if (! ((n > 2) + && (p[1] >= '0') && (p[1] <= '7') + && (p[2] >= '0') && (p[2] <= '7'))) + { + *erroff = p - buffer; + /* Invalid octal value. */ + err = GPG_ERR_SEXP_BAD_QUOTATION; + } + p += 2; + n -= 2; + quoted_esc = 0; + break; + + case 'x': + if (! ((n > 2) && isxdigit(p[1]) && isxdigit(p[2]))) + { + *erroff = p - buffer; + /* Invalid hex value. */ + err = GPG_ERR_SEXP_BAD_QUOTATION; + } + p += 2; + n -= 2; + quoted_esc = 0; + break; + + case '\r': + /* ignore CR[,LF] */ + if (n && (p[1] == '\n')) + { + p++; + n--; + } + quoted_esc = 0; + break; + + case '\n': + /* ignore LF[,CR] */ + if (n && (p[1] == '\r')) + { + p++; + n--; + } + quoted_esc = 0; + break; + + default: + *erroff = p - buffer; + /* Invalid quoted string escape. */ + err = GPG_ERR_SEXP_BAD_QUOTATION; + } + } + else if (*p == '\\') + quoted_esc = 1; + else if (*p == '\"') + { + /* Keep it easy - we know that the unquoted string will + never be larger. */ + char *save; + size_t len; + + quoted++; /* Skip leading quote. */ + MAKE_SPACE (p - quoted); + *c.pos++ = ST_DATA; + save = c.pos; + STORE_LEN (c.pos, 0); /* Will be fixed up later. */ + len = unquote_string (quoted, p - quoted, c.pos); + c.pos += len; + STORE_LEN (save, len); + quoted = NULL; + } + } + else if (hexfmt) + { + if (isxdigit (*p)) + hexcount++; + else if (*p == '#') + { + if ((hexcount & 1)) + { + *erroff = p - buffer; + err = GPG_ERR_SEXP_ODD_HEX_NUMBERS; + } + + datalen = hexcount / 2; + MAKE_SPACE (datalen); + *c.pos++ = ST_DATA; + STORE_LEN (c.pos, datalen); + for (hexfmt++; hexfmt < p; hexfmt++) + { + if (isspace (*hexfmt)) + continue; + *c.pos++ = hextobyte (hexfmt); + hexfmt++; + } + hexfmt = NULL; + } + else if (! isspace (*p)) + { + *erroff = p - buffer; + err = GPG_ERR_SEXP_BAD_HEX_CHAR; + } } + else if (base64) + { + if (*p == '|') + base64 = NULL; + } + else if (digptr) + { + if (isdigit (*p)) + ; + else if (*p == ':') + { + datalen = atoi (digptr); /* FIXME: check for overflow. */ + digptr = NULL; + if (datalen > n - 1) + { + *erroff = p - buffer; + /* Buffer too short. */ + err = GPG_ERR_SEXP_STRING_TOO_LONG; + } + /* Make a new list entry. */ + MAKE_SPACE (datalen); + *c.pos++ = ST_DATA; + STORE_LEN (c.pos, datalen); + memcpy (c.pos, p + 1, datalen); + c.pos += datalen; + n -= datalen; + p += datalen; + } + else if (*p == '\"') + { + digptr = NULL; /* We ignore the optional length. */ + quoted = p; + quoted_esc = 0; + } + else if (*p == '#') + { + digptr = NULL; /* We ignore the optional length. */ + hexfmt = p; + hexcount = 0; + } + else if (*p == '|') + { + digptr = NULL; /* We ignore the optional length. */ + base64 = p; + } + else + { + *erroff = p - buffer; + err = GPG_ERR_SEXP_INV_LEN_SPEC; + } + } + else if (percent) + { + if (*p == 'm') + { + /* Insert an MPI. */ + gcry_mpi_t m; + size_t nm = 0; + + ARG_NEXT (m, gcry_mpi_t); + + if (gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &nm, m)) + BUG (); - datalen = hexcount/2; - MAKE_SPACE (datalen); - *c.pos++ = ST_DATA; - STORE_LEN (c.pos, datalen); - for( hexfmt++; hexfmt < p; hexfmt++ ) { - if( isspace( *hexfmt ) ) - continue; - *c.pos++ = hextobyte( hexfmt ); - hexfmt++; + MAKE_SPACE (nm); + if ((! gcry_is_secure (c.sexp->d)) + && gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE)) + { + /* We have to switch to secure allocation. */ + gcry_sexp_t newsexp; + byte *newhead; + + newsexp = gcry_xmalloc_secure (sizeof *newsexp + + c.allocated - 1); + newhead = newsexp->d; + memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d)); + c.pos = newhead + (c.pos - c.sexp->d); + gcry_free (c.sexp); + c.sexp = newsexp; + } + + *c.pos++ = ST_DATA; + STORE_LEN (c.pos, nm); + if (gcry_mpi_print (GCRYMPI_FMT_STD, c.pos, nm, &nm, m)) + BUG (); + c.pos += nm; + } + else if (*p == 's') + { + /* Insert an string. */ + const char *astr; + size_t alen; + + ARG_NEXT (astr, const char *); + alen = strlen (astr); + + MAKE_SPACE (alen); + *c.pos++ = ST_DATA; + STORE_LEN (c.pos, alen); + memcpy (c.pos, astr, alen); + c.pos += alen; + } + else if (*p == 'b') + { + /* Insert a memory buffer. */ + const char *astr; + int alen; + + ARG_NEXT (alen, int); + ARG_NEXT (astr, const char *); + + MAKE_SPACE (alen); + if (alen + && !gcry_is_secure (c.sexp->d) + && gcry_is_secure (astr)) + { + /* We have to switch to secure allocation. */ + gcry_sexp_t newsexp; + byte *newhead; + + newsexp = gcry_xmalloc_secure (sizeof *newsexp + + c.allocated - 1); + newhead = newsexp->d; + memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d)); + c.pos = newhead + (c.pos - c.sexp->d); + gcry_free (c.sexp); + c.sexp = newsexp; + } + + *c.pos++ = ST_DATA; + STORE_LEN (c.pos, alen); + memcpy (c.pos, astr, alen); + c.pos += alen; + } + else if (*p == 'd') + { + /* Insert an integer as string. */ + int aint; + size_t alen; + char buf[20]; + + ARG_NEXT (aint, int); + sprintf (buf, "%d", aint); + alen = strlen (buf); + MAKE_SPACE (alen); + *c.pos++ = ST_DATA; + STORE_LEN (c.pos, alen); + memcpy (c.pos, buf, alen); + c.pos += alen; + } + else + { + *erroff = p - buffer; + /* Invalid format specifier. */ + err = GPG_ERR_SEXP_INV_LEN_SPEC; + } + percent = NULL; } - hexfmt = NULL; - } - else if( !isspace( *p ) ) { - *erroff = p - buffer; - return gcry_error (GPG_ERR_SEXP_BAD_HEX_CHAR); - } - } - else if( base64 ) { - if( *p == '|' ) - base64 = NULL; - } - else if( digptr ) { - if( isdigit(*p) ) + else if (*p == '(') + { + if (disphint) + { + *erroff = p - buffer; + /* Open display hint. */ + err = GPG_ERR_SEXP_UNMATCHED_DH; + } + MAKE_SPACE (0); + *c.pos++ = ST_OPEN; + level++; + } + else if (*p == ')') + { + /* Walk up. */ + if (disphint) + { + *erroff = p - buffer; + /* Open display hint. */ + err = GPG_ERR_SEXP_UNMATCHED_DH; + } + MAKE_SPACE (0); + *c.pos++ = ST_CLOSE; + level--; + } + else if (*p == '\"') + { + quoted = p; + quoted_esc = 0; + } + else if (*p == '#') + { + hexfmt = p; + hexcount = 0; + } + else if (*p == '|') + base64 = p; + else if (*p == '[') + { + if (disphint) + { + *erroff = p - buffer; + /* Open display hint. */ + err = GPG_ERR_SEXP_NESTED_DH; + } + disphint = p; + } + else if (*p == ']') + { + if (! disphint) + { + *erroff = p - buffer; + /* Open display hint. */ + err = GPG_ERR_SEXP_UNMATCHED_DH; + } + disphint = NULL; + } + else if (isdigit (*p)) + { + if (*p == '0') + { + /* A length may not begin with zero. */ + *erroff = p - buffer; + err = GPG_ERR_SEXP_ZERO_PREFIX; + } + digptr = p; + } + else if (strchr (tokenchars, *p)) + tokenp = p; + else if (isspace (*p)) ; - else if( *p == ':' ) { - datalen = atoi( digptr ); /* fixme: check for overflow */ - digptr = NULL; - if( datalen > n-1 ) { + else if (*p == '{') + { + /* fixme: handle rescanning: we can do this by saving our + current state and start over at p+1 -- Hmmm. At this + point here we are in a well defined state, so we don't + need to save it. Great. */ *erroff = p - buffer; - /* Buffer too short. */ - return gcry_error (GPG_ERR_SEXP_STRING_TOO_LONG); + err = GPG_ERR_SEXP_UNEXPECTED_PUNC; } - /* make a new list entry */ - MAKE_SPACE (datalen); - *c.pos++ = ST_DATA; - STORE_LEN (c.pos, datalen); - memcpy (c.pos, p+1, datalen ); - c.pos += datalen; - n -= datalen; - p += datalen; - } - else if( *p == '\"' ) { - digptr = NULL; /* we ignore the optional length */ - quoted = p; - quoted_esc = 0; - } - else if( *p == '#' ) { - digptr = NULL; /* we ignore the optional length */ - hexfmt = p; - hexcount = 0; - } - else if( *p == '|' ) { - digptr = NULL; /* we ignore the optional length */ - base64 = p; - } - else { - *erroff = p - buffer; - return gcry_error (GPG_ERR_SEXP_INV_LEN_SPEC); - } - } - else if ( percent ) { - if ( *p == 'm' ) { /* insert an MPI */ - gcry_mpi_t m; - size_t nm = 0; - - ARG_NEXT (m, gcry_mpi_t); - - if ( gcry_mpi_print( GCRYMPI_FMT_STD, NULL, 0, &nm, m ) ) - BUG (); - - MAKE_SPACE (nm); - if ( !gcry_is_secure ( c.sexp->d ) - && gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE ) ) { - /* we have to switch to secure allocation */ - gcry_sexp_t newsexp; - byte *newhead; - - newsexp = gcry_xmalloc_secure ( sizeof *newsexp - + c.allocated - 1 ); - newhead = newsexp->d; - memcpy ( newhead, c.sexp->d, (c.pos - c.sexp->d) ); - c.pos = newhead + ( c.pos - c.sexp->d ); - gcry_free ( c.sexp ); - c.sexp = newsexp; + else if (strchr ("&\\", *p)) + { + /* Reserved punctuation. */ + *erroff = p - buffer; + err = GPG_ERR_SEXP_UNEXPECTED_PUNC; + } + else if (argflag && (*p == '%')) + percent = p; + else + { + /* Bad or unavailable. */ + *erroff = p - buffer; + err = GPG_ERR_SEXP_BAD_CHARACTER; } - - *c.pos++ = ST_DATA; - STORE_LEN (c.pos, nm); - if ( gcry_mpi_print( GCRYMPI_FMT_STD, c.pos, nm, &nm, m ) ) - BUG (); - c.pos += nm; - } - else if ( *p == 's' ) { /* insert an string */ - const char *astr; - size_t alen; - - ARG_NEXT (astr, const char *); - alen = strlen (astr); - - MAKE_SPACE (alen); - *c.pos++ = ST_DATA; - STORE_LEN (c.pos, alen); - memcpy ( c.pos, astr, alen ); - c.pos += alen; - } - else if ( *p == 'd' ) { /* insert an integer as string */ - int aint; - size_t alen; - char buf[20]; - - ARG_NEXT (aint, int); - sprintf ( buf, "%d", aint ); - alen = strlen ( buf ); - MAKE_SPACE (alen); - *c.pos++ = ST_DATA; - STORE_LEN (c.pos, alen); - memcpy ( c.pos, buf, alen ); - c.pos += alen; - } - else { - *erroff = p - buffer; - /* Invalid format specifier. */ - return gcry_error (GPG_ERR_SEXP_INV_LEN_SPEC); - } - percent = NULL; - } - else if( *p == '(' ) { - if( disphint ) { - *erroff = p - buffer; - /* Open display hint. */ - return gcry_error (GPG_ERR_SEXP_UNMATCHED_DH); - } - MAKE_SPACE (0); - *c.pos++ = ST_OPEN; - } - else if( *p == ')' ) { /* walk up */ - if( disphint ) { - *erroff = p - buffer; - /* Open display hint. */ - return gcry_error (GPG_ERR_SEXP_UNMATCHED_DH); - } - MAKE_SPACE (0); - *c.pos++ = ST_CLOSE; - } - else if( *p == '\"' ) { - quoted = p; - quoted_esc = 0; - } - else if( *p == '#' ) { - hexfmt = p; - hexcount = 0; - } - else if( *p == '|' ) - base64 = p; - else if( *p == '[' ) { - if( disphint ) { - *erroff = p - buffer; - /* Open display hint. */ - return gcry_error (GPG_ERR_SEXP_NESTED_DH); - } - disphint = p; - } - else if( *p == ']' ) { - if( !disphint ) { - *erroff = p - buffer; - /* Open display hint. */ - return gcry_error (GPG_ERR_SEXP_UNMATCHED_DH); - } - disphint = NULL; - } - else if( isdigit(*p) ) { - if( *p == '0' ) { /* a length may not begin with zero */ - *erroff = p - buffer; - return gcry_error (GPG_ERR_SEXP_ZERO_PREFIX); - } - digptr = p; - } - else if( strchr( tokenchars, *p ) ) - tokenp = p; - else if( isspace(*p) ) - ; - else if( *p == '{' ) { - /* fixme: handle rescanning: - * we can do this by saving our current state - * and start over at p+1 -- Hmmm. At this point here - * we are in a well defined state, so we don't need to save - * it. Great. - */ - *erroff = p - buffer; - return gcry_error (GPG_ERR_SEXP_UNEXPECTED_PUNC); - } - else if( strchr( "&\\", *p ) ) { /*reserved punctuation*/ - *erroff = p - buffer; - return gcry_error (GPG_ERR_SEXP_UNEXPECTED_PUNC); - } - else if( argflag && *p == '%' ) { - percent = p; - } - else { /* bad or unavailable*/ - *erroff = p - buffer; - return gcry_error (GPG_ERR_SEXP_BAD_CHARACTER); } - - } MAKE_SPACE (0); *c.pos++ = ST_STOP; - *retsexp = normalize ( c.sexp ); - return gcry_error (GPG_ERR_NO_ERROR); + if (level) + err = GPG_ERR_SEXP_UNMATCHED_PAREN; + + if (err) + { + /* Error -> deallocate. */ + if (c.sexp) + { + /* Extra paranoid wipe on error. */ + if (gcry_is_secure (c.sexp)) + wipememory (c.sexp, sizeof (struct gcry_sexp) + c.allocated - 1); + gcry_free (c.sexp); + } + /* This might be expected by existing code... */ + *retsexp = NULL; + } + else + *retsexp = normalize (c.sexp); + + return gcry_error (err); #undef MAKE_SPACE #undef STORE_LEN } |