acl/lib_tls/tls/tls_prng_egd.c

169 lines
4.3 KiB
C

/*++
* NAME
* tls_prng_egd 3
* SUMMARY
* seed OpenSSL PRNG from EGD server
* SYNOPSIS
* #include <tls_prng_src.h>
*
* TLS_PRNG_SRC *tls_prng_egd_open(name, timeout)
* const char *name;
* int timeout;
*
* ssize_t tls_prng_egd_read(egd, length)
* TLS_PRNG_SRC *egd;
* size_t length;
*
* int tls_prng_egd_close(egd)
* TLS_PRNG_SRC *egd;
* DESCRIPTION
* tls_prng_egd_open() connect to the specified UNIX-domain service
* and returns a handle that should be used with all subsequent
* access.
*
* tls_prng_egd_read() reads the requested number of bytes from
* the EGD server and updates the OpenSSL PRNG.
*
* tls_prng_egd_close() disconnects from the specified EGD server
* and releases memory that was allocated for the handle.
*
* Arguments:
* .IP name
* The UNIX-domain pathname of the EGD service.
* .IP length
* The number of bytes to read from the EGD server.
* Request lengths will be truncated at 255 bytes.
* .IP timeout
* Time limit on individual I/O operations.
* DIAGNOSTICS
* tls_prng_egd_open() returns a null pointer on error.
*
* tls_prng_egd_read() returns -1 on error, the number
* of bytes received on success.
*
* tls_prng_egd_close() returns -1 on error, 0 on success.
*
* In all cases the errno variable indicates the type of error.
* LICENSE
* .ad
* .fi
* The Secure Mailer license must be distributed with this software.
* AUTHOR(S)
* Wietse Venema
* IBM T.J. Watson Research
* P.O. Box 704
* Yorktown Heights, NY 10598, USA
*--*/
#include "StdAfx.h"
#ifdef ACL_UNIX
#include <unistd.h>
#endif
#include <limits.h>
#ifndef UCHAR_MAX
#define UCHAR_MAX 0xff
#endif
/* OpenSSL library. */
#ifdef USE_TLS
#include <openssl/rand.h> /* For the PRNG */
/* TLS library. */
#include "tls_prng.h"
/* tls_prng_egd_open - connect to EGD server */
TLS_PRNG_SRC *tls_prng_egd_open(const char *name, int timeout)
{
const char *myname = "tls_prng_egd_open";
TLS_PRNG_SRC *egd;
ACL_SOCKET fd;
if (acl_msg_verbose)
acl_msg_info("%s: connect to EGD server %s", myname, name);
#ifdef ACL_UNIX
fd = acl_unix_connect(name, ACL_BLOCKING, timeout);
#elif defined(WIN32)
fd = acl_inet_connect(name, ACL_BLOCKING, timeout);
#endif
if (fd < 0) {
if (acl_msg_verbose)
acl_msg_info("%s: cannot connect to EGD server %s: %s",
myname, name, acl_last_serror());
return (0);
} else {
egd = (TLS_PRNG_SRC *) acl_mymalloc(sizeof(*egd));
egd->fd.sock = fd;
egd->name = acl_mystrdup(name);
egd->timeout = timeout;
if (acl_msg_verbose)
acl_msg_info("%s: connected to EGD server %s", myname, name);
return (egd);
}
}
/* tls_prng_egd_read - update internal PRNG from EGD server */
ssize_t tls_prng_egd_read(TLS_PRNG_SRC *egd, size_t len)
{
const char *myname = "tls_prng_egd_read";
unsigned char buffer[UCHAR_MAX];
ssize_t count;
if (len <= 0)
acl_msg_panic("%s: bad length %ld", myname, (long) len);
buffer[0] = 1;
buffer[1] = (unsigned char) (len > UCHAR_MAX ? UCHAR_MAX : len);
if (acl_timed_write(egd->fd.sock, buffer, 2, egd->timeout, (void *) 0) != 2) {
acl_msg_info("%s: cannot write to EGD server %s: %s",
myname, egd->name, acl_last_serror());
return (-1);
}
if (acl_timed_read(egd->fd.sock, buffer, 1, egd->timeout, (void *) 0) != 1) {
acl_msg_info("%s: cannot read from EGD server %s: %s",
myname, egd->name, acl_last_serror());
return (-1);
}
count = buffer[0];
if (count > (ssize_t) sizeof(buffer))
count = sizeof(buffer);
if (count == 0) {
acl_msg_info("EGD server %s reports zero bytes available", egd->name);
return (-1);
}
if (acl_timed_read(egd->fd.sock, buffer, count, egd->timeout, (void *) 0) != count) {
acl_msg_info("%s: cannot read %ld bytes from EGD server %s: %s",
myname, (long) count, egd->name, acl_last_serror());
return (-1);
}
if (acl_msg_verbose)
acl_msg_info("%s: got %ld bytes from EGD server %s", myname,
(long) count, egd->name);
RAND_seed(buffer, count);
return (count);
}
/* tls_prng_egd_close - disconnect from EGD server */
int tls_prng_egd_close(TLS_PRNG_SRC *egd)
{
const char *myname = "tls_prng_egd_close";
int err;
if (acl_msg_verbose)
acl_msg_info("%s: close EGD server %s", myname, egd->name);
err = acl_file_close(egd->fd.file);
acl_myfree(egd->name);
acl_myfree(egd);
return (err);
}
#endif