1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-01-25 15:27:03 +01:00

2004-07-27 Moritz Schulte <moritz@g10code.com>

* command-ssh.c: Use gcrypt memory allocators, use secure memory
	where necessary.

2004-07-26  Moritz Schulte  <moritz@g10code.com>

	* command-ssh.c (data_sign): Do not forget to unsigned char when
	constructing human-readable key grip.

	* Makefile.am (gpg_agent_SOURCES): Removed: buffer.c, buffer.h;
	updated Libgpg-stream.
This commit is contained in:
Moritz Schulte 2004-07-26 23:01:19 +00:00
parent da2899b712
commit 809b77941f
5 changed files with 571 additions and 73 deletions

View File

@ -1,3 +1,16 @@
2004-07-27 Moritz Schulte <moritz@g10code.com>
* command-ssh.c: Use gcrypt memory allocators, use secure memory
where necessary.
2004-07-26 Moritz Schulte <moritz@g10code.com>
* command-ssh.c (data_sign): Do not forget to unsigned char when
constructing human-readable key grip.
* Makefile.am (gpg_agent_SOURCES): Removed: buffer.c, buffer.h;
updated Libgpg-stream.
2004-07-24 Moritz Schulte <moritz@g10code.com>
* gpg-stream-config.h: New file (was missing before).

View File

@ -30,7 +30,6 @@ AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS) $(PTH_CFLAGS)
gpg_agent_SOURCES = \
gpg-agent.c agent.h \
gpg-stream.c gpg-stream.h gpg-stream-config.h \
buffer.c buffer.h \
command.c command-ssh.c \
query.c \
cache.c \

View File

@ -26,7 +26,7 @@
#include <errno.h>
#include <sys/types.h>
#include <dirent.h>
//#include <stdio.h>
#include <stdio.h>
#include "agent.h"
@ -227,7 +227,7 @@ gpg_stream_write_uint32 (gpg_stream_t stream, uint32_t uint32)
}
static gpg_err_code_t
gpg_stream_read_string (gpg_stream_t stream,
gpg_stream_read_string (gpg_stream_t stream, unsigned int secure,
unsigned char **string, uint32_t *string_size)
{
gpg_err_code_t err = GPG_ERR_NO_ERROR;
@ -241,7 +241,10 @@ gpg_stream_read_string (gpg_stream_t stream,
goto out;
/* Allocate space. */
buffer = malloc (length + 1);
if (secure)
buffer = gcry_malloc_secure (length + 1);
else
buffer = gcry_malloc (length + 1);
if (! buffer)
{
err = gpg_err_code_from_errno (errno);
@ -268,7 +271,7 @@ gpg_stream_read_string (gpg_stream_t stream,
}
else
if (buffer)
free (buffer);
gcry_free (buffer);
return err;
}
@ -303,8 +306,8 @@ gpg_stream_write_cstring (gpg_stream_t stream, char *string)
}
static gpg_err_code_t
gpg_stream_read_mpint (gpg_stream_t stream, mpint_t *mpint,
unsigned int mpi_type)
gpg_stream_read_mpint (gpg_stream_t stream, unsigned int secure,
mpint_t *mpint, unsigned int mpi_type)
{
gpg_err_code_t err = GPG_ERR_NO_ERROR;
unsigned char *mpi_data = NULL;
@ -314,7 +317,8 @@ gpg_stream_read_mpint (gpg_stream_t stream, mpint_t *mpint,
if (! mpi_type)
mpi_type = GCRYMPI_FMT_STD;
err = gpg_stream_read_string (stream, &mpi_data, &mpi_data_size);
err = gpg_stream_read_string (stream, secure,
&mpi_data, &mpi_data_size);
if (err)
goto out;
@ -324,7 +328,7 @@ gpg_stream_read_mpint (gpg_stream_t stream, mpint_t *mpint,
out:
free (mpi_data);
gcry_free (mpi_data);
if (! err)
*mpint = mpi;
@ -333,8 +337,8 @@ gpg_stream_read_mpint (gpg_stream_t stream, mpint_t *mpint,
}
static gpg_err_code_t
gpg_stream_write_mpint (gpg_stream_t stream, mpint_t mpint,
unsigned int mpi_type)
gpg_stream_write_mpint (gpg_stream_t stream,
mpint_t mpint, unsigned int mpi_type)
{
gpg_err_code_t err = GPG_ERR_NO_ERROR;
unsigned char *mpi_buffer = NULL;
@ -376,7 +380,7 @@ gpg_stream_read_file (const char *filename,
if (err)
goto out;
buffer_new = malloc (buffer_new_n);
buffer_new = gcry_malloc (buffer_new_n);
if (! buffer_new)
{
err = gpg_err_code_from_errno (errno);
@ -436,7 +440,7 @@ ssh_receive_key_secret (gpg_stream_t stream, ssh_key_secret_t *key_secret)
unsigned char *key_type = NULL;
gcry_mpi_t mpi_iqmp = NULL;
err = gpg_stream_read_string (stream, &key_type, NULL);
err = gpg_stream_read_string (stream, 0, &key_type, NULL);
if (err)
goto out;
@ -448,22 +452,22 @@ ssh_receive_key_secret (gpg_stream_t stream, ssh_key_secret_t *key_secret)
{
case SSH_KEY_TYPE_RSA:
{
err = gpg_stream_read_mpint (stream, &key.material.rsa.n, 0);
err = gpg_stream_read_mpint (stream, 0, &key.material.rsa.n, 0);
if (err)
break;
err = gpg_stream_read_mpint (stream, &key.material.rsa.e, 0);
err = gpg_stream_read_mpint (stream, 0, &key.material.rsa.e, 0);
if (err)
break;
err = gpg_stream_read_mpint (stream, &key.material.rsa.d, 0);
err = gpg_stream_read_mpint (stream, 1, &key.material.rsa.d, 0);
if (err)
break;
err = gpg_stream_read_mpint (stream, &mpi_iqmp, 0);
err = gpg_stream_read_mpint (stream, 1, &mpi_iqmp, 0);
if (err)
break;
err = gpg_stream_read_mpint (stream, &key.material.rsa.p, 0);
err = gpg_stream_read_mpint (stream, 1, &key.material.rsa.p, 0);
if (err)
break;
err = gpg_stream_read_mpint (stream, &key.material.rsa.q, 0);
err = gpg_stream_read_mpint (stream, 1, &key.material.rsa.q, 0);
if (err)
break;
@ -483,7 +487,7 @@ ssh_receive_key_secret (gpg_stream_t stream, ssh_key_secret_t *key_secret)
{
/* u has to be recomputed. */
key.material.rsa.u = gcry_mpi_new (0);
key.material.rsa.u = gcry_mpi_snew (0);
gcry_mpi_invm (key.material.rsa.u,
key.material.rsa.p, key.material.rsa.q);
}
@ -501,19 +505,27 @@ ssh_receive_key_secret (gpg_stream_t stream, ssh_key_secret_t *key_secret)
out:
free (key_type);
gcry_free (key_type);
gcry_mpi_release (mpi_iqmp);
if (! err)
*key_secret = key;
else
{
gcry_mpi_release (key.material.rsa.n);
gcry_mpi_release (key.material.rsa.e);
gcry_mpi_release (key.material.rsa.d);
gcry_mpi_release (key.material.rsa.p);
gcry_mpi_release (key.material.rsa.q);
gcry_mpi_release (key.material.rsa.u);
switch (key.type)
{
case SSH_KEY_TYPE_RSA:
gcry_mpi_release (key.material.rsa.n);
gcry_mpi_release (key.material.rsa.e);
gcry_mpi_release (key.material.rsa.d);
gcry_mpi_release (key.material.rsa.p);
gcry_mpi_release (key.material.rsa.q);
gcry_mpi_release (key.material.rsa.u);
break;
case SSH_KEY_TYPE_NONE:
break;
}
}
return err;
@ -558,7 +570,7 @@ ssh_receive_key_public (gpg_stream_t stream, ssh_key_public_t *key_public)
ssh_key_public_t key = { 0 };
unsigned char *key_type = NULL;
err = gpg_stream_read_string (stream, &key_type, NULL);
err = gpg_stream_read_string (stream, 0, &key_type, NULL);
if (err)
goto out;
@ -570,10 +582,10 @@ ssh_receive_key_public (gpg_stream_t stream, ssh_key_public_t *key_public)
{
case SSH_KEY_TYPE_RSA:
{
err = gpg_stream_read_mpint (stream, &key.material.rsa.e, 0);
err = gpg_stream_read_mpint (stream, 0, &key.material.rsa.e, 0);
if (err)
break;
err = gpg_stream_read_mpint (stream, &key.material.rsa.n, 0);
err = gpg_stream_read_mpint (stream, 0, &key.material.rsa.n, 0);
if (err)
break;
break;
@ -589,7 +601,7 @@ ssh_receive_key_public (gpg_stream_t stream, ssh_key_public_t *key_public)
out:
free (key_type);
gcry_free (key_type);
if (! err)
*key_public = key;
@ -670,7 +682,7 @@ ssh_convert_key_to_blob (unsigned char **blob, size_t *blob_size,
if (err)
goto out;
blob_new = malloc (blob_new_size);
blob_new = gcry_malloc (blob_new_size);
if (! blob_new)
{
err = gpg_err_code_from_errno (errno);
@ -721,7 +733,7 @@ ssh_key_grip (ssh_key_public_t *public, ssh_key_secret_t *secret,
: secret->material.rsa.n,
public
? public->material.rsa.e
: secret->material.rsa.n);
: secret->material.rsa.e);
break;
case SSH_KEY_TYPE_NONE:
@ -867,7 +879,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
}
key_directory_n = strlen (key_directory);
key_path = malloc (key_directory_n + 46);
key_path = gcry_malloc (key_directory_n + 46);
if (! key_path)
{
err = gpg_err_code_from_errno (errno);
@ -903,7 +915,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
/* Convert it into a public key. */
err = ssh_key_public_from_stored_key (buffer, buffer_n, &key);
free (buffer);
gcry_free (buffer);
buffer = NULL;
if (err)
goto out;
@ -915,7 +927,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
/* Add key blob to buffer stream. */
err = gpg_stream_write_string (key_blobs, key_blob, key_blob_n);
free (key_blob);
gcry_free (key_blob);
key_blob = NULL;
if (err)
goto out;
@ -949,8 +961,8 @@ ssh_handler_request_identities (ctrl_t ctrl,
gpg_stream_destroy (key_blobs);
closedir (dir);
free (key_directory);
free (key_path);
free (key_blob);
gcry_free (key_path);
gcry_free (key_blob);
}
static gpg_err_code_t
@ -984,7 +996,7 @@ data_sign (CTRL ctrl, unsigned char **sig, size_t *sig_n)
unsigned int i = 0;
for (i = 0; i < 20; i++)
sprintf (&key_grip[i * 2], "%02X", ctrl->keygrip[i]);
sprintf (&key_grip[i * 2], "%02X", (unsigned char) ctrl->keygrip[i]);
strncpy (strchr (description, '0'), key_grip, 40);
err = agent_pksign_do (ctrl, description, &signature_sexp, 0);
@ -1039,7 +1051,7 @@ data_sign (CTRL ctrl, unsigned char **sig, size_t *sig_n)
if (err)
goto out;
sig_blob = malloc (sig_blob_n);
sig_blob = gcry_malloc (sig_blob_n);
if (! sig_blob)
{
err = gpg_err_code_from_errno (errno);
@ -1048,7 +1060,7 @@ data_sign (CTRL ctrl, unsigned char **sig, size_t *sig_n)
err = gpg_stream_read (stream, sig_blob, sig_blob_n, &bytes_read);
if ((! err) && (sig_blob_n != bytes_read))
err = GPG_ERR_INTERNAL; /* violation */
err = GPG_ERR_EOF;
if (err)
goto out;
@ -1067,7 +1079,7 @@ data_sign (CTRL ctrl, unsigned char **sig, size_t *sig_n)
{
gcry_sexp_release (signature_sexp);
gcry_sexp_release (sublist);
free (sig_blob);
gcry_free (sig_blob);
}
return err;
@ -1095,7 +1107,7 @@ ssh_handler_sign_request (ctrl_t ctrl,
/* Receive key. */
err = gpg_stream_read_string (request, &key_blob, &key_blob_size);
err = gpg_stream_read_string (request, 0, &key_blob, &key_blob_size);
if (err)
goto out;
@ -1105,7 +1117,7 @@ ssh_handler_sign_request (ctrl_t ctrl,
/* Receive data to sign. */
err = gpg_stream_read_string (request, &data, &data_size);
err = gpg_stream_read_string (request, 0, &data, &data_size);
if (err)
goto out;
@ -1161,9 +1173,9 @@ ssh_handler_sign_request (ctrl_t ctrl,
else
gpg_stream_write_byte (response, SSH_RESPONSE_FAILURE);
free (key_blob);
free (data);
free (sig);
gcry_free (key_blob);
gcry_free (data);
gcry_free (sig);
}
static gpg_err_code_t
@ -1194,7 +1206,7 @@ ssh_key_to_sexp_buffer (ssh_key_secret_t *key, const char *passphrase,
goto out;
buffer_new_n = gcry_sexp_sprint (key_sexp, GCRYSEXP_FMT_CANON, NULL, 0);
buffer_new = malloc (buffer_new_n);
buffer_new = gcry_malloc (buffer_new_n);
if (! buffer_new)
{
err = gpg_err_code_from_errno (errno);
@ -1209,10 +1221,8 @@ ssh_key_to_sexp_buffer (ssh_key_secret_t *key, const char *passphrase,
out:
if (key_sexp)
gcry_sexp_release (key_sexp);
if (buffer_new)
free (buffer_new);
gcry_sexp_release (key_sexp);
gcry_free (buffer_new);
return err;
}
@ -1254,24 +1264,35 @@ static gpg_err_code_t
ssh_identity_register (ssh_key_secret_t *key, int ttl)
{
gpg_err_code_t err = GPG_ERR_NO_ERROR;
unsigned char key_grip[21] = { 0 };
unsigned char key_grip_raw[21] = { 0 };
unsigned char *buffer = NULL;
unsigned int buffer_n = 0;
char passphrase[100] = { 0 };
char description[] =
"Please provide the passphrase, which should "
"be used for protecting the received secret key "
"`0123456789012345678901234567890123456789':";
unsigned int i = 0;
char key_grip[41];
int ret = 0;
if (DBG_COMMAND)
log_debug ("[ssh-agent] registering identity `%s'\n", key_grip);
err = ssh_key_grip (NULL, key, key_grip);
err = ssh_key_grip (NULL, key, key_grip_raw);
if (err)
goto out;
ret = agent_key_available (key_grip);
ret = agent_key_available (key_grip_raw);
if (! ret)
goto out;
err = get_passphrase ("foo", sizeof (passphrase), passphrase);
for (i = 0; i < 20; i++)
sprintf (&key_grip[i * 2], "%02X", key_grip_raw[i]);
strncpy (strchr (description, '0'), key_grip, 40);
err = get_passphrase (description,
sizeof (passphrase), passphrase);
if (err)
goto out;
@ -1279,11 +1300,11 @@ ssh_identity_register (ssh_key_secret_t *key, int ttl)
if (err)
goto out;
err = agent_write_private_key (key_grip, buffer, buffer_n, 0);
err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0);
if (err)
goto out;
err = agent_put_cache (key_grip, passphrase, ttl);
err = agent_put_cache (key_grip_raw, passphrase, ttl);
if (err)
goto out;
@ -1332,7 +1353,7 @@ ssh_handler_add_identity (ctrl_t ctrl,
if (err)
goto out;
err = gpg_stream_read_string (request, &comment, NULL);
err = gpg_stream_read_string (request, 0, &comment, NULL);
if (err)
goto out;
@ -1382,8 +1403,21 @@ ssh_handler_add_identity (ctrl_t ctrl,
out:
free (comment);
//ssh_key_destroy (key); FIXME
switch (key.type)
{
case SSH_KEY_TYPE_RSA:
gcry_mpi_release (key.material.rsa.n);
gcry_mpi_release (key.material.rsa.e);
gcry_mpi_release (key.material.rsa.d);
gcry_mpi_release (key.material.rsa.p);
gcry_mpi_release (key.material.rsa.q);
gcry_mpi_release (key.material.rsa.u);
break;
case SSH_KEY_TYPE_NONE:
break;
}
gpg_stream_write_byte (response,
err
@ -1405,7 +1439,7 @@ ssh_handler_remove_identity (ctrl_t ctrl,
if (DBG_COMMAND)
log_debug ("[ssh-agent] remove identity\n");
err = gpg_stream_read_string (request, &key_blob, NULL);
err = gpg_stream_read_string (request, 0, &key_blob, NULL);
if (err)
goto out;
@ -1419,7 +1453,7 @@ ssh_handler_remove_identity (ctrl_t ctrl,
out:
free (key_blob);
gcry_free (key_blob);
err = gpg_stream_write_byte (response,
err
@ -1567,9 +1601,25 @@ gpg_stream_eof_p (gpg_stream_t stream, unsigned int *eof)
return err;
}
/* FIXME: Libgcrypt should provide this function. */
static void *
gcry_realloc_secure (void *mem, size_t size)
{
if (! mem)
return gcry_malloc_secure (size);
else
return gcry_realloc (mem, size);
}
void
start_command_handler_ssh (int sock_client)
{
gpg_stream_spec_mem_t stream_spec_secure = { NULL, 0, 1,
gcry_realloc_secure,
gcry_free };
gpg_stream_spec_mem_t stream_spec = { NULL, 0, 1,
gcry_realloc,
gcry_free };
struct server_control_s ctrl = { NULL };
gpg_err_code_t err = GPG_ERR_NO_ERROR;
gpg_stream_t stream_sock = NULL;
@ -1598,24 +1648,28 @@ start_command_handler_ssh (int sock_client)
if (err || eof)
break;
/* Create memory streams for request/response data. */
/* Create memory streams for request/response data. The entire
request will be stored in secure memory, since it might
contain secret key material. The response does not have to
be stored in secure memory, since we never give out secret
keys. */
stream_request = NULL;
err = gpg_stream_create (&stream_request, NULL,
err = gpg_stream_create (&stream_request, &stream_spec_secure,
GPG_STREAM_FLAG_READ | GPG_STREAM_FLAG_WRITE,
gpg_stream_functions_mem);
if (err)
break;
stream_response = NULL;
err = gpg_stream_create (&stream_response, NULL,
err = gpg_stream_create (&stream_response, &stream_spec,
GPG_STREAM_FLAG_READ | GPG_STREAM_FLAG_WRITE,
gpg_stream_functions_mem);
if (err)
break;
/* Retrieve request length. */
free (request);
gcry_free (request);
request = NULL;
err = gpg_stream_read_string (stream_sock, &request, &request_size);
err = gpg_stream_read_string (stream_sock, 1, &request, &request_size);
if (err)
break;
@ -1666,7 +1720,7 @@ start_command_handler_ssh (int sock_client)
gpg_stream_destroy (stream_sock);
gpg_stream_destroy (stream_request);
gpg_stream_destroy (stream_response);
free (request);
gcry_free (request);
if (DBG_COMMAND)
log_debug ("[ssh-agent] Leaving ssh command handler: %s\n", gpg_strerror (err));

View File

@ -33,10 +33,430 @@
#include "gpg-stream.h"
#include "gpg-stream-config.h"
#include "buffer.h"
/* Buffer management layer. */
#define BUFFER_BLOCK_SIZE 1024
typedef struct buffer *buffer_t;
/* Callbacks, necessary for filling/flushing/seeking. */
typedef gpg_error_t (*buffer_func_read_t) (void *handle,
char *buffer,
size_t bytes_to_read,
size_t *bytes_read);
typedef gpg_error_t (*buffer_func_write_t) (void *handle,
const char *buffer,
size_t bytes_to_write,
size_t *bytes_written);
typedef gpg_error_t (*buffer_func_seek_t) (void *handle,
off_t offset,
int whence);
typedef gpg_error_t (*buffer_func_stat_t) (void *handle,
size_t *size);
typedef struct buffer_functions
{
buffer_func_read_t func_read; /* Read callback. */
buffer_func_write_t func_write; /* Write callback. */
buffer_func_seek_t func_seek; /* Seek callback. */
buffer_func_stat_t func_stat; /* Stat callback. */
} buffer_functions_t;
/* Buffer context. */
struct buffer
{
void *handle; /* Handle, passed to callbacks. */
buffer_functions_t functions; /* Callback functions. */
unsigned int flags; /* General flags. */
struct buffer_in
{
char *container; /* Container holding data. */
size_t container_size; /* Size of CONTAINER. */
size_t data_size; /* Size of data in CONTAINER. */
off_t data_offset; /* Offset inside of CONTAINER. */
} buffer_in;
struct buffer_out
{
char *container; /* Container holding data. */
size_t container_size; /* Size of CONTAINER. */
size_t data_size; /* Size of data in CONTAINER. */
off_t data_offset; /* Offset inside of CONTAINER. */
size_t data_flushed; /* Amount of data already flushed. */
} buffer_out;
};
/* Buffer contains unflushed data. */
#define BUFFER_FLAG_DIRTY (1 << 0)
/* Fill buffer. */
static gpg_error_t
buffer_fill_do (buffer_t buffer)
{
gpg_error_t err = GPG_ERR_NO_ERROR;
size_t bytes_read = 0;
if (! buffer->functions.func_read)
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
else
{
buffer_func_read_t func_read = buffer->functions.func_read;
err = (*func_read) (buffer->handle,
buffer->buffer_in.container,
buffer->buffer_in.container_size,
&bytes_read);
}
buffer->buffer_in.data_offset = 0;
buffer->buffer_in.data_size = bytes_read;
return err;
}
/* Empty buffer input. */
static gpg_error_t
buffer_empty (buffer_t buffer)
{
gpg_error_t err = GPG_ERR_NO_ERROR;
buffer->buffer_in.data_size = 0;
buffer->buffer_in.data_offset = 0;
return err;
}
/* Flush data contained in buffer. */
static gpg_error_t
buffer_flush_do (buffer_t buffer)
{
buffer_func_write_t func_write = buffer->functions.func_write;
gpg_error_t err = GPG_ERR_NO_ERROR;
size_t bytes_written = 0;
if (! func_write)
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
else if (buffer->flags & BUFFER_FLAG_DIRTY)
while ((buffer->buffer_out.data_size
- buffer->buffer_out.data_flushed) && (! err))
{
err = (*func_write) (buffer->handle,
buffer->buffer_out.container
+ buffer->buffer_out.data_flushed,
buffer->buffer_out.data_size
- buffer->buffer_out.data_flushed,
&bytes_written);
if (! err)
{
buffer->buffer_out.data_size = 0;
buffer->buffer_out.data_offset = 0;
buffer->buffer_out.data_flushed = 0;
buffer->flags &= ~BUFFER_FLAG_DIRTY;
}
else
buffer->buffer_out.data_flushed += bytes_written;
}
return err;
}
static gpg_error_t
buffer_stat_do (buffer_t buffer,
size_t *size)
{
buffer_func_stat_t func_stat = buffer->functions.func_stat;
gpg_error_t err = GPG_ERR_NO_ERROR;
err = (*func_stat) (buffer->handle, size);
return err;
}
/* Read from a buffer. */
gpg_error_t
buffer_read (buffer_t buffer,
char *data,
size_t bytes_to_read,
size_t *bytes_read)
{
gpg_error_t err = GPG_ERR_NO_ERROR;
size_t data_read = 0;
size_t data_to_copy = 0;
if (! (buffer->flags & BUFFER_FLAG_DIRTY))
err = buffer_flush_do (buffer);
while ((bytes_to_read - data_read) && (! err))
{
if (buffer->buffer_in.data_offset == buffer->buffer_in.data_size)
{
/* Nothing more to read in current container, try to
fill container with new data. */
err = buffer_fill_do (buffer);
if (! err)
if (! buffer->buffer_in.data_size)
/* Filling did not result in any data read. */
break;
}
if (! err)
{
if ((bytes_to_read
- data_read) > (buffer->buffer_in.data_size
- buffer->buffer_in.data_offset))
data_to_copy = (buffer->buffer_in.data_size
- buffer->buffer_in.data_offset);
else
data_to_copy = bytes_to_read - data_read;
memcpy (data + data_read,
buffer->buffer_in.container + buffer->buffer_in.data_offset,
data_to_copy);
buffer->buffer_in.data_offset += data_to_copy;
data_read += data_to_copy;
}
}
if (bytes_read)
*bytes_read = data_read;
return err;
}
/* Write to a buffer. */
gpg_error_t
buffer_write (buffer_t buffer,
const char *data,
size_t bytes_to_write,
size_t *bytes_written)
{
gpg_error_t err = GPG_ERR_NO_ERROR;
size_t data_written = 0;
size_t data_to_copy = 0;
while ((bytes_to_write - data_written) && (! err))
{
if (buffer->buffer_out.data_offset == buffer->buffer_out.container_size)
/* Container full, flush buffer. */
err = buffer_flush_do (buffer);
if (! err)
{
if ((bytes_to_write
- data_written) > (buffer->buffer_out.container_size
- buffer->buffer_out.data_offset))
data_to_copy = (buffer->buffer_out.container_size
- buffer->buffer_out.data_offset);
else
data_to_copy = bytes_to_write - data_written;
memcpy (buffer->buffer_out.container
+ buffer->buffer_out.data_offset,
data + data_written,
data_to_copy);
if ((buffer->buffer_out.data_offset
+ data_to_copy) > buffer->buffer_out.data_size)
buffer->buffer_out.data_size = (buffer->buffer_out.data_offset
+ data_to_copy);
buffer->buffer_out.data_offset += data_to_copy;
data_written += data_to_copy;
if (data_written)
if (! (buffer->flags & BUFFER_FLAG_DIRTY))
buffer->flags |= BUFFER_FLAG_DIRTY;
}
}
if (bytes_written)
*bytes_written = data_written;
return err;
}
/* Seek in a buffer. */
gpg_error_t
buffer_seek (buffer_t buffer,
off_t offset,
int whence)
{
buffer_func_seek_t func_seek = buffer->functions.func_seek;
gpg_error_t err = GPG_ERR_NO_ERROR;
if (! func_seek)
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
else
{
if (buffer->flags & BUFFER_FLAG_DIRTY)
/* Flush data first in order to prevent flushing it to the
wrong offset. */
err = buffer_flush_do (buffer);
if (! err)
err = (*func_seek) (buffer->handle, offset, whence);
if (! err)
err = buffer_empty (buffer);
}
return err;
}
/* Return the unread data contained in a buffer. */
gpg_error_t
buffer_peek (buffer_t buffer,
char **data,
size_t *data_size)
{
gpg_error_t err = GPG_ERR_NO_ERROR;
if (buffer->buffer_in.data_offset == buffer->buffer_in.data_size)
/* Refill container. */
err = buffer_fill_do (buffer);
if (! err)
{
if (data)
*data = buffer->buffer_in.container + buffer->buffer_in.data_offset;
if (data_size)
*data_size = buffer->buffer_in.data_size - buffer->buffer_in.data_offset;
}
return err;
}
/* Skip SIZE bytes of input data contained in buffer. */
gpg_error_t
buffer_skip (buffer_t buffer,
size_t size)
{
gpg_error_t err = GPG_ERR_NO_ERROR;
if (buffer->buffer_in.data_offset + size > buffer->buffer_in.data_size)
err = gpg_error (GPG_ERR_INV_ARG);
else
buffer->buffer_in.data_offset += size;
return err;
}
/* Create a new buffer. */
gpg_error_t
buffer_create (buffer_t *buffer,
void *handle,
buffer_functions_t functions)
{
gpg_error_t err = GPG_ERR_NO_ERROR;
/* Allocate memory, initialize. */
buffer_t buffer_new = NULL;
char *container_in_new = NULL;
char *container_out_new = NULL;
buffer_new = malloc (sizeof (*buffer_new));
if (! buffer_new)
err = gpg_error_from_errno (errno);
if (! err)
{
container_in_new = malloc (BUFFER_BLOCK_SIZE);
if (! container_in_new)
err = gpg_error_from_errno (errno);
}
if (! err)
{
container_out_new = malloc (BUFFER_BLOCK_SIZE);
if (! container_out_new)
err = gpg_error_from_errno (errno);
}
if (! err)
{
buffer_new->handle = handle;
buffer_new->flags = 0;
buffer_new->functions = functions;
buffer_new->buffer_in.container = container_in_new;
buffer_new->buffer_in.container_size = BUFFER_BLOCK_SIZE;
buffer_new->buffer_in.data_size = 0;
buffer_new->buffer_in.data_offset = 0;
buffer_new->buffer_out.container = container_out_new;
buffer_new->buffer_out.container_size = BUFFER_BLOCK_SIZE;
buffer_new->buffer_out.data_size = 0;
buffer_new->buffer_out.data_offset = 0;
buffer_new->buffer_out.data_flushed = 0;
*buffer = buffer_new;
}
else
{
if (container_in_new)
free (container_in_new);
if (container_out_new)
free (container_out_new);
if (buffer_new)
free (buffer_new);
}
return err;
}
/* Destroy a buffer. */
gpg_error_t
buffer_destroy (buffer_t buffer)
{
gpg_error_t err = GPG_ERR_NO_ERROR;
if (buffer)
{
err = buffer_flush_do (buffer);
free (buffer->buffer_in.container);
free (buffer->buffer_out.container);
free (buffer);
}
return err;
}
/* Write out unwritten data contained in buffer. */
gpg_error_t
buffer_flush (buffer_t buffer)
{
gpg_error_t err = GPG_ERR_NO_ERROR;
err = buffer_flush_do (buffer);
return err;
}
/* Stat buffer. */
gpg_error_t
buffer_stat (buffer_t buffer,
size_t *size)
{
gpg_error_t err = GPG_ERR_NO_ERROR;
err = buffer_stat_do (buffer, size);
return err;
}
/* Stream layer. */
/* A Stream Context. */
struct gpg_stream
{
@ -66,6 +486,9 @@ struct gpg_stream
/* Implementation of Memory I/O. */
typedef void *(*mem_func_realloc_t) (void *mem, size_t size);
typedef void (*mem_func_free_t) (void *mem);
typedef struct gpg_stream_handle_mem
{
char *memory; /* Data. */
@ -73,6 +496,8 @@ typedef struct gpg_stream_handle_mem
size_t data_size; /* Size of data in MEMORY. */
unsigned int grow: 1; /* MEMORY is allowed to grow. */
size_t offset; /* Current offset in MEMORY. */
mem_func_realloc_t func_realloc;
mem_func_free_t func_free;
} *gpg_stream_handle_mem_t;
static gpg_error_t
@ -94,6 +519,10 @@ gpg_stream_func_mem_create (void **handle,
mem_handle->data_size = 0;
mem_handle->grow = mem_spec ? mem_spec->grow : 1;
mem_handle->offset = 0;
mem_handle->func_realloc = ((mem_spec && mem_spec->func_realloc)
? mem_spec->func_realloc : realloc);
mem_handle->func_free = ((mem_spec && mem_spec->func_free)
? mem_spec->func_free : free);
*handle = mem_handle;
}
@ -136,8 +565,9 @@ gpg_stream_func_mem_write (void *handle,
while (bytes_to_write > mem_handle->memory_size - mem_handle->offset)
{
memory_new = realloc (mem_handle->memory,
mem_handle->memory_size + BUFFER_BLOCK_SIZE);
memory_new = (*mem_handle->func_realloc)
(mem_handle->memory,
mem_handle->memory_size + BUFFER_BLOCK_SIZE);
if (! memory_new)
err = gpg_error_from_errno (errno);
else
@ -216,7 +646,7 @@ gpg_stream_func_mem_destroy (void *handle)
gpg_error_t err = GPG_ERR_NO_ERROR;
if (mem_handle->memory)
free (mem_handle->memory);
(*mem_handle->func_free) (mem_handle->memory);
free (mem_handle);
return err;

View File

@ -129,6 +129,8 @@ typedef struct gpg_stream_spec_mem
char *memory;
size_t memory_size;
unsigned int grow: 1;
void *(*func_realloc) (void *mem, size_t size);
void (*func_free) (void *mem);
} gpg_stream_spec_mem_t;
extern gpg_stream_functions_t gpg_stream_functions_mem;