summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ath.c172
-rw-r--r--src/ath.h92
-rw-r--r--src/cipher.h66
-rw-r--r--src/global.c154
-rw-r--r--src/libgcrypt-config.in109
-rw-r--r--src/libgcrypt.m450
-rw-r--r--src/misc.c13
-rw-r--r--src/missing-string.c3
-rw-r--r--src/module.c43
-rw-r--r--src/secmem.c80
-rw-r--r--src/secmem.h8
-rw-r--r--src/sexp.c781
12 files changed, 994 insertions, 577 deletions
diff --git a/src/ath.c b/src/ath.c
index 36d896ef..6788bbaa 100644
--- a/src/ath.c
+++ b/src/ath.c
@@ -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);
}
diff --git a/src/ath.h b/src/ath.h
index 9514af86..d492c2a3 100644
--- a/src/ath.h
+++ b/src/ath.h
@@ -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)
diff --git a/src/misc.c b/src/misc.c
index 8af686f4..20bf2e61 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -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 */
diff --git a/src/sexp.c b/src/sexp.c
index 5de4c8c5..33bb912d 100644
--- a/src/sexp.c
+++ b/src/sexp.c
@@ -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
}