1/*++
2/* NAME
3/*	tls_prng_dev 3
4/* SUMMARY
5/*	seed OpenSSL PRNG from entropy device
6/* SYNOPSIS
7/*	#include <tls_prng_src.h>
8/*
9/*	TLS_PRNG_SRC *tls_prng_dev_open(name, timeout)
10/*	const char *name;
11/*	int	timeout;
12/*
13/*	ssize_t tls_prng_dev_read(dev, length)
14/*	TLS_PRNG_SRC *dev;
15/*	size_t length;
16/*
17/*	int	tls_prng_dev_close(dev)
18/*	TLS_PRNG_SRC *dev;
19/* DESCRIPTION
20/*	tls_prng_dev_open() opens the specified entropy device
21/*	and returns a handle that should be used with all subsequent
22/*	access.
23/*
24/*	tls_prng_dev_read() reads the requested number of bytes from
25/*	the entropy device and updates the OpenSSL PRNG.
26/*
27/*	tls_prng_dev_close() closes the specified entropy device
28/*	and releases memory that was allocated for the handle.
29/*
30/*	Arguments:
31/* .IP name
32/*	The pathname of the entropy device.
33/* .IP length
34/*	The number of bytes to read from the entropy device.
35/*	Request lengths will be truncated at 255 bytes.
36/* .IP timeout
37/*	Time limit on individual I/O operations.
38/* DIAGNOSTICS
39/*	tls_prng_dev_open() returns a null pointer on error.
40/*
41/*	tls_prng_dev_read() returns -1 on error, the number
42/*	of bytes received on success.
43/*
44/*	tls_prng_dev_close() returns -1 on error, 0 on success.
45/*
46/*	In all cases the errno variable indicates the type of error.
47/* LICENSE
48/* .ad
49/* .fi
50/*	The Secure Mailer license must be distributed with this software.
51/* AUTHOR(S)
52/*	Wietse Venema
53/*	IBM T.J. Watson Research
54/*	P.O. Box 704
55/*	Yorktown Heights, NY 10598, USA
56/*--*/
57
58/* System library. */
59
60#include <sys_defs.h>
61#include <fcntl.h>
62#include <unistd.h>
63#include <limits.h>
64#include <errno.h>
65
66#ifndef UCHAR_MAX
67#define UCHAR_MAX 0xff
68#endif
69
70/* OpenSSL library. */
71
72#ifdef USE_TLS
73#include <openssl/rand.h>		/* For the PRNG */
74
75/* Utility library. */
76
77#include <msg.h>
78#include <mymalloc.h>
79#include <connect.h>
80#include <iostuff.h>
81
82/* TLS library. */
83
84#include <tls_prng.h>
85
86/* tls_prng_dev_open - open entropy device */
87
88TLS_PRNG_SRC *tls_prng_dev_open(const char *name, int timeout)
89{
90    const char *myname = "tls_prng_dev_open";
91    TLS_PRNG_SRC *dev;
92    int     fd;
93
94    if ((fd = open(name, O_RDONLY, 0)) < 0) {
95	if (msg_verbose)
96	    msg_info("%s: cannot open entropy device %s: %m", myname, name);
97	return (0);
98    } else {
99	dev = (TLS_PRNG_SRC *) mymalloc(sizeof(*dev));
100	dev->fd = fd;
101	dev->name = mystrdup(name);
102	dev->timeout = timeout;
103	if (msg_verbose)
104	    msg_info("%s: opened entropy device %s", myname, name);
105	return (dev);
106    }
107}
108
109/* tls_prng_dev_read - update internal PRNG from device */
110
111ssize_t tls_prng_dev_read(TLS_PRNG_SRC *dev, size_t len)
112{
113    const char *myname = "tls_prng_dev_read";
114    unsigned char buffer[UCHAR_MAX];
115    ssize_t count;
116    size_t  rand_bytes;
117
118    if (len <= 0)
119	msg_panic("%s: bad read length: %ld", myname, (long) len);
120
121    if (len > sizeof(buffer))
122	rand_bytes = sizeof(buffer);
123    else
124	rand_bytes = len;
125    errno = 0;
126#ifdef __APPLE_OS_X_SERVER__
127    const char *p_no_poll = "apple-no-poll";
128    count = timed_read(dev->fd, buffer, rand_bytes, dev->timeout, (void *)p_no_poll);
129#else /* __APPLE_OS_X_SERVER__ */
130    count = timed_read(dev->fd, buffer, rand_bytes, dev->timeout, (void *) 0);
131#endif /* __APPLE_OS_X_SERVER__ */
132    if (count > 0) {
133	if (msg_verbose)
134	    msg_info("%s: read %ld bytes from entropy device %s",
135		     myname, (long) count, dev->name);
136	RAND_seed(buffer, count);
137    } else {
138	if (msg_verbose)
139	    msg_info("%s: cannot read %ld bytes from entropy device %s: %m",
140		     myname, (long) rand_bytes, dev->name);
141    }
142    return (count);
143}
144
145/* tls_prng_dev_close - disconnect from EGD server */
146
147int     tls_prng_dev_close(TLS_PRNG_SRC *dev)
148{
149    const char *myname = "tls_prng_dev_close";
150    int     err;
151
152    if (msg_verbose)
153	msg_info("%s: close entropy device %s", myname, dev->name);
154    err = close(dev->fd);
155    myfree(dev->name);
156    myfree((char *) dev);
157    return (err);
158}
159
160#endif
161