/*++ * NAME * tls_prng_egd 3 * SUMMARY * seed OpenSSL PRNG from EGD server * SYNOPSIS * #include * * 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 #endif #include #ifndef UCHAR_MAX #define UCHAR_MAX 0xff #endif /* OpenSSL library. */ #ifdef USE_TLS #include /* 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